14 ms·
How Does React Tell a Class from a Function?
- abhisuri97 8y ago"Please don’t turn this into an interview question. In fact, this post is more about JavaScript than it is about React" I love this line.
- ronilan 8y ago“In a December, 2nd, 2018 blog post, developer Dan Abramov explained in length and in detail how React can (and/or can not) tell a Class from a Function. He wrote: ‘please don’t turn this into an interview question’ Can you define what this refers to?”
- deleted 8y ago[deleted]
- tomjakubowski 8y agoI don't think I can answer that without knowing how this has been bound by the caller.
- chrisweekly 8y agoAbramov's a class act all the way.
- jakelazaroff 8y agoOr is he a function act?
- yuchi 8y ago:clap:
- shawn 8y agoIt defines Component.prototype.isReactComponent. There isn't really a better way to do it in JS.
- Waterluvian 8y agoI'm really quite surprised how much time is spent worrying about Babel. I always thought that you could just write valid JavaScript and it's completely Babel's responsibility not to screw that up. Edit: not sure what's wrong with my comment so let me clarify: I wouldn't have thought that library developers had to think about what other tools might do with their library. I always thought that so long as your code is valid JavaScript, Babel would faithfully transpile it down to another valid target using polyfills and whatnot.
- alangpierce 8y agoTranspiling ES6 to ES5 is a hard problem, and I believe it's impossible to be 100% correct unless you ship a full JS interpreter written in JS (which would have terrible performance). As a result, Babel and TypeScript both have to make pragmatic tradeoffs, and you can certainly find plenty of cases of non-spec-compliance if you go looking for them. Sometimes transpilers diverge from the spec for performance reasons, sometimes because following the spec would be too hard to implement, and sometimes because there isn't any (reasonable) way to follow the spec. This is especially true with low-level reflection operations like seeing if something is a class or a function.
- sophiebits 8y ago(I work on React.) Most of our users use Babel so it would be irresponsible for us to not consider how React and Babel play together; if we didn't we'd quickly get into a situation where no one can use React because their setups are incompatible. For what it's worth, if we found while developing React that Babel was compiling something in a problematic way and we had a better suggestion for the compiled output, we'd certainly see if we could get it fixed upstream. In this case the Babel output for classes is pretty reasonable so there's nothing to change. We did briefly consider if it made sense to require every function component to be written using an arrow functions and asking Babel to delete the .prototype property from every compiled arrow function (compiling a = () => ... into something like a = function() { ... }; a.prototype = undefined;). We eventually decided that the .prototype.isReactComponent compromise described in the post was a better result overall, both for authoring ergonomics and runtime performance.
- xrd 8y agoI've read at least two dozen explanations of prototypes that didn't offer 10% of the clarity of this post. And another brilliantly told story of how React does its work. Bravo.
- cryptonector 8y agoI agree, this is the best explanation of JavScript's new/this/prototype/__proto__ I've seen yet. It was definitely worth the read.
- baseballMan 8y agoTotally! I'm not even a full time JS dev (I just have played around with React before) and I understood all of it.
- danschumann 8y agoTL;DR -- it uses `instanceof`
- awestroke 8y agoWrong, try again.
- shawn 8y agoJoy. We've gone from "Please don't post TL;DRs" to "Please at least be correct."
- pookeh 8y agoYou probably need to continue reading the post :) > That’s not what React does though. > > One caveat to the instanceof solution is that it doesn’t work when there are multiple copies of React on the page, and the component we’re checking inherits from another React copy’s React.Component. Real TL;DR: > If you don’t extend React.Component, React won’t find isReactComponent on the prototype, and won’t treat component as a class.
- petilon 8y agoSo React added isReactComponent to Component class but the author doesn't explain why they couldn't just check for render() method. It works in this React-like library: https://github.com/wisercoder/uibuilder/blob/master/UIBuilder/UIBuilder.ts#L130 https://github.com/wisercoder/uibuilder/blob/master/UIBuilde...
- acemarke 8y agoSomeone else asked that same question on Reddit [0], and Dan pointed out the paragraph in the post that answers it : > One other possible heuristic could be to check for presence of a render method on the prototype. However, at the time it wasn’t clear how the component API would evolve. Every check has a cost so we wouldn’t want to add more than one. This would also not work if render was defined as an instance method, such as with the class property syntax. [0] https://www.reddit.com/r/reactjs/comments/a2j6xk/how_does_react_tell_a_class_from_a_function/eayzfhx/ https://www.reddit.com/r/reactjs/comments/a2j6xk/how_does_re...
- deleted 8y ago[deleted]
- wz1000 8y agoI have written maybe 200 lines of JavaScript in my life, and this article has strongly reinforced my desire to never have to write a single one more. The next time someone asks me what the problem with JavaScript is, I will send them this article. "Scheme for the browser" what a joke. Some excerpts for those that didn't have the strength to sit through the entire thing without pulling their hair out: > If you called Person('Fred') without new, this inside it would point to something global and useless (for example, window or undefined). So our code would crash or do something silly like setting window.name. > However, JavaScript also allows a function called with new to override the return value of new by returning some other object. Presumably, this was considered useful for patterns like pooling where we want to reuse instances: > However, new also completely ignores a function’s return value if it’s not an object. If you return a string or a number, it’s like there was no return at all. > And yet I still find it very confusing that a property called prototype does not give you a value’s prototype (for example, fred.prototype is undefined because fred is not a function). Personally, I think this is the biggest reason even experienced developers tend to misunderstand JavaScript prototypes. > However, some class implementations we wanted to target did not copy static properties (or set the non-standard __proto__), so the flag was getting lost Edit: And I missed the best/worst one yet: You can have MULTIPLE VERSIONS of the SAME DEPENDENCY running around in your codebase, interacting in ways that only god knows. In retrospect, this should have been obvious from the way javascript "imports" work, but, holy shit! If Satan himself had to design a language, he could not have done a better job. And I'm sure he would not have the stroke of genius required to make it the only programming language you can use if you want to target the most widely available platform for code in the world. The next time I have to allow NoScript to let some js in, I will wonder how many goat sacrifices went into making the thing work.
- leeoniya 8y agoi've used this in the past: function isClass(fn) { return !Object.getOwnPropertyDescriptor(fn, 'prototype').writable; } it relies on the fact that the prototype object of ES6 classes always non-writable.
- dgoldstein0 8y agoI don't think that would work for the standard es5 pattern of using functions as classes?
- alangpierce 8y agoNote that this breaks with Babel and TypeScript, since I guess this is one aspect where neither strictly follows the spec. Both of these examples print false: https://babeljs.io/repl/build/master/#?babili=false&browsers=&build=&builtIns=false&code_lz=GYVwdgxgLglg9mABDAzgYQDYEMUoBTBgCUiA3gFCKIBOAplCNUgIQDyARgFa3QB0A5vVYB3MAAVqcAA61qUAJ4ARWigjUYUqHGoEwAGkQByKZK0KZhor2HqoWdhloBucgF9y5CNlyIAgmXdPBBQ4R14MOH48VEwcfF8iIhcgA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&lineWrap=true&presets=es2015%2Creact&prettier=false&targets=&version=7.1.6&envVersion= https://babeljs.io/repl/build/master/#?babili=false&browsers... https://www.typescriptlang.org/play/index.html#src=function%20isClass(fn)%20%7B%0A%20%20return%20!Object.getOwnPropertyDescriptor(fn%2C%20'prototype').writable%3B%0A%7D%0A%0Aclass%20A%20%7B%7D%0A%0Aconsole.log(isClass(A))%3B%0A https://www.typescriptlang.org/play/index.html#src=function%...
- galaxyLogic 8y agoYou get an error if you try to call an ES6 class as a function (without 'new'). So just try to do that inside a try-catch. If there is no error you know it is not a class and you have the result of the function already. If you do get an error and you know it is a function you know it must be a class.
- efrafa 8y agoClasses get transpiled to functions, but even if they wouldnt, what if function body throws?
- alangpierce 8y agoI believe throwing and catching exceptions over and over as part of normal rendering is the sort of thing that would be disastrous for performance, certainly the sort of thing that the React authors would really want to avoid.
- sorahn 8y agoThe new suspense api is based on throwing and catching promises as part of the render, so I don’t think its that.
- danabramov 8y agoSuspense only uses throwing when it's blocked on network. There is huge difference between doing this once every few seconds, and doing this thousands of times per second.
- seattle_spring 8y agoYikes. Definitely do not do this.
- danabramov 8y agoThat would unfortunately be too slow for production.
- code001 8y agoGreat job Dan, please keep posting more articles on your blog!
- finchisko 8y agoI'm pretty much aware about prototype inheritance in js. But still scratching my head everytime, I try to understand difference between prototype and __proto__. Thankfully with ES6 classes and class inheritance constructs, we don't need to override prototype constructor and such a things anymore. Still wish, that somebody will explain it to me in plain english.
- sophiebits 8y agoThis post does try to explain it in plain English. See the explanation starting at the bolded sentence that starts "Confusingly,".
- ricardobeat 8y agoHonestly I don’t think it does a good job at explaining it. Classes are mostly syntax sugar for “old” constructors and prototypes, not the other way around (that’s the whole reason you can’t tell them apart). Would be easier to explain it that way; on mobile right now so can’t comment too much.
- jrumbut 8y agoI thought it was unfortunate that prototypes were characterized as an inadequate approximation of classes, when in fact prototypes are a wholly legitimate, powerful, and certainly interesting way to approach object-oriented programming (https://en.m.wikipedia.org/wiki/Prototype-based_programming https://en.m.wikipedia.org/wiki/Prototype-based_programming). 20+ years of confused programmers suggests that maybe it wasn't the right way to go for a language that is frequently used by beginners, but still that wasn't the fault of prototype based programming itself. The new class system is syntactic sugar leveraging the power of prototypes. This was always possible, and nothing stopped you from implementing a class-like system in JavaScript a long time ago. More, very readable, info here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...
- danabramov 8y ago
- ricardobeat 8y ago“In the old days, JavaScript did not have classes” gave me a laugh. This was 3-4 years ago.
- welfare 8y agoHow I read it, "Old days" in my opinion refers to the 90's and early 00's, and not so much about the recent changes in the language.
- Vinnl 8y agoI guess he meant "the old days of React", i.e. in the first half or so of its lifespan.
- Grue3 8y agoMy reaction was "Wait, JavaScript has classes now???"
- Shorel 8y agoIf you have to use .bind(), then no, it doesn't.
- MoTTs_ 8y agoIn C++ you have to use bind too.
- Shorel 8y agoNo, not even close. You can use it if you want to, but it has never been popular in C++, and in 20 years I have never encountered a problem that could be solved by using it, so I have never used it. And in C++ bind is part of the functional programming paradigm, as it does currying, not much to do with classes. Bind in JavaScript makes your shoehorned collection of attributes actually behave like objects. We can see JavaScript's bind used everywhere.
- 8y ago
- torgian 8y agoUgh. This just doesn’t make me want to touch JavaScript. I’d rather stick to Django and Python
- Vinnl 8y agoI'm quite sure the authors of Django would be able to tell similar stories about Python...
- danabramov 8y agoYeah that's kind of the point of this blog. I dive a bit deeper than you need to know as an app developer. Also touched on this at the end: >If the final API is successful, its users never have to think about this process. Instead they can focus on creating apps.
- perfunctory 8y ago> Instead they can focus on creating apps. If only it worked that way. Unfortunately, somehow I always end up needing to know about the process cause the abstraction leaks like a sieve. And it's leakier in javascript than in any other language.
- Kiro 8y ago> In the old days, JavaScript did not have classes. Feels like yesterday to me. I still do my objects prototype style because classes feel too new and bleeding edge.
- miklax 8y agoI like a domain name.
- arry 8y agoWhat's the rationale for allowing the components to be defined as functions in the first place? As far as I can see, it has a single thing going for it: saving a line of code, at the expense of jumping through the JavaScript hoops to implement the class/function distinction described in the post. Besides, when the function component evolves and acquires the need for state or other features, the saved line of code goes right back in.
- cozos 8y agoFunctions are stateless and I believe can be better optimized. Enforcing statelessness is also a win in itself.
- RoryH 8y agoIndeed, also checkout the React.PureComponent for another example of an in-between Class and Function optimisation.
- quietbritishjim 8y agoSurprisingly, pure functional components are called even when their props haven't changed so PureComponent is not "in between" but "even more" than functional components. As for regular components, you can override this behaviour by adding a componentWillReceiveProps() method (yes, you can add a method to your functional component!).
- peterjmag 8y agoI like function components too, but I've seen some interesting arguments against using them: https://medium.freecodecamp.org/7-reasons-to-outlaw-reacts-functional-components-ff5b5ae09b7c https://medium.freecodecamp.org/7-reasons-to-outlaw-reacts-f... And I wish I had a reference for this, but I seem to remember reading that any future performance optimizations that could be applied to function components could probably also be applied to class components (at least ones that contain only a render() function and nothing else). In any case, I'm hoping that React eventually gets to a point where developers don't have to make a choice between class and function components, and the compiler or the runtime makes that decision for us on a per-component basis. EDIT: As an example, here's a Babel plugin that takes care of the conversion for you at compile time: https://github.com/remcohaszing/babel-plugin-transform-react-class-to-function https://github.com/remcohaszing/babel-plugin-transform-react.... Not sure what its heuristics are for determining what should and shouldn't be converted though, if any.
- kbumsik 8y ago> I didn’t know this for years. Please don’t turn this into an interview question. In fact, this post is more about JavaScript than it is about React. Well, I think how prototype works is much more important than using React. I think having an interview in JS without knowing prototype is like having an Java interview without knowing polymorphism, abstract class, interface or something.
- danabramov 8y agoI don't disagree with this — I was referring to the how does React do it part specifically. Although I'd also note that in practice people tend to use a subset of JS in their work, and often prototypes aren't directly used. (I understand they power everything under the hood but I'm talking about something product engineer has to think about.)
- k__ 8y agoI don't know. Prototypes are more powerful than anything Java has to offer. It's a low-level concept that is mostly used to create a class system on top of it, rather than used directly. Polymorphism, abstract classes or interfaces are part of the day-to-day stuff a Java dev has to meddle with.
- maceurt 8y agoI have heard Prototype in js used as a term, but I don't really understand what it means. I have programmed a good deal of things in js also, and I have never felt like I needed to explicitly know what Prototype means. Is it really essential to know what this term means?
- dntrkv 8y agoDepends on what you work on and what kind of developer you are. If you are just building frontend applications using frameworks like React and Vue, you don't really need to know how things work under the hood. Especially with all of the new syntactic sugar introduced to JS in the last few years. But, if you are building lower level tooling and you want to understand why things are implemented the way they are (this post being a great example) you really should understand them as best you can. A lot of design decisions in JS are influenced by these lower-level design "constraints."
- tcgv 8y agoTLDR Version: React defines the property "isReactComponent" in its "Component" class prototype object. When you extend "Component" React can simply check "MyClass.prototype.isReactComponent" and if the result is true, it knows it's a class and not a function!
- snek 8y agomfw __proto__ instead of Object.getPrototypeOf
- cj 8y ago> Please don’t turn this into an interview question. In fact, this post is more about JavaScript than it is about React. Aren't most people hiring frontend developers looking for people who understanding Javascript (and not just React)? Or is "React" a skill separate from Javascript these days? Personally, I'd be hesitant to hire anyone who "knows React" but doesn't know the basics of how it works.
- zwerdlds 8y agoAll of the hiring managers I've talked to recently have the JQuery/JS dichotomy applied to React now. That is, they don't seem to really care that there's a difference. You can say you're good with JS, Vue, DOM etc, but if you don't check that React box, it's not good enough.
- pier25 8y agoI recently discovered http://imba.io/ http://imba.io/ which makes the virtual DOM approach irrelevant. It just renders "everything, every time" like the main loop of a game, so you don't need any more reconciliation, async state management, etc. In some benchmarks this approach is 20 to 30 times faster than React.
- iooi 8y agoOn a related note, this is the one article which after reading I wanted to subscribe to, but could not find a newsletter or subscription. Dan, if you're reading this, this might help: https://www.gatsbyjs.org/packages/gatsby-plugin-mailchimp/?no-cache=1 https://www.gatsbyjs.org/packages/gatsby-plugin-mailchimp/?n... I'm guessing the site is built with gatsby from the theme.
- rexpan 8y agoYup, it is gatsby. https://github.com/gaearon/overreacted.io https://github.com/gaearon/overreacted.io You can use https://overreacted.io/rss.xml https://overreacted.io/rss.xml for subscription.
- chairmanmow 8y agoReact doesn't care whether something is a class or function until Congress notices.