Hacker News new | comments | show | ask | jobs | submit login
How Does React Tell a Class from a Function? (overreacted.io)
348 points by obilgic 12 days ago | hide | past | web | favorite | 129 comments





What'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.

To me it's all about intent. By using a function instead of a class, you are basically saying "future reader, this component is nothing more than a simple mapping from those values to that DOM tree, don't try to look for internal states or any complex treatment here".

Sure you could write a "normal React component without state" and do the same, but having those properties baked in the way you defined the component is much stronger.


I absolutely agree with you.

This makes me very skeptical about the proposed feature in React, called "hooks", which is linked to in the article. It lets you add state to your functional components, and it looks like you end up bundling all your code into one function rather than having a separate constructor to initialise the state (to me, separating out that function is a good thing). I would be interested in the motivation for that.

Link: https://reactjs.org/docs/hooks-intro.html


I have this doubt as well.

Hooks will allow people to use "class like" features and behavior, but with none of the conventions forced by syntax, plus some pitfalls.

To me it seems a good way to ensure most devs (espacially unexperienced casual ones, which are legions in JS by nature of the market) will dump their logic wherever it works with as little structure as it allows. It's a technical debt catalyser, and will make sure nobody feels at home in someone else's code. The community will pay the price in a year.

It's also yet another way to do the same thing, and JS has already a lot of those. React as well. Documentations, tutorials and examples will suffer from it. But again, it's very common in JS land where learning anything requires gathering scattered puzzle pieces then assembling them, hoping they are from the same set this time. It allows me to bill more, so I'm not complaining, but it's not fair to newcommers.

Note that I can see some nice things about hooks. I just strongly think they don't outweight the cost by an order of magnitude.

FB idea of ergonomics and user friendliness, in API and UI, has always been to force their way into things, until it blocks, back down, and fix things when possible or use a workaround.

Having been training people in web tech for years, the consequences of such policy show in the classroom. But, hey, more money for me :) Plus when I dev, I have the experience to avoid the pain, mostly knowing when not to do or use things. But I can tell than many of my younger colleagues don't, and a few of my not so young ones too.

Still, I wish they gave a bit more though to this aspects of their products: their are brillant technicians, so it's not that they can't, it's just a matter of culture.


I've also had doubts about hooks since its proposal, and I agree with the points you raised.

From the Rules of Hooks section in the documentation[0].

- React relies on the order in which Hooks are called. - Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions. - Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.

This design decision doesn't sit well with me, and I won't be using it. However, the community seems to have already welcomed it, so I'm forced to learn the intricacies to be able to understand React codebases and keep up with the latest trend..

The addition of this feature is sure to increase cognitive load and technical debt. There are already countless variations of state management libraries and patterns that encourage pure functional components and decoupled logic. Hooks seem to be yet another opinionated strategy - and not for the best, in my view.

---

[0] https://reactjs.org/docs/hooks-rules.html


> However, the community seems to have already welcomed it, so I'm forced to learn the intricacies to be able to understand React codebases and keep up with the latest trend..

That's one thing that no many realizes: the JS community is special and you should take that in consideration when adding a new features.

When I say special, I mean it reacts (puns intended) in a way no other programming community does:

- it jumps on novelty with very little afterthoughs or regards for consequences.

- it has an habit of disregarding lessons from the past.

- it seldom fix problems, but add a new layer of solution on top of it.

Knowing this, the way hooks are released is too me like giving matches to children with the only advice "look how cool it is, I can make fireworks".

Yes, I'm exagerating for the argument sake. But still, react is now a software used everywhere, I'd welcome a switch from "move fast and break things" to "let's think this true" once in a while.


This is a good way to summarize the javascript community. Not learning from the past is possibly a side effect of being dominated by young and/or inexperienced programmers and being less inclined to research established concepts before making something up. Although there are plenty of benefits to younger programmers (I hope, I'm one myself), but there are drawbacks to everything.

> will dump their logic wherever it works with as little structure as it allows. It's a technical debt catalyser, and will make sure nobody feels at home in someone else's code. The community will pay the price in a year.

I don't want to downplay your concerns, but I will say that this is already a problem. Part of the goal with hooks (and I can't say if it achieves that) is to encourage the separation of a lot of state-interaction OUT of the components. Today it is much too easy (arguably it is easiest) to write a component that is basically untestable - basically a mini-application in itself, which is the opposite of good React design.

