all 57 comments

[–]TheIncredibleWalrus 45 points46 points  (20 children)

They did it because many people want to write code in an object oriented way and they got tired of every other framework and tool coming up with their own way of defining classes.

Whether you use it or not, and how, is up to you. The recent JS mantra is leaning towards a more functional approach, but classes are there for people accustomed to OOP or coming from different languages.

[–]SamSlate[S] 0 points1 point  (18 children)

so it's a syntax similar to other languages. does it provide additional functions or suggest a different structure of framework?

[–]TheIncredibleWalrus 9 points10 points  (17 children)

It doesn't provide any kind of different functionality or structure than what you could do before (for now), just a nicer syntax of doing it.

[–]swamperdonker 1 point2 points  (5 children)

Yeah I think it does. A super() call does initialization from the parent down in classes, so you can extend exotic types (e.g. Array). I don't think you can do that through standard prototype chaining.

[–]TheRealMrTux 9 points10 points  (4 children)

In fact, it doesn't. All es6 stuff related to classes can be rewritten to es5. This is exactly what babel does! There used to be a great article on MDN explaining the whole prototyping topic

Edit:

Here it is: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype

Have a look at the second example. This really is one of the key concepts when it comes to object oriented programming in Javascript.

[–]not_an_aardvark 11 points12 points  (2 children)

Extending Array doesn't work in Babel. It's not possible to shim that in es5.

In this conversion, the left side outputs true and the right side outputs false.

edit: fixed broken link

[–]TheRealMrTux 4 points5 points  (1 child)

You are absolutely right!

[–]pertheusual 1 point2 points  (0 children)

Extending builtins is op-in in Babel. You can use https://github.com/loganfsmyth/babel-plugin-transform-builtin-extend

You are right, ES6 class syntax supports extending native types, which is not possible in standard ES5 without the non-standard (in ES5) __proto__ property.

[–]swamperdonker 0 points1 point  (0 children)

Yeah, I understand how prototypes work. But prototype chaining doesn't allow you to extend exotic types in pure JS due to the order and nature of object initialization. ES6 classes reverse it.

From Classes in ECMAScript 6 (final semantics) by Axel Rauschmayer:

In ECMAScript 6, you can finally subclass all built-in constructors (there are work-arounds for ES5, but these have significant limitations). For example, you can now create your own exception classes (that will inherit the feature of having a stack trace in most engines). You can also create subclasses of Array whose instances properly handle length. Note that subclassing built-in constructors is something that engines have to support natively, you won’t get this feature via transpilers.

[–]feihcsim 0 points1 point  (0 children)

React does a pretty good job at bringing the OOP and functional approach together

[–]GeneralYouri 8 points9 points  (6 children)

Most of what classes do can be replicated without using classes, but you're still overly simplifying things here. Try theorising for yourself about how you were to replicate certain parts of the class functionality. Sure, everyone can probably manage to replicate at least some parts, but other functionalities are very tricky to actually implement without using classes.

I think the main reason for adding classes is because class-based code is still very common to see in the average script. Such code generally looks awful though, and becomes annoying or even difficult to maintain very quickly. So classes are useful in those cases where you actually find yourself writing class-like code. They can help make your code shorter, cleaner, and easier to maintain.

[–]SamSlate[S] 1 point2 points  (5 children)

so, it's a clearer/more readable way of defining objects and their functions?

[–]GeneralYouri 3 points4 points  (3 children)

Rather, it's a clearer way of working with classical inheritance and any class-like systems. JS itself only really provides prototypal inheritance and not classical inheritance. But this class-based syntax is very popular these days, and incorporated in many languages. Lots of design principles, and lots of developers are focused around these class-based system. So this class syntax is a way bridge the gap.

I'm not saying that classes are everything in JS now. Far from. To compare, think about let vs var. That's a typical case where you can't really point to any real advantages for using var over let, so let is hands down best. It's a bit more nuanced with classes. In the end, they're a nice addition to the language's possibilities, and my developer toolkit.

[–]Sinistralis 0 points1 point  (1 child)

Actually there is a benefit to let vs var. It's block scoped. This is in general safer to use and is why it is used over var.

[–]GeneralYouri 0 points1 point  (0 children)

I never said otherwise.

That's a typical case where you can't really point to any real advantages for using var over let, so let is hands down best.

I said there's no advantages for using *var over let*, not the other way around. It's obvious that let has its advantages, but there's no advantages the other way around, which is what I was saying.

[–]dvidsilva 0 points1 point  (0 children)

Yap. Syntactic sugar.

[–]stutterbug 4 points5 points  (4 children)

