
ES6 in Depth: Classes - shawndumas
https://hacks.mozilla.org/2015/07/es6-in-depth-classes/
======
Cshelton
Hopefully 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!

~~~
sago
It'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.

~~~
TazeTSchnitzel
The 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.

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

~~~
angersock
If it's truly a standard, there should be no other options.

Instead, this sets the stage for lots of OOPish JS which feels very different
from a lot of existing code out there, and will result in awkward shims to
interface the different paradigms.

We already see such ugliness in C++.

~~~
chc
> _If it 's truly a standard, there should be no other options._

That's a bit strong. Most languages come with a standard set of data
structures, but that doesn't mean they make it impossible to implement other
data structures if it suits you (e.g. few languages include binary trees as a
standard data type, but that doesn't mean you can't use them).

C includes standard string algorithms, but that doesn't mean you can't write
your own — you can even create your own string type if C strings are
problematic for some reason.

Many things in many languages are there to offer a reasonable default that is
generally useful. This seems along those lines to me.

------
epidemian
This 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
This 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
> 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?

It does. But don't you feel that making that distinction makes the code more
inflexible for (arguably) little gain?

To put a concrete example, let's consider an "items left" property of a TODO
list:

    
    
      class TodoList {
        // ...
        itemsLeft() {
          return _.count(this.todos, todo => !todo.done)
        }
      }
    

itemsLeft was defined as method because it's computed by iterating a list, so
we deem it non-trivial. But let's say that later on we discover that a better
internal structure for our TodoList is to have the unfinished and finished
todo's in different lists, so our itemsLeft becomes "trivial":

    
    
      class TodoList {
        // ...
        itemsLeft() {
          return this.unfinishedTodos.length
        }
      } 
    

If using getters is preferable for trivial properties, should we then change
itemsLeft to be a getter and refactor the existing code that uses it?

Besides, there's the problem of having to draw a line between trivial and non-
trivial code (e.g., "is string concatenation trivial?", "but it's O(n+m) on
the lengths of the strings!", etc). Using always the same style for accessors
(either plain-old methods or getters), regardless of how complex the
underneath code is, frees us from having to make this consideration in the
first place and also leaves the door open for changing an object's
implementation without changing its public interface.

\---

I feel this perception probably depends on the language background tough.
E.g., in languages like Ruby you always interact with objects via messages, so
you never have this distinction of whether something is computed or not from a
the caller's perspective (or at least not in a syntactic level).

But it's weird that this distinction is made in JS though, as many of the
classic JS APIs have computed properties that "do stuff", and quite a lot!
(e.g., Node#textContent). My guess is that most likely it's a result of the
language lacking user-definable getters and setters for such a long time.

------
raziel2p
Working 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
Or use :

    
    
      myMethod = (arg) => {return this.value + arg;}
    

With es7.classProperties in babel.
[https://babeljs.io/docs/usage/experimental/](https://babeljs.io/docs/usage/experimental/)

~~~
karcass
Or more tersely:

    
    
      myMethod = arg => this.value + arg;

------
thomasfoster96
Fun fact: code within a class definition is always strict mode code. Indeed,
so is anything within a module.

~~~
TazeTSchnitzel
w- _what_?!

So there is a new way to activate strict mode?!

~~~
thomasfoster96
Nope, 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).

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

------
ffn
Not 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
You mean like the ES7 decorators proposal[1], or something else?

[1] [https://github.com/wycats/javascript-
decorators](https://github.com/wycats/javascript-decorators)

~~~
sago
But 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
Thanks 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.)

~~~
sago
I was responding to the person responding to you mostly, but thanks for
clarifying, I'd not taken your issue seriously in my reply.

Having just a deprecated macro seems very narrow and special case to me.

Something like FF's getSource would work.

    
    
        var deprecated = function(fn) {
           console.warn("Function "+fn.name+" deprecated (at "+fn.getSource()+")");
           fn.apply(this, arguments);
        };
    

but obv. isn't useful in real code at the moment because it is FF-only
(afaik).

I'm generally quite nervous of 'special forms' in languages that don't allow
you to define them yourself. Part of why scheme is so powerful is that most of
it can be implemented in the same tools it gives you. I'd like to see that
approach.

------
pags

      static set circlesMade(val) {
        this._count = val;
      };
    

What's the value of "this" here?

~~~
dsp1234
It's the class constructor function.

Something like:

    
    
      Function Circle(){}
      
      Circle.circlesMade(val) = function circlesMade(val){
        this._count = val;
      }

~~~
pags
That's strange, coming from Java.

~~~
dsp1234
That'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"

------
tgibson
So... JS with Classes... or JS++

edit: Why the downvote? I'm just having a bit of fun.

~~~
scott_s
Regarding 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.