I'm hopeful that Hooks will help, and I think the original demonstration focused too much on state and not enough on other interactions external to the component, which is where the real pain today exists. I've not played with the alpha at all to have a feel for how realistic my hopes are.


> is to encourage the separation of a lot of state-interaction OUT of the components

I get that, but I'm not sure it's in the interest of most projects either. The vast majority of React code base can (and IMO should) do the simplest things instead of going with a store. Redux and other means of putting state interactions out of components are a huge overhead in so many ways that I think it should be the exception, not the rule.

Besides, even for fluent react devs, it is a common strategy to create applications as a big fat component that does it all, then split it little by little into smaller parts as the need arises. Complexity management is hard after all.

It makes sense the FB team wants to promote a pure clean industrial flux pattern, so I understand why they go this way. I just note they are doing so, ignoring the fact the vast majority of devs work on code that never reaches anything close to their requirements. And if it ever does, it certainly doesn't start that way.

Same goes for tests. I'd say only one projects out of give I work on are decently tested. Our industry has low quality standards it seems. But creating something that will cause confusion among the less skilled in hoping it will help the experts do fewer mistakes is not a good trade off: IRL teams have one 10x programmer for many more regular ones, if at all.

Again, I follow the logic. I just think it's not a good bet for the community. It may be a good bet for FB scale entities, but I'm not even sure it is.


I read the hooks documentation. Why would someone find this pattern better than a pre-defined state object ? I don’t get it.

React seems like it’s getting more complicated every single day. I loved it due to its simplicity but now i’m not so sure.


mostly because you can encapsulate and reuse some state logic. allows for easier testing too.

You could already do that with regular functions, class inheritence, mixin, prototype inheritence, composition, event dispatching or stores.

If preventing people from being confused and doing the wrong thing was the goal, I'm not sure adding one new way to the mix is going to make things clearer.

Besides, while I agree tooling help with applying good practices, including encapsulation, it's no substitute for a good initial API design.

React and JS API are confusing, because they have been designed this way from the start. We are now adding things on top of it, again and again, without ever fixing anything at the bottom. This creates problems at the same time it solves others.

Another issue is that the JS community wants to professionalise without aknowledging that a huge part of it doesn't have the skill to do so yet. It's a community that includes many young devs with little experience, people that are not programmers but ends up doing so, devs born in a culture of instant results... It's important to address this as well, by talking to them in tutorials and documentation, by creating API shaped with them in mind, so that they can grow in empowering directions.

Instead, we create monster trucks, and they put ads on youtube to tell everyone how "easy it is to drive" and "you should do it too right now".

For me, hooks are a monster truck. And most JS devs I work with are not capable of driving that safely.


Sure, but if you can drive hooks safely, they seems to make some things _very_ clean. I'm going back through and rewriting a toy app I haven't launched yet to use hooks and it's been a joy to work with them so far.

This seems to be the response to every addition to javascript or react without addressing the above concerns.

Nothing wrong with your comment on trying to embrace it per se, but it would be healthier if this sentiment was balanced in the community with more skepticism rather than blind embrace.


I agree with this thinking.

One of the key reasons for choosing a framework/library is to enforce (reasonable) constraints. These constraints help in making sure that the framework takes a longer term view of things than just making it easy in the short term.


>to me, separating out that function is a good thing

To us, too, and that's exactly the point of Hooks. They let you extract logic into functions in a way that wasn't possible before. I suggest to read more than a single page -- in particular, extracting custom Hooks is largely the point of the proposal.

https://reactjs.org/docs/hooks-custom.html

I also wrote about this here:

https://medium.com/@dan_abramov/making-sense-of-react-hooks-...


That post has changed my opinion about hooks. I find this gist especially compelling:

https://gist.github.com/gaearon/cb5add26336003ed8c0004c4ba82...

Without hooks, that example would require adding a method (or two) to the component class. With custom hooks, that code can go into a separate module.

Component bloat has been a problem for us, and if hooks can enable components to focus solely on render logic, I'd say that's an improvement.