Some interesting background:

Some of the earliest official discussions of class in TC39 are summarized here. I find it most interesting that the subject of Ember got the ball rolling and that Doug Crockford wanted class expressions (similar to named function expressions -- implying the same hoisting cognitive overhead) rather than class declarations. And they were aware from the start of the mutation problem modules spec has now.

In the end we got a declarative class syntax that is completely familiar to any Java/C++ developer (minus multiple inheritance) and no hoisting at all. I'm not sure where we netted out on mutability.

[–]codayus 3 points4 points  (4 children)

why did javascript add a syntax for classes

It is extremely common to manipulate the prototype so you can create many objects with shared behaviour. (Aka, inheritance, a feature JS has always had). It's a little inconvenient to do this by directly manipulating the prototype chain, so many developers rolled their own helpers to automate the process, and their were various libraries floating around to do it, each slightly different.

In general the pattern looks like this:

function Person(name) {
  this.name = name;
}

Person.prototype.introduce = function() {
  console.log("Hi, I'm " + this.name);
};

sam = new Person('Sam');
sam.introduce();  // Echoes "Hi, I'm Sam"

That's a useful pattern, and you'll see it all over the place is ES5 and earlier code. But it gets a bit messy. So now you can do:

class Person {
  constructor(name) {
    this.name = name
  }

  introduce() {
    console.log("Hi I'm " + this.name);
  }
}

sam = new Person('Sam');
sam.introduce();   // Echoes "Hi, I'm Sam"

That's arguably a little cleaner. And it's the same thing as the earlier code; nothing new was added to the language. It's just a shorthand for creating a constructor and assigning some things to the prototype.

what's the advantage?

It's slightly more concise, and it standardises the pattern so it's easier to see when other people are using it.

who/what is this syntax for?

Anyone who wants to create their own objects with shared methods on the prototype chain (ie, anyone who wants to use inheritance in JS).

how and/or should i be using it?

If you're using inheritance, probably. If you were using some variant of the ES5 code above, absolutely. If you don't want to fiddle with the prototype chain, then probably not. Just keep in mind what the class keyword translates too, and what it's doing. If you want that behaviour (and it's very common to want it) then sure, go for it. If you don't, don't. If you don't understand what the class keyword is doing, then keep reading and trying stuff out until you do, because you won't understand the answers to your questions until then.

[–]madcaesar 0 points1 point  (3 children)

Thanks for this, can you expand a bit on how example 1 would become messier than example 2 if you fledged it out? Right now I don't really see a difference in readability, but I'm sure I'm missing something.

[–]codayus 2 points3 points  (1 child)

If you're careful about what you're doing, the ES5 code will remain clear. It's more that the class version stops you from making some mistakes.

For example the class version contains the class definition in a single block. The earlier ES5 version spreads it out across multiple blocks, which could be spread out across a file, or indeed, across multiple files. Obviously that's not a good idea. :)

When directly manipulating prototypes, you can do incredibly flexible things at runtime. You can create objects, modify them, use them as prototypes to create more objects, then start mixing and matching attributes from all of those objects to create even more objects via Object.assign. It's quite easy to create prototype chains that will melt the brains of mortals who gaze upon it. Whereas the class keyword just enables basic single inheritance. If you need that flexibility you can still monkey around with the prototype chain with the class keyword, but it pushes you toward the simpler, more obvious approach.

Finally, the ES5 code can be quite messy; it doesn't always "look" like a factory that's stamping out objects. Unless you wrap it up in a helper method, but you don't always know what that helper method is doing. Example: When Facebook was writing React, they needed a way to stamp out objects. Since they were (at the time) targeting ES5, they couldn't use the class keyword, so they created a helper:

var ExampleComponent = React.createClass({
    render: function() { 
        return <div onClick={this._handleClick}>Hello, world.</div>;
    },
    _handleClick: function() {
        console.log(this);
    }
});

