News for hackers. Stuff that matters.
Re:Refactoring Legacy JavaScript Code to Use Classes by pg_bot on Tuesday March 07, 2017 @02:44PM (#13813975)
While I'm a huge fan of what ES2015 has brought to JavaScript, the "class" keyword was a huge mistake. There are no classes in Javascript, there are only objects. By embracing prototypal inheritance you will write cleaner code with fewer errors.
Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Tuesday March 07, 2017 @06:48PM (#13816422)
> the "class" keyword was a huge mistake. There are no classes in Javascript, there are only objects

That's true if you define the word "class" to not include JS classes, but in that case, you can use the keyword and still "embrace" prototypal inheritance, since as you say, it's all just objects (even if you use the class keyword).

Alternatively if you use a more flexible definition of the word class, then your assertion is not true, because JS does have classes, they just are implemented via prototypes.

Either way, I don't see how your comment is correct. Is it all objects, or not? :)

Re:Refactoring Legacy JavaScript Code to Use Classes by camus2 on Tuesday March 07, 2017 @07:33PM (#13816729)
> the "class" keyword was a huge mistake

There is not a single fact proving that statement. People want to write Javascript in different ways, Javascript is no less OO that it is FP. I don't see why one camp should be more privileged than the other.

> prototypal inheritance you will write cleaner code with fewer errors.

JS Classes use "prototype inheritance". compare that :

    function Foo(){}

    function Bar(){
       Foo.call(this)
    }

    Bar.prototype = Object.create(Foo.prototype)

with that :

    class Foo{}

    class Bar extends Foo{}

There is absolutely no debate as to what is more readable, cleaner,easier to parse for IDE, and less error prone. ES6+ is considerably making writing JS easier and safer. There is very little reason today to deal with prototypes directly. And in strict mode, calling Foo or Bar without using new yields an error.
Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Tuesday March 07, 2017 @09:54PM (#13817487)
Encouraging inheritance in the first place is the mistake. Using composition with Object.assign is far less fragile than inheritance. An article with concrete examples: https://medium.com/javascript-scene/master-the-javascript-in...
Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Tuesday March 07, 2017 @10:21PM (#13817589)
> Encouraging inheritance in the first place is the mistake.

Yes.

> Using composition with Object.assign is far less fragile than inheritance.

Absolutely not. Object.assign is an example of inheritance, not composition, and it's just as fragile as the others. Eric Elliott is well known for calling "composition" what everyone else calls "multiple inheritance". See, eg:

http://wsieroci.github.io/elliott/inheritance/composition/20...

https://www.reddit.com/r/javascript/comments/3oy9c3/composit...

It's almost a running joke on the /r/javascript subreddit at this point.

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Tuesday March 07, 2017 @10:36PM (#13817673)
How is Object.assign not a "has-a relationship"? From the first article you posted, this example of composition was given:

  {
    author: createAuthor(),
    posts: createPosts() 
  }
How is that different from this?

  Object.assign({}, author, post)
In both cases you end up with an object that has an instance of an author and a post. What am I missing?
Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Tuesday March 07, 2017 @11:10PM (#13817829)
> In both cases you end up with an object that has an instance of an author and a post.

But you don't; not even close.

The first one is a has-a relationship; the object contains two references (`author` and `posts`), which presumably point to an instance of the Author class and a collection of instances of the Post class (or whatever). This is composition.

The second is an is-a relationship; the object has the properties of the author and post objects copied over the top of it. There is now only one object (not three), and if we're lucky, it implements the interface contracts of both the Author class and the Post class.

Consider if Author has a title field that contains their preferred prefix (Mr, Ms, Mrs, Dr), and Post has a title field that contains the subject line.

With the first approach, we could do `foo.author.title` or `foo.posts[0].title`, using our references to the underlying Author or Post instances.

With the second approach, we can do `foo.title` or...`foo.title`. Whups. We have no references, there is no underlying Author or Post instances; there's just a single object which is trying to inherit the behaviour of both the Author and the Post class, and failing.

It's not a horrible way of implementing multiple inheritance in JS, but it's still inheritance. And in it's single inheritance form (`Object.assign({}, author)`) it's yields an identical result to normal prototypal inheritance or the class keyword.

Edit: This becomes even clearer when you start to flesh out the examples. Eg, https://jsbin.com/kigewonepe/1/edit?js,console

Note how obj2 has a `fullName` method (which only Author's do), because it is an author. Except note that it returns the wrong string when you run it, because obj is also a post. Where obj1 works correctly because it has an author and it has a post, without trying to be either of them. Composition over inheritance, just like the Gang of Four said. :)

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Tuesday March 07, 2017 @11:23PM (#13817880)
I can get foo.author.title and foo.post.title no problem using Object.assign:

  Object.assign({}, { author: author }, { post: post });
Can you give a better example of where a reference to an instance is any different than copying an instance?

EDIT: I fixed your example. https://jsbin.com/zamuqoropa/1/edit?js,console

EDIT 2: In fact, my Object.assign does exactly the same thing as your example of composition. And

  console.log(obj1.author === obj2.author);
produces 'true'.

https://jsbin.com/vafudizumo/1/edit?js,console

Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.

Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Tuesday March 07, 2017 @11:50PM (#13817982)

    Object.assign({}, { author: author }, { post: post });
Yep, that's composition and it's identical to my composition example. Of course, you're not actually using Object.assign() to do anything; your code is 100% identical to just saying:

    {author, post};
Not that there's anything wrong with that...but do note that it's also the exact opposite of what Elliott is advocating for, not what he shows off in his code examples, not what his Stampit library does, etc.

> Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.

Your first example (and Elliott's examples) are inheritance. Your second example is composition. The difference is enormous.

Edit: Elliott says here[0]

"Similarly, you can use `Object.assign()` to compose any number of objects together with last-in priority:"

    let ninjamouse = Object.assign({}, mouse, ninja);
1) That's not composition, that's inheritance.

2) That's the same as your first example, but fundamentally different than your second.

He's trying to make a "ninjamouse" which has the properties and methods of both mice and ninjas, because it is a mouse and a ninja. (That's inheritance, and it's fragile for all the reasons inheritance is always fragile).

Your second example makes an object that has both a mouse and a ninja. That's composition.

"This technique is called concatenative inheritance"

By absolutely no one ever. :)

[0]: https://medium.com/javascript-scene/common-misconceptions-ab...

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Wednesday March 08, 2017 @01:40AM (#13818445)
I agree now that what Eric Elliot is doing is not composition. But it's not inheritance as it is commonly known either. If I inherit from a prototype, then inherited objects can use the prototype methods via prototype delegation. If I change a method in the prototype, inherited objects will see that change. Which is similar to class based inheritance, but can happen at run time. That will not happen with Object.assign because it is cloning or copying. If I make a change to a prototype I cloned from, the cloned object will not be changed. This is also known as concatenative prototyping. Yes, it's considered a type of inheritance, but I think different enough from prototype delegation and class inheritance that it should be pointed out when claiming it is inheritance. Because copying feels closer to composition than than it does to OO inheritance or prototype delegation IMO. Composition still wins though. Good discussion.

"By absolutely no one ever. :)" Actually, quite often. A few examples below:

https://en.wikipedia.org/wiki/Prototype-based_programming#Co...

http://aaditmshah.github.io/why-prototypal-inheritance-matte...

http://www.datchley.name/understanding-prototypes-delegation...

Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Wednesday March 08, 2017 @03:21AM (#13818819)
> But it's not inheritance as it is commonly known either.

Wikipedia disagrees; do you have a citation in mind?

> Which is similar to class based inheritance, but can happen at run time.

That's not a distinguishing feature of class based inheritance; many implementation do this. Python's class based inheritance is extremely flexible and absolutely allows run time modification; to a greater or lesser extent this is true of many dynamic language (Ruby, Perl, etc.).

What do you think the defining feature of class based inheritance is that allows a clean distinction between JS and Python? Because I don't personally see much of one.

> Because copying feels closer to composition than than it does to OO inheritance or prototype delegation IMO.

Well, opinions are subjective. My experience has been the reverse, however.

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Wednesday March 08, 2017 @04:04AM (#13819002)
> Wikipedia disagrees; do you have a citation in mind?

Nowhere in the wikipedia main article about inheritance does it cover concatenation inheritance (https://en.wikipedia.org/wiki/Inheritance_(object-oriented_p...). You only find it in the article about Prototype based programming (https://en.wikipedia.org/wiki/Prototype-based_programming). It's also my personal experience (started with Java when it was first released...) that inheritance means class-based inheritance to a lot of devs. I'm sure that changes depending on which devs you hang out with.

If I understand right, concatenation is more commonly called a mixin? At least the way it's done in javascript. In which case the wikipedia article on that says 'Mixins are sometimes described as being "included" rather than "inherited". Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause'

Based on that last quote, I'm confident I'm not the only one with the opinion that concatenation inheritance isn't a strict "is-a" relationship and might veer towards "has-a". Maybe "has-a-trait" type relationship? That's also how Eric Elliot was using Object.assign. A guitar has distortion, volume, and a cabinet. Let's not go in circles: I still agree his code isn't composition. But mixins sure do blur the lines between composition and inheritance for me.

> That's not a distinguishing feature of class based inheritance

It was an aside. Not very important to the point I was making. The point was that prototype delegation and class inheritance are similar in the way that methods are inherited, and that's different from how concatenation treats methods. But thanks for the info, I didn't know that about Python.

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Wednesday March 08, 2017 @01:00AM (#13818287)
I can get foo.author.title and foo.post.title no problem using Object.assign:

  Object.assign({}, { author: author }, { post: post });
Can you give a better example of where a reference to an instance is any different than copying an instance?

EDIT: I fixed your example. https://jsbin.com/zamuqoropa/1/edit?js,console

EDIT 2: In fact, my Object.assign does exactly the same thing as your example of composition. And console.log(obj1.author === obj2.author); produces 'true'. https://jsbin.com/vafudizumo/1/edit?js,console Either you're doing composition wrong, or I'm not doing inheritance like you are claiming.

Re:Refactoring Legacy JavaScript Code to Use Classes by camus2 on Tuesday March 07, 2017 @10:10PM (#13817547)
The point the OP was making that the class keyword was a mistake, not that inheritance was a mistake. This is an entirely different topic.

Furthermore, Javascript classes make writing mixins AKA composition a breeze, compared to before:

http://justinfagnani.com/2015/12/21/real-mixins-with-javascr...

This link is an excellent rebuttal to Eric Elliot article and how he achieve composition through copying by the way.

So even if you like composition over inheritance, Javascript classes still allow you to write safer and clearer and cleaner code. Now you can do away with ugly factories and property copying.

> Object.assign is far less fragile than inheritance

You realize the using Object.assign means copying properties from object to object over and over and increase memory requirements in order to run a script.

So my point still stands, there is not a single disadvantage introduced with the class keyword.

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Tuesday March 07, 2017 @10:52PM (#13817744)
Thanks for the article, it's a long read that requires some thinking so I'll get to it tomorrow. In the meantime I'll put a Kyle Simpson chapter out there as a rebuttal to "there is not a single disadvantage introduced with the class keyword". He makes a good case that there is more than one disadvantage to the class keyword. https://github.com/getify/You-Dont-Know-JS/blob/master/this%...
Re:Refactoring Legacy JavaScript Code to Use Classes by baron816 on Tuesday March 07, 2017 @04:14PM (#13814950)
How about Parasitic Inheritance? http://www.breck-mckye.com/blog/2014/05/why-i-prefer-parasit...

You can get rid of "this" and all it's problems, and the code is even cleaner.

Re:Refactoring Legacy JavaScript Code to Use Classes by chickenfries on Tuesday March 07, 2017 @03:06PM (#13814214)
> By embracing prototypal inheritance you will write cleaner code with fewer errors.

[citation needed]

Classes are fine, they're just sugar over prototypal inheritance.

Re:Refactoring Legacy JavaScript Code to Use Classes by tantalor on Tuesday March 07, 2017 @04:29PM (#13815095)
Yes, this why the class keyword is great. Also it fixes inheritance which is not easy to do with prototypes.

  class A {}
  > class A {}
  class B extends A {}
  > class B extends A {}
  new B instanceof B
  > true
  new B instanceof A
  > true
There is just 1 way to do this with classes, it is very concise, and it is impossible to do wrong, e.g., by forgetting to call the super class constructor. Try doing that with prototypes.
Re:Refactoring Legacy JavaScript Code to Use Classes by MrPatan on Tuesday March 07, 2017 @06:04PM (#13816040)
That's the thing, with prototypes you don't use inheritance, which is the good option. Now it's easy to do the wrong thing. Thanks ECMA!
Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Tuesday March 07, 2017 @06:50PM (#13816438)
> with prototypes you don't use inheritance

That is 100% wrong. Prototypes are inheritance. Quoting from wikipedia:

"Prototype-based programming is a style of object-oriented programming in which behaviour reuse (known as inheritance) is performed via a process of reusing existing objects via delegation that serve as prototypes."

I have no idea what you were trying to say, but what you wrote is nonsense.

Re:Refactoring Legacy JavaScript Code to Use Classes by cmrdporcupine on Tuesday March 07, 2017 @08:12PM (#13816933)
Well arguably the definition of inheritance there doesn't meet the poster's idea of inheritance. Prototype 'inheritance' is a kind of delegation and some prototype OO languages make that explicit by using different terminology (Self says 'delegate' and not 'parent' for example).

But then arguably in class-based OO languages, classes don't "inherit" either and really just delegate to other classes.

(FWIW I wrote a big chunk of the prototype-OO article on WP at one point. Not sure how much of that text still exists)

Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Tuesday March 07, 2017 @10:20PM (#13817588)
It's sort of wrong, but not really if we are using the commonly used definition of inheritance where we think of the strict hierarchical inheritance provided by classes. And you mention prototype delegation which is only one type of inheritance provided by javascript and is also hierarchical. There are two other types of inheritance you can use with javascript: functional inheritance, and concatenative inheritance. Concatenative inheritance is so different from class inheritance that most people don't even call it inheritance. They call it object composition. Which has been preferred over class inheritance as far back as the GoF "Favor object composition over class inheritance." More here: https://medium.com/javascript-scene/master-the-javascript-in...
Re:Refactoring Legacy JavaScript Code to Use Classes by MrPatan on Wednesday March 08, 2017 @01:40PM (#13822482)
What I was trying to say is that without the class keyword, people used inheritance less, prototypal or whatever. Which is good, because inheritance sucks.
Re:Refactoring Legacy JavaScript Code to Use Classes by paulddraper on Tuesday March 07, 2017 @03:37PM (#13814588)
> By embracing prototypal inheritance you will write cleaner code with fewer errors.

Do you have a concrete example in mind? Code sample A is cleaner and has fewer errors than its class equivalent B?

Re:Refactoring Legacy JavaScript Code to Use Classes by namelezz on Tuesday March 07, 2017 @03:04PM (#13814192)
Can you give an example of errors introduced by using "class"?
Re:Refactoring Legacy JavaScript Code to Use Classes by JSDave on Tuesday March 07, 2017 @03:12PM (#13814284)
There's a lot of reasons against classes in JS. This list has a lot of articles. https://github.com/joshburgess/not-awesome-es6-classes A common point seems to be against the brittleness caused by inheritance (including prototypical) in general. Personally, I find that the tiny amount of performance you give up by using factory and composition patterns is generally worth not having to deal with binding the right context
Re:Refactoring Legacy JavaScript Code to Use Classes by chickenfries on Tuesday March 07, 2017 @04:02PM (#13814848)
Grand-parent comment asked for an example of an error introduced by using class that would've been avoided with prototype inheritance, and you respond with an "awesome" "curated" list of opinion pieces and conference talks by famous devs and rockstars...

This is what's wrong with the JS community and why everything is so hype driven... this list gives the impression that if you want to be a good JS developer you should've even THINK about trying to use classes in your JS because if you do then you don't truly "get" JS.

Think for yourself and decide if classes will improve your code in the way you plan to use it. Classes have hugely improved my company's JavaScript, it works well considering our developers understand OOP much better than they do functional programming, which I think is pretty common.

We don't rely on inheritance, we reuse by composition (which is just as easy to do with class as it is to do with protypes).

Classes are fine! Use them if you want to! Don't use them if your existing code relies heavily on prototypal inheritance, but if you just wanna wrap some methods around some internal state and you like the way the class syntax looks compared to the prototype syntax don't let some think piece on medium try to convince you that classes are bad.

EDIT: sorry to go off on a slightly OT rant on your comment... I just got frustrated by the link you posted.

Re:Refactoring Legacy JavaScript Code to Use Classes by JSDave on Tuesday March 07, 2017 @04:23PM (#13815034)
That list is actually making fun of what you're describing in the JS community. "Not Awesome" is a play on the "Awesome" lists like this [https://github.com/sindresorhus/awesome]

JS classes were extremely hyped up a year ago. Taking a stance against classes was going very hard against the hype.

How well your devs understand the code is the only real metric. If you understand OOP better, stick with it!

Re:Refactoring Legacy JavaScript Code to Use Classes by chickenfries on Tuesday March 07, 2017 @04:25PM (#13815053)
Huh, I must have missed the "classes are great" wave. I only remember the "classes are bad" FUD represented by this list... HN is my main connection to the hype train these days since I quit Twitter.

> How well your devs understand the code is the only real metric. If you understand OOP better, stick with it!

Agreed.

Re:Refactoring Legacy JavaScript Code to Use Classes by Lazare on Tuesday March 07, 2017 @06:52PM (#13816450)
That doesn't really answer OPs question though?

He's asking about why manipulating prototypes directly is better than doing so via the class keyword sugar, and your response seems to explains why you probably shouldn't do either one.

Re:Refactoring Legacy JavaScript Code to Use Classes by pg_bot on Tuesday March 07, 2017 @04:34PM (#13815146)
Kyle Simpson has a good writeup of the class keyword from his series of books "You don't know Javascript". https://github.com/getify/You-Dont-Know-JS/blob/master/this%... You can read through the gotchas section and come up with your own conclusions.
Re:Refactoring Legacy JavaScript Code to Use Classes by tchaffee on Tuesday March 07, 2017 @10:02PM (#13817516)
Classes enforce a strict hierarchical relationship which is rarely how the real world works. And you also inherit everything from a parent class whether you need it or not. One alternative to class inheritance possible with javascript is object composition (usually Object.assign()) which does not enforce a hierarchical relationship and you can use only what you want from other objects. More flexible, less brittle. Eric Elliot goes into details with concrete examples in this article. https://medium.com/javascript-scene/master-the-javascript-in...
Re:Refactoring Legacy JavaScript Code to Use Classes by popopobobobo on Tuesday March 07, 2017 @03:18PM (#13814355)
yeah, let's write js as pure functional language.
Re:Refactoring Legacy JavaScript Code to Use Classes by mpfundstein on Tuesday March 07, 2017 @04:28PM (#13815081)
Check fantasy-land and ramda
Re:Refactoring Legacy JavaScript Code to Use Classes by draw_down on Tuesday March 07, 2017 @03:20PM (#13814377)
Agreed that `class` was a mistake, but I try to use inheritance (of any kind) as sparingly as possible.