Can't you achieve the same result by leaving only view logic in the component, and having the data-related logic, including the fact that data has changed in a way that may require redraw, handled in a separate object? Here's how I'd do it in Mithril/TSX:

    class WidthStore {
        width: stream.Stream<number>;
        constructor() {
            this.width = stream(window.innerWidth);
            window.addEventListener('resize', () => {
                this.width(window.innerWidth);
                m.redraw();
            });
        }
    }

    const widthStore: WidthStore = new WidthStore();

    class MyResponsiveComponent {
        view(vnode) {
            return <p>Window width is {widthStore.width()}</p>;
        }
    }

It reminds me quite a bit of mixins.

The problem is class based components have to be written very carefully to remain testable, and the average developer is not that careful. It's basically a foot cannon, and the worst react spaghetti I've seen has always been a result of huge classes that manage way too much state. I believe that making it a convention for developers to break up their components into small, pure functions will raise the quality of most react applications. Recompose has made this possible for a while, but most react devs aren't familiar with it, and baking it into the framework should make that approach less exotic. Of course, you will still be able to write huge functions that manage too much state, but I think classes encourage this more than functions.

>I would be interested in the motivation for that

The article you link to actually explains that quite well. Basically there are three motivations for hooks:

1. Keep code that belongs to one functionality in one place. For example setup and teardown would be in the same hook, but when writing a class they are scattered among the many things happening in the event methods in the class

2. Allow new ways to compose functionality. You can use the same hook in different functions. You could achieve the same effect before, but this makes it more convinient

3. Produce code that works better with Prepack [1], to make ahead-of-time compiled react runtimes more efficient. It might be some time until this becomes a rolled out advertised feature, but hooks are a good step on the way there

1: https://prepack.io/


I think this in turn is a symptom of conflating rendering with state management in the first place.

The line between React and vanilla code is blurring more every day - which is a bit greedy for something that's purely meant to be a rendering solution. I would personally advocate to push React as far away from my app code as possible, and instead implement a specialised container class that hooks into React's internals (Controller? Model?) purely to handle localised state changes.


To me, hooks feel like just reinventing mixins, except they have weirder edge case when they break.

I agree with you, but now with hooks that's not the case anymore.

It seems the React team intends to completely move away form using classes.


How do hooks fit in with that definition?

Functions are stateless and I believe can be better optimized. Enforcing statelessness is also a win in itself.

I like function components too, but I've seen some interesting arguments against using them:

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.... Not sure what its heuristics are for determining what should and shouldn't be converted though, if any.


This is true in theory but the React team has not optimized them directly. React.memo is the only way to optimize them thus far.

I think he's referring to the optimizations the JIT/engine will do.

Indeed, also checkout the React.PureComponent for another example of an in-between Class and Function optimisation.

Surprisingly, 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!).

Sadly (or luckily?) with hooks they aren't stateless anymore.

React started with class components, because of state, I guess.

Later they added function components because they are more concise and tell readers that this component is a simple mapping from props to virtual DOM elements.

With hooks, a recent addition to React, they seem to move away from class components. Hooks enable you to use state and do things when a component is mounted in the DOM or removed from it inside of function components.


> What's the rationale for allowing the components to be defined as functions in the first place?

Intent: it makes clear that the component is stateless in a way a class-based component does not.


This is why I don't like the hooks concept introduced in the post. It breaks these semantics.

These semantics didn’t exist, anyway. Functional components can hold state through higher order components (eg connected to redux store), render props of children components, etc.

The future of React is less classes and more functions.

See hooks

https://reactjs.org/docs/hooks-intro.html


Because in JavaScript classes are lies.

"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.

“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?”

I don't think I can answer that without knowing how this has been bound by the caller.

Abramov's a class act all the way.

Or is he a function act?

I'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.

I agree, this is the best explanation of JavScript's new/this/prototype/__proto__ I've seen yet. It was definitely worth the read.

Totally! I'm not even a full time JS dev (I just have played around with React before) and I understood all of it.

I'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.


(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.


Transpiling 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.

> 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.


I 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.)


I 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?

As a js dev for 6 years now, and having conducted hundreds of interviews, I would say it is not necessary for a junior developer and most of the things they'd be doing.

