8 ms·
ES6 in Depth: Classes
- thomasfoster96 11y agoFun fact: code within a class definition is always strict mode code. Indeed, so is anything within a module.
- TazeTSchnitzel 11y agow-what?! So there is a new way to activate strict mode?!
- thomasfoster96 11y agoNope, you'll still need to use "use strict" if you're not in a class definition or a module. It's just that classes and modules are strict mode by default (and there's no way of changing that as far as I know).
- Cshelton 11y agoHopefully this will clear the whole "class" thing in javascript up with some people. Every time I mention using classes in Javascript I get the obligatory response, "That's stupid, they are not actual classes, just syntactic sugar. I'm not using that!" face palm Yes, I know...but look at how much nicer that is to type than his first example... Pretty good, straight forward write up though!
- jonahx 11y agoDouglas Crockford says that classes were the single worst mistake in es6. So it's not really a face palm: https://www.youtube.com/watch?v=PSGEjv3Tqo0&t=5m https://www.youtube.com/watch?v=PSGEjv3Tqo0&t=5m
- jtuchsen 11y agoIs his entire complaint that the syntax looks too much like Java? The fact is, people are already using prototypes to share common methods across objects, and classes are really nice short syntactic sugar for doing that. His comment on classes there is too flippant to even know the meaning of his complaint. Beyond that I'd argue that classes give you more guarantees about how an object will behave at the expense of flexibility, although they give you escape hatches if you like. The reduced flexibility is really nice because you can define safe subsets of the language in which tools that analyze and refactor code are possible, even across files if you're using the module system. Moving the language in a direction where consistent universal tooling is possible to write is something that I love about classes, and is often overlooked in discussions about it. I don't care that classes are just a simplified subset feature of what's possible using prototypes, it covers the common case well enough and makes it possible to write really nice code completetion and refactoring tools that don't randomly break. That's worth all the extra magic in my opinion.
- roebk 11y agoPersonally I find the OLOO style much simpler, cleaner system. I'd be interested to know why you'd choose class over Object.create()
- jtuchsen 11y agoPeople do weird metaprogramming things with the existing constructs. In a lot of cases it's because people prefer to keep things DRY, but it hurts when you're trying to grep through a large codebase to find that one method you need. A contrived example: function Animal() {} function Cat() {} Cat.prototype = Object.create(Animal.prototype); (function(fields) { fields.forEach(function(field) { Cat.prototype[field] = function() { // Some nonsense }; }); })(['what', 'the', 'hell']); It's impossible to statically infer what methods are being declared in ES5 code in general. You can pick up on some common assignment patterns, but not all the weird stuff people do. Just check out the top 10 NPM modules and I guarantee you'll find some odd assignment patterns. I can remember that the "colors" module did meta stuff when I last checked. You can't just easily run the code to find out what the module is exporting either, because of potential side effects from IO. You can wrap Node's core IO modules, but that solution is specific to Node, and still won't cover every possible case. In short, it's a huge pain to write tools to pull information out of Javascript code in general, and that hurts the tooling ecosystem around Javascript. With the class pattern you at least have some staticly inferable information you're sure you can pull out of the class, and weird stuff is discouraged. I know in some ways that this is a weak argument, because of the new square bracket assignment, and the fact that anyone can muck with the prototype of the class after it's created. Even still, for the simple OLOO case it does encourage people to write code that has method names that can easily be staticly inferred, and that's a good thing for JS tooling possibilities. I really just want omnicompletion that doesn't randomly break on me! The OLOO pattern is one that's incredibly common in JS
- mhd 11y agoThere's no rest for the Java programmer, now even JS coders join the SmallTalk/Lisp elite… Is Crockford's dislike still based on this: http://www.crockford.com/javascript/inheritance.html http://www.crockford.com/javascript/inheritance.html ? Because I don't quite buy into that line of thinking. I'm really looking forward to webassembly…
- voyou 11y agoI think Crockford is wrong in that linked article. What he presents as unique features of prototype-based OO seem to really be features of highly dynamic OO. All of the things he implements in that article could be implemented just as easily (indeed, in more-or-less the same way) in Python or Smalltalk, couldn't they?
- wnevets 11y agoI gotta agree with him, the class sugar is just the continuation of the 'new' mistake.
- noobermin 11y agoThat was actually a great talk, I'm happy I'm not the only one in the world that doesn't use new...and the dec64 idea sounds freaking awesome
- sago 11y agoIt's a Faustian bargain. It blesses Javascript with a wider audience, less initial balking by new JS programmers, and a few characters for established JS programmers. But it does so by deliberately misleading programmers by naming the syntax to be the same as the thing they think they want, but JS doesn't contain. That seems like a dick move that condemns a whole slew of new developers to permanent misunderstanding of what they're writing, and a fundamental lack of clarity on prototypical inheritance. I will use it. Because syntactic sugar in this case does save some work. But I'm very conscious the code has swapped superficial clarity for deep lies. I suspect Stack Overflow will overflow with even more 'javascript OO is broken' questions and the MDN article won't make more than a dent on clearing up that (deliberate) confusion. I agree with Crockford on this.
- frik 11y agoI agree with Crockford too. It's Microsoft, Eich & co that pushed the class syntax based on ideas that originated in TypeScript. I am very grateful to Crockford for the "Good Parts" book and JS5 - I like that lean approach.
- TazeTSchnitzel 11y agoThe flexibility of prototypical inheritance is one of JavaScript's greatest assets. JavaScript: The Good Parts includes several different approaches to OOP which prototypes make possible. `class` just picks one and pretends the rest never existed.
- frik 11y agoExactly! Sadly many misunderstand JavaScript and don't even know or misunderstand prototype-based inheritance: https://en.wikipedia.org/wiki/Prototype-based_programming https://en.wikipedia.org/wiki/Prototype-based_programming Lua is another well know language that has prototype-based inheritance.
- chc 11y agoI don't see what's wrong with that. Converging on one way of doing things is part of the purpose of a standard. We still have the option of implementing a different method if we prefer, just as much as we ever did.
- fallat 11y agoIt is important they understand what is really happening though, or else they're in for a few surprises.
- Epenthesis 11y agoI'm sad that they don't have executable bodies. That was a key feature of CoffeeScript classes for me, and not having it makes ES6 classes considerably less useful/interesting.
- jbeja 11y agoThe stupidest addition to JS ever.
- deleted 11y ago[deleted]
- deleted 11y ago[deleted]
- Cshelton 11y agoNobody will ever give any credence to a statement like that if you do not list your reasons for why you think that.
- frik 11y agoWell, he is right, JavaScript is a Prototype based language which is technically more powerful than a class based one: https://en.wikipedia.org/wiki/Prototype-based_programming https://en.wikipedia.org/wiki/Prototype-based_programming
- reverius42 11y agoAnd it still is! So what's everyone complaining about? Language (keyword/syntax) bloat without adding new functionality?
- voyou 11y agoIs JavaScript really a prototype-based language? In prototype-based programming, you create an object which has shared functionality (the prototype), and then create new objects by cloning that object. That's not how you implement shared functionality in JavaScript; in JavaScript, you implement shared functionality by delegating to another object. In other words, JavaScript objects work like Python, or Ruby, or Smalltalk (yes, unlike these languages JavaScript, until ES6, makes no language-level distinction between an object which is also a class, and an object which isn't a class, but that's just a matter of syntactic sugar).
- tgibson 11y agoSo... JS with Classes... or JS++ edit: Why the downvote? I'm just having a bit of fun.
- scott_s 11y agoRegarding why you're probably getting downvoted: your comment does not add much to the discussion. Quick one-liners, which tend to make the obvious jokes, are usually seen as noise, and get downvoted.
- raziel2p 11y agoWorking with classes in ES6 is such a relief. My only complaint is that if you save a method as a variable or pass it to another function, it'll just be a function with its own scope (`this` won't reference the class instance, but instead the method function). Easily "fixed" if you remember to put `.bind(this)` everywhere, though.
- hokkos 11y agoOr use : myMethod = (arg) => {return this.value + arg;} With es7.classProperties in babel. https://babeljs.io/docs/usage/experimental/ https://babeljs.io/docs/usage/experimental/
- savanaly 11y agoSample code from just this afternoon: const typeMap = { 'i-text': this.processText.bind(this), 'image': this.processImage.bind(this), 'rect': this.processRectangle.bind(this) }; Really annoying if you ask me, though I understand why it had to be this way.
- ffn 11y agoNot gonna lie, classes, destructing, TCO, and all these "engineering optimizations" are great... but what JS really, really, really needs is some sort of way to declare decorator macros. A great use case for these macros (especially in the browser) is in dealing with those god-awful deprecation warnings any given big-enough framework will eventually start spitting out after enough usage. Right now, framework developers use console.warn which, as a function, is usually buried in the framework, and so gives stack-traces that are entirely useless to a developer using said framework (especially if the framework wraps console.warn in some way). A good clean way of declaring macros will allow JS frameworks to not be cancerous to maintain by making the stack-trace for deprecated user-code very easy to spot and correct. And unlike features such as classes, generators, symbols, and even TCO that are reasonably achievable through clever engineering, macros flat-out have to be special-formed in. But their utility in making JS a much more maintainer-friendly language would go a long way to reducing the misery of us plebeian js users.
- joshuacc 11y agoYou mean like the ES7 decorators proposal[1], or something else? [1] https://github.com/wycats/javascript-decorators https://github.com/wycats/javascript-decorators
- sago 11y agoBut decorators are just syntactic sugar around functions. You can have them now with; var deprecated = function(fn) { console.warn("Deprecated!"); fn.apply(this, arguments); }; then var oldMethod = deprecated(function() { }); In ES7 you'll be able to call decorators with the new syntax: @deprecated function oldMethod { } But nothing stopping you writing modular code now. The complaint about 'I have to write console.warn everywhere' seems to have an obvious answer; 'no you don't'. As for other issues with ES6+7, the new syntax trades a few characters for a lack of clarity about what is actually happening.
- ffn 11y agoThanks for writing it out, but you've actually illustrated exactly my complaint. When you call oldMethod console.warn will spit out the line number of the wherever in your framework you have the var deprecated = function(fn) { console.warn("Deprecated!"); fn.apply(this, arguments); }; declared... but you (as the user of a framework) still have no real idea where the actual function you shouldn't be calling (the fn) lives in your code (especially since the function can be anonymous)... you just know that the framework is telling you you're using a deprecated function somewhere in the code you wrote. What I really want, and what can't be achieved with your purely in-language solution (and it really is a great solution considering the constraints), is a special form for things like @deprecated such that it straight-up can capture not only the function it's decorating, but also meta-data about the function (e.g. where it's declared, the caller / callee, etc.)
- epidemian 11y agoThis is unrelated to JS classes, but is there a good reason for using getters/setters for some properties but not for other? I've always had trouble understanding why some people prefer this style. For instance, given the article's Circle definition (any of them), accessing a circle's radius is different than accessing its area: let c = new Circle(10); c.radius // => 10; good c.area // Nope, that returns a function. c.area() // => 314.15... OK c.radius() // Raises a TypeError, 10 is not a function Presumably, the author declared the area accessor as a function instead of a getter because it does some other computation beyond returning a stored value. But a different implementation of Circle could instead store the area and compute the radius from that[1]. In that case, would we then have to change the way of accessing the circle's properties to `c.area` and `c.radius()`? I think it'd be much better to define these properties so accessing them has a uniform syntax: either `c.area` and `c.radius`, or `c.area()` and `c.radius()`[2]. Isn't in fact the purpose of adding getters and setters to the language to allow users to define how a property is accessed? [1]: That might make sense if it turns out that asking for a circle's area is much more common than asking for its radius, and it's done so frequently that it impacts performance; or if we prefer to have circles with nice round numbers for areas in our application and don't care too much about their radii. [2]: Yeah, i know that there is a named principle for this. In fact i always thought that adding getters and setters was motivated by the Uniform Access Principle.
- dcherman 11y agoThis is not a hard and fast rule and I have no idea if there is any pattern, but I reserve getters for trivial properties like `firstName + " " + lastName;` If it does any non-trivial amount of work, then I always use a function. The reason for that is in codebases that I've worked on in the past, getters were heavily overused and people ended up writing code that while at a glance seemed entirely reasonable, it was actually doing an absurd amount of redundant work and was causing performance issues. I feel that requiring the `()` to invoke it as a function at least hints that "this does stuff" rather than hiding the implementation in a getter. Does that make sense?
- epidemian 11y ago
- pags 11y agostatic set circlesMade(val) { this._count = val; }; What's the value of "this" here?
- dsp1234 11y agoIt's the class constructor function. Something like: Function Circle(){} Circle.circlesMade(val) = function circlesMade(val){ this._count = val; }
- pags 11y agoThat's strange, coming from Java.
- dsp1234 11y agoThat's a validation of some of the other discussion in the thread. JavaScript gets a 'class' keyword, but it's really just syntactic sugar over prototypical inheritance. So there is some misunderstanding about what it does and doesn't do. That said, it could have also been written as: static set circlesMade(val) { Circle._count = val; }; which means the exact same thing, and would maybe help people to understand that "_count" is just like a static class property on the Circle "class"