0

Update : Post by @Bergi on this thread explains the need to use Reflect.construct instead of just calling the parent constructor. This shifts the question to "What's the technical difference between Constructor.call() and Reflect.construct()". Thanks for all the comments.

For quite a while I have been extending all sorts of types by setting the prototype of my new prototype to the one that is to be extended. E.g. If I wanted to extend the class "Person" i'd create my extending prototype by calling NewType.prototype=Object.create(Person.prototype); for something like:

const B = function(){
    return A.call(this);
};

B.prototype = Object.create(A.prototype);

B.prototype.extra_method = function(){
    console.log('hello');
}

Recently I have noticed tho that this method is not as capable as the ES6 class extends. For example if I wanted to extend a builtin type, I can only really do that with the class extends keyword. Why is that?

Example A (does not work):

const ArrayExt = function(){
    this.extra_variable = 'hello!';
    return Array.call(this,...arguments); 
}

ArrayExt.prototype = Object.create(Array.prototype);

ArrayExt.prototype.extra_method = function(){
    console.log('Method called!');
}

var inst = new ArrayExt(1,2,3);

inst.push(4);
inst.length == 4 //seems to work right?

inst.extra_method == undefined //not included
inst.extra_variable == undefined //not included (why?)


Example B (works):

const ArrayExt = class extends Array{
    constructor(){
        super(...arguments);
        this.extra_variable = 'Hello!';
    }

    extra_method(){
        console.log('I actually am here now!');
    }
};

var inst = new ArrayExt(1,2,3);

inst.push(4);
inst.length == 4 //works
inst.extra_variable == 'Hello!' //works
inst.extra_method() //'I actually am here now!' works
John Smith
  • 570
  • 2
  • 7
  • 17
  • 1
    classes and extends are just syntactic sugar to old style "classes" and "extends" . If you use a transpiler to convert ES6 to older syntax then you'll confirm this is more or less accurate – apokryfos Dec 09 '17 at 12:48
  • so then how come I can only extend builtin types (Array,Function) with the extends keyword? – John Smith Dec 09 '17 at 12:50
  • 2
    https://stackoverflow.com/questions/33369131/is-it-possible-to-inherit-old-style-class-from-ecmascript-6-class-in-javascript looks relevant. Also your question is asking the opposite of what your comment is saying. – apokryfos Dec 09 '17 at 12:55
  • How so? Thanks for the link, this really does seem relevant. – John Smith Dec 09 '17 at 12:58
  • You are saying that you can only extend `Array` and `Function` using the `extends` keyword (which is not true, the old style should still work https://jsfiddle.net/z63qsrk0/) but your comment says that you cannot use the `extends` keyword on any built in type other than Array and Function (which may be true not sure) – apokryfos Dec 09 '17 at 13:01
  • I tested your fiddle. It only works at first glance, then I noticed that the extra_method is not included in the object. It seems to simply ignore the extending prototype. i.e. b.extra_method == undefined. Also I think you might misread what I wrote. Atleast if "not as capable as ES6 class extends" means "not as powerful as ES6 class extends" (not a native speaker). – John Smith Dec 09 '17 at 13:05
  • @apokryfos no his question is completely logical. – Jonas Wilms Dec 09 '17 at 13:06
  • *“Why is that?”* No particular reason for being able to do it – you just can, now. I’d consider it another ES6 mistake. – Ry- Dec 09 '17 at 13:29
  • I gave the previously posted thread a more thorough read, and it seems that what I am doing is "parasitic inheritance", I was missing the use of Reflect.construct, which works (!). – John Smith Dec 09 '17 at 13:33

1 Answers1

1

What's the technical difference between Constructor.call() and Reflect.construct()

It's a different usage of the function object. It's the same as the difference between Example() and new Example().

The two expressions always did different things, resolving to two different internal methods (named [[call]] and [[construct]]) that an object could have. ES6 just introduced new types of functions where only one of them works (arrows, methods: call; class constructors: construct). Functions created from function syntax always did enable both (even when it was not desirable).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks for the answer @Bergi. I assumed that the new operator just calls the constructor-function with a new instance, as in myType.call(Object.create(myType.prototype)). Is there a special reason for the new operator not doing just that instead of calling this internal [[construct]] method? – John Smith Dec 09 '17 at 17:35
  • 1
    @JohnSmith Not exactly. `new` is calling the [[construct]] method, which was doing this instance construction and function body execution (plus some things about the return value) with old `function` constructors. Some builtins (like `Date` or `HTMLElement`) did work differently the whole time - and now with ES6 they are extensible. – Bergi Dec 09 '17 at 18:54