However, when it comes to a mid or senior level engineer, it's important not to just make things work, but to understand the how and why in order to build performant applications at scale.

So to answer your question, no it's not a necessity to build applications. Yes, it is if you want to excel at building applications.


Depends 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."


I 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.


I have developed javascript applications for a while now and I have never had to use prototype. If I was asked about it in an interview, I would explain that it's a leaky abstraction, that using it in code means you are over-complicating your solution, and that it seems to be a holdover from when people thought your codebase should be modeled according to reality ("we have users, therefore we should have a user model").

You can absolutely be a great javascript developer without ever touching prototype. Prototype is an infection of object-oriented programming into a functional language.


I couldn't agree more !

“In the old days, JavaScript did not have classes” gave me a laugh. This was 3-4 years ago.

How 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.

I guess he meant "the old days of React", i.e. in the first half or so of its lifespan.

My reaction was "Wait, JavaScript has classes now???"

If you have to use .bind(), then no, it doesn't.

In C++ you have to use bind too.

No, 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.


The issue we complain about in JavaScript is one like this:

    class C {
        handleEvent() {}

        someMethod() {
            onEvent(this.handleEvent); // bad; "this" lost
            onEvent(this.handleEvent.bind(this); // ok
        }
    }
C++ requires the same thing. The bad case will even generate an error at compile time.

    class C {
        public:
            void handle_event() {}

            void some_method() {
                on_event(&C::handle_event); // bad; error
                on_event(std::bind(&C::handle_event, this)); // ok
            }
    };

TLDR 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!

i'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.

Note 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...

https://www.typescriptlang.org/play/index.html#src=function%...


I don't think that would work for the standard es5 pattern of using functions as classes?

On 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/?n...

I'm guessing the site is built with gatsby from the theme.


Yup, it is gatsby. https://github.com/gaearon/overreacted.io

You can use https://overreacted.io/rss.xml for subscription.


> 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.


All 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.

> 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.


So 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/UIBuilde...


Someone 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_re...


I recently discovered 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.


Great job Dan, please keep posting more articles on your blog!

React doesn't care whether something is a class or function until Congress notices.

I'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.

This post does try to explain it in plain English. See the explanation starting at the bolded sentence that starts "Confusingly,".

Honestly 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.

I 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).

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/Guid...


I tried not to mention classes too explicitly in the section that deals with __proto__, and only explain the prototypes themselves. But keep in mind that new readers are often exposed to classes only so they need some practical ground. In any case there's plenty of resources -- maybe my explanation will click with somebody.

.__proto__ is that objects prototype that was used to create it.

.prototype is the template of newly created objects of the object you are inspecting.


I like a domain name.

mfw __proto__ instead of Object.getPrototypeOf

TL;DR -- it uses `instanceof`

You 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.

Wrong, try again.

Ugh. This just doesn’t make me want to touch JavaScript. I’d rather stick to Django and Python

I'm quite sure the authors of Django would be able to tell similar stories about Python...

Yeah 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.


> 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.


You 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.

I 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.

The new suspense api is based on throwing and catching promises as part of the render, so I don’t think its that.

Suspense 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.

Classes get transpiled to functions, but even if they wouldnt, what if function body throws?

That would unfortunately be too slow for production.

Yikes. Definitely do not do this.

I 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.


Author here :-) I don't think I disagree with you. JS has its warts and some of them are... weird. The web delivery mechanism has always been its killer feature, not the language. And for web delivery mechanism to work, it needs to maintain backwards compatibility.

In practice, however, I think a lot of these things become irrelevant because JS subcommunities carve out reasonable subsets of the language. For example when using React you almost never need to care about prototypal (or even normal) inheritance because it's explicitly discouraged by React. And in the future, we might not need to encourage classes when writing components altogether.

If you limit yourself to avoiding some features then it's not such a bad language after all.


> If you limit yourself to avoiding some features then it's not such a bad language after all.

Unfortunately that's not possible unless you never interoperate with other code.


I'd say JavaScript works well enough for its original goal - simple DOM manipulation in response to UI events. IMHO the trouble comes from folks who want to use it for all kinds of over-reaching frameworks. The moment you have to discuss enumerating properties of classes, prototypes, etc., JavaScript's lack of typing becomes painfully obvious and there are just much better languages to spend your time on.