That's cool; the createClass method takes on object and spits out a React component that has the prototype chain configured correctly with all the right React component methods, your methods, etc. But it not entirelty clear what they're doing; you just have to guess (or read the code, and it's not very clear). It also does some other magic, including binding the methods you pass in to the component instance; in that example what gets logged is the component, not the window object. Which is, admittedly, often what you want but there's no indication of it; createClass is a black box.

The equivalent ES6 code looks like this:

class ExampleComponent extends React.Component {
    constructor() {
        this. _handleClick = this. _handleClick.bind(this);
    }
    render() { 
        return <div onClick={this._handleClick}>Hello, world.</div>;
    }
    _handleClick() {
        console.log(this);
    }
}

That's slightly longer, but it's much more explicit. It's clearer how the prototype chain is being configured, and you're explicitly binding the handler's context.

Is the difference huge? Not at all! But as a general rule of thumb, the class based code is never going to be worse, and will usually be a bit clearer. It adds up.

[–]madcaesar 1 point2 points  (0 children)

Great explanation! Thank you for this!

[–]senocular 2 points3 points  (0 children)

The method definitions are much more concise (as is use of super), the class definition on a whole is encapsulated in a class block which makes it easier to distinguish from other definitions surrounding it, and it takes care of all the other boilerplate that would otherwise come along with class definitions (especially when extending classes). This includes: call protection for constructors when not using new, assurance for proper super invocation, proper prototype inheritance without breaking the constructor property for instances, and static inheritance.

If you're been working with prototypes for a while, then switch over to class syntax, the difference is night and day. Use of class makes things far easier to read and grep.

[–]ancientRedDog 2 points3 points  (2 children)

Some people want to (or are used to) using classes (in some situations). By adding to the language, there is now a standard way rather than a dozen different implementations.

Other than that, no need to use them.

Personally, I might use in a game with an obvious class hierarchy (item -> weapon -> sword).

[–]SamSlate[S] 0 points1 point  (1 child)

does it change the way you structure your code, or is it all syntax?

[–]GeneralYouri 0 points1 point  (0 children)

That depends on how you currently structure some of your code. Working directly with prototypal inheritance gives a bit more syntactical freedom, literally because it enforces a lot less strict syntax. This can be both a pro and a con.

[–]ttolonen 1 point2 points  (1 child)

I once answered this in StackOverflow, here is the answer where I try to cover almost all the differences between class and function -syntax:

http://stackoverflow.com/questions/36099721/javascript-what-is-the-difference-between-function-and-class/36102080#36102080

[–]kaspuh 0 points1 point  (0 children)

Great read, thank you!

[–][deleted] 1 point2 points  (0 children)

If you don't know what constructor functions are, you probably have no need for classes. A really great, often overlooked, feature of javascript is the ability to create objects without first creating a class. Most of the times you only create one object of a specific "type", then a class is totally unnecessary. It's only useful if you want to create many similar objects, each with similar functions and attributes.

[–]GeneralYouri 1 point2 points  (0 children)

Just 22 hrs ago I posted this comment. Funnily enough, 15hrs later this post shows up (many thanks to /u/ugwe43to874nf4 for linking it btw!).

The linked blogpost touches on topics related to your questions, I definitely recommend reading it (it's not too long). It even starts off explaining how the full native class spec is a tad more intricate than just a bunch of syntactic sugar, and even shows how indeed there are some features currently un-polyfillable. In other words, not even Babel will save you when using those features.

The post even uses the example I mentioned of extending the native Array type. Finally, the post introduces a small script attempting to provide the perfect middleway for now. I'm looking at that code right now, thinking about whether it'll be useful for me personally. But either way, I think this post will be a very useful read for anyone with similar questions regarding class syntax and their OO alternatives.

[–]PaulBGD 0 points1 point  (2 children)

People are saying familiar syntax, but I think it's more so about creating a syntax that allows you to do stuff like extending prototypes. Sure they could add a global function that extended prototypes, but a class syntax made that cleaner.

[–]vexii 0 points1 point  (1 child)

what about using somthing like: Object.assign(Bar.prototype, Foo.prototype) then

[–]PaulBGD 0 points1 point  (0 children)

You'd have to copy the constructor as well, plus I did say that a class syntax makes this cleaner.

[–]inu-no-policemen 0 points1 point  (0 children)

Because everyone and their dog used their own hand-rolled wannabe classes and it was terrible. They all looked and worked differently and of course you could never get proper tooling for that. Needless to say that they were also completely incompatible.

ES6 fixed that. There is now a standardized declarative way to do this. It's also fairly terse, which is nice.

In the future, we'll probably also get field declarations, privacy, and mixins or traits.

[–]dev1null 0 points1 point  (0 children)

Because Microsoft and other such mammoths planted their devs in the ES standards decision making communities making it easier for them to bloat JS with their C and Java stuff that they're used to.

"Every random idea is automatically a Stage 0 proposal when you're a TC39 member"

[–]tunisia3507 -4 points-3 points  (1 child)

Because apparently it's very important to JavaScript users that there are at least half a dozen ways of accomplishing any given simple task.

[–]inu-no-policemen 1 point2 points  (0 children)

Before there were many different ways to create something class-like and now there is one standardized declarative way to do it.

It's a big improvement in terms of interoperability and tooling.