I also like the original practical vision for node.js/CommonJS as an escape from the metaprogramming excess that has become Java.


I've written many times that, and I don't hate the language. But man does it have some footguns.

Tools without flaws are not the tools that get used for real work. Sometimes you have to suck it up and learn the quirks in the tools you have.

That's not to discourage work on improving the current situation, just an observation on practicality.


One of the points of the post was that you almost definitely don't need to worry about this yourself, especially if you're using React.

If you're going to be using any language seriously, you better understand how functions and objects and classes in that language work.

I’ve been writing React for 3ish years and not once would knowing any of the weird details in the blog post have been useful for anything I’ve built.

In most cases I'd agree, but essentially JS has gotten to the point that it's only usable if you write an entirely new language on top of it, like React/Vue/Angular have. All of them are basically to avoid the confusion that arises from the weird quirks of JS, like it's classes implementation. These languages then also try to integrate the few positives of JS into their paradigms, and IMO they are decently successful to the point of usability for a frontend.

I don't understand how "React/Vue/Angular" is considered "an entirely new language." I use React primarily, so I'm going to speak from knowledge of that. It is very obviously a framework and it does one thing - handle your view.

Depending on what you are doing, you may have very little react-specific code in your application.

You have data fetching, caching, persistence, authentication, tons of things, not to mention business logic that needs to be implemented in just plain Javascript.

Then out of that process you may have workers or other async background jobs happening which should not involve React at all.


While I agree with your point, your example of React literally adds a DSL that requires a pre-compilation step. It's not required[0], I get that, but it's still a new language.

[0]: It may not be required, but it was created for a reason....


JSX is not only not required, it's sugar that breaks referential transparency: https://medium.com/@david.chambers/jsx-violates-referential-...

Personally I still use it, but I think it's fair to say that as much as JSX was created for a reason, it's made optional for a reason too.


JSX doesn't violate referential transparency. A component either is referentially transparent, or it isn't; nothing about how it's invoked changes that.

Put another way: React calls your components, not you. You pass the component function itself to React.createElement, not its result.


I don't mind a pre-compilation step as I'm already doing it in my projects and a lot of the community is as well.

There are other templating systems you can use in React if you don't like JSX.

I've seen one codebase use direct calls to ReactDOM.createElement and there is a new hotness (which I can't think of the name of now) that replaces JSX with template literals, something like:

  function NamePetList(props) {
    return html`
      <div>
        Hello <b>${props.name}</b>!
        <ul>
        ${props.pets.map(pet => html`
          <li ${...pet.props}>${pet.name}</li>`
        }
        </ul>
     </div>
    `
  }
which I really like.

The library parses the strings to figure out which elements to create. Flow control and variables are just normal template literal arguments.


You're likely thinking of https://github.com/developit/htm.

Oh yes! Thank you.

I get the pros and cons of jsx/htm (and hyperhtml/lithtml) just fine. I'm just saying that bringing up React as an example of a framework that should not be treated as a new language is not the best possible example, since it does literally come with a new language.

I guess your downvoters have some sort of Stockholm syndrome.

Javascript is a giant mess and all attempts to fix it seem to make it even worse. Having a sane language in the browser would be the single biggest boost to overall productivity. That alone would push the global gdp up by 5%. At the very least.


I don't understand why you're getting downvoted, completely agree.

I'm hoping WebASM can save the browser from this foul language. Don't even get me started on server-side JS; if it were a nice, sane scripting language, I'd agree, but the amount of hoops, translators, hackish dev tools etc that have been thrown into the mix to wrangle it into a workable experience... it's too much.


I get your hope for WASM, but I'm not so optimistic. That's not because I don't think that WASM would allow for "better" languages(I personally like and prefer JavaScript), but the future you are suggesting might cause even more fracturing in the web development community than already exists with frameworks and changes in ECMAScript.

Arguably, such fracturing already exists with frontend frameworks. But what will that be like when we become fractured by language? Plenty of people like and prefer JavaScript, but seem to be at least as many people who would rather use an entirely different language on the frontend. I know someone will want to chime in and point out that WASM will still need to interact with JavaScript, but that's not really the point; once JavaScript as a language can be effectively ignored by the developer, that complicates our occupation in terms of interoperability.

One of the great things about web development was that workflows could be different but, at the end of the day, the end product is(was?) essentially HTML, CSS, and JavaScript. There were only so many languages we needed to learn in order to write servers, and at the end of the day we just needed to make something respond to HTTP requests. I chose web development because it wasn't going to pigeonhole me as much as other fields of software engineering; one can, or could, take their web development skills from one company and easily apply them to another, no matter the scale.

Today, we have a constantly evolving browser language, several frontend frameworks and rendering libraries, not just PHP; ASP; and Perl for the server but Python; Ruby; Java; Elixir; Node.js; Groovy, and a wide variety of toolchains and transpilation setups. Now, we're going to open the frontend floodgates to different language runtimes, and along with them even more frontend debugging tools?

This field is becoming way less fun. It's not that I don't understand the desire for choice or to simply not use JavaScript, but I doubt that as humans we won't naturally take the freedom given to us and use it to our detriment.


You don't write js because you like, is because is a competitive advantage:

- Write in one language only for both client and server side. Why is good? You just need js devs, no need to duplicate validation and other logic. I'm making a game right now and has js on the backend. I want to make the game single player, now I can just import a file from the client side and <<Boom!>> now is single player. If your backend is in java, good luck to make it single player.

- Compare a website to an installable app. Who is more likely to gain more customers all things being equal? If you click on a link from google, is more likely to browse a website rather than installing an app.

You could compile java to js, but is a nightmare to debug and you are far away from the real code. You will have a lot of issues.

There are more benefits of js of course.


I really don't get how JS on the client and the server is any real advantage - besides sharing some syntax, the models and paradigms are so drastically different it might as well be two different languages. Why make the server so bad when you don't have to? I think JS has its place despite it's flaws, but for the sake of sanity I can't imagine ever using it on the backend by choice. If you want the ease of express, use Flask.

If you can't write your backend in something else and use the same devs, you have bad devs. It's not that hard to pick up a language if you understand the concepts needed to write a client and a server.


> I really don't get how JS on the client and the server is any real advantage

from my own experience, using single language has huge influence on overall code quality. Makes you understand it much better, comparing to situation you must switch between multiple languages. As you gain more experience in it, the less obvious bugs you'll make (just by knowing what's good and what's wrong).

The worst js code I see, is coming from programmers for whose javascript is their secondary (or third) language. They simply don't understand the basics of it. For example they use timeouts to make asynchronous code synchronous, etc... Then bitching on internet how bad language it is.


Can I ask if you've ever programmed in another language on the backend? I've done plenty of JS and many backend languages and I'd never consider using JS on the backend.

> from my own experience, using single language has huge influence on overall code quality.

From my experience, JS code is really poor quality and overly complex (looking at your build chain) even when written by an expert.


i could argue with you here, but i rather skip

My code is barely coupled with any server engine. My code is just agnostic. Everything is a function. Then I put some wrapper to connect my function to express API or sockets. My code probably is not aware is running on the client or server, nor should be aware of that.

For me works amazingly. I couldn't see myself using anything else on server.

It's not hard to pick up a new language, but changing every 5 minutes it is, especially when you create a new feature.

I think I have 75% of the code shared between client and server side. Again, I can't see myself duplicating so much code and testing it.

I use typescript by the way, so it's pretty good imo.

Just think of all the utils that are shared between client and server side.

Of course I'm talking about web applications with streaming data, not simple webpages.

In a project before we had some functionally that was done on the client side, then somebody decided to move on the server side. Has to be written again in Java from scratch. It's doable, but it's more expensive.


>My code probably is not aware is running on the client or server, nor should be aware of that.

Client- and server-side are very different in terms of network connectivity, CPU and other resources. On the backend you can get by with N+1 queries if the DB is running on the adjacent VM. On the client side, hardly.


The backed's job is to give the frontend what it needs, so at some point it has to make the objects that the fontend will consume and instantiate. That point at which the two realms join is a source of lots of potential reuse, from model objects, to the business rules surrounding their use and structure. Also consider things like validation, javascript-driven server-side rendering, etc



Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: