2

As the output of 6to5 I've got the following code:

var _inherits = function (subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
      throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
      constructor: {
        value: subClass,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
    // question is about next row
    if (superClass) subClass.__proto__ = superClass;
  };
_inherits(Controller, CoreController);

Can anybody describe what for used updating __proto__ property? As i try - it doesn't nothing useful

P.S. as documentation says that proto should be object, but in code is used for setting function

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Vasiliy vvscode Vanchuk
  • 7,007
  • 2
  • 21
  • 44

3 Answers3

3

Can anybody describe what for used updating __proto__ property?

ES6 specs that when classes inherit from each other, the resulting constructor functions should inherit from each other as well. CoreController.isPrototypeOf(Controller) will yield true.

As i try - it doesn't nothing useful

It is very useful for inheriting static properties, which are placed on the constructor functions in JS.

CoreController.hi = console.log.bind(console, "hello world");
CoreController.hi(); // hello world
Controller.hi(); // error
_inherits(Controller, CoreController);
Controller.hi(); // hello world

documentation says that proto should be object, but in code is used for setting function

Every function is an object in JS. It has a prototype, and it can serve as one.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • This behavior can't be defined with subClass.prototype = Object.create(superClass && superClass.prototype, { - it's common practice. What for __proto__ update? – Vasiliy vvscode Vanchuk Feb 23 '15 at 16:20
  • Yes, this behaviour can't be defined using `Object.create`, as `Object.create` does not create function objects. What's your question? – Bergi Feb 23 '15 at 16:21
  • Object.create - create object with all CoreController properties. And set it into prototype Controller - so controller instance will have all properties as Controller – Vasiliy vvscode Vanchuk Feb 23 '15 at 16:24
  • We're not talking about Controller *instances*, but about `Controller` itself. The instance inheritance is handled by the assignment above the line of interest. – Bergi Feb 23 '15 at 16:29
  • Yep. And what the matter to use proto? i can't catch ( – Vasiliy vvscode Vanchuk Feb 23 '15 at 17:49
  • 1
    What else would you use? OK, `Object.setPrototyeOf` should actually be shimmed :-) – Bergi Feb 23 '15 at 17:52
  • @VasilVanchuk: There are only two ways to set the prototype object of an *existing* object. `__proto__` is one of them. – Felix Kling Feb 24 '15 at 16:10
2

Not really an answer to your question, but more of a warning regarding overriding inheritance:

Assigning the __proto__ property of an object or using the ES6 equivalent Object.setPrototypeOf() has severe performance impacts on any code path that is touched by such an object.

Blog post with benchmarks showing some of the performance impact.

Firefox emits a warning when you do this:

mutating the [[Prototype]] of an object will cause your code to run very slowly;
instead create the object with the correct initial [[Prototype]] value using Object.create 

To quote from mozilla bug 984146

The __proto__ is deadly for the type inference, basically, after doing that this means that Type Inference is unable to follow any of the properties of the object as you are changing the underlying object lookup behind his back.

This basically means that every lookup you do on this object or any object created with this constructor will fallback on a slow path for reading/writing properties to the object. I might under estimate this issue, Eric would know better. (ni: efaust)

It's even worse than that.

When you set __proto__, not only are you ruining any chances you may have had for future optimizations from Ion on that object, but you also force the engine to go crawling around to all the other pieces of TI (information about function return values, or property values, perhaps) which think they know about this object and tell them not to make many assumptions either, which involves further deoptimization and perhaps invalidation of existing jitcode.

Changing the prototype of an object in the middle of execution is really a nasty sledgehammer, and the only way we have to keep from being wrong is to play it safe, but safe is slow. If possible, try to create directly with prototype chain you want. If we really have to swizzle prototype chains around dynamically, I'm not sure I have great advice as to how to minimize the performance implications of that action.

the8472
  • 40,999
  • 5
  • 70
  • 122
2

It's used for 'static" properties inheritance. Please see the code example below:

class Parent {
 myMethod() {}
}

console.log(Parent.prototype.myMethod); // [Function]
console.log(Parent.prototype.hasOwnProperty('myMethod')); // true
console.log(Parent.myMethod); // undefined

class Child extends Parent {}

console.log(Child.prototype.myMethod); // Function
console.log(Child.prototype.hasOwnProperty('myMethod')); // false
console.log(Child.myMethod); // undefined

Parent.myStaticProp = 42;

console.log(Parent.prototype.myStaticProp); // undefined
console.log(Parent.myStaticProp); // 42
console.log(Parent.hasOwnProperty('myStaticProp')); // true

console.log(Child.prototype.myStaticProp); // undefined
console.log(Child.myStaticProp); // 42
console.log(Child.hasOwnProperty('myStaticProp')); // false

Also, in the similar question on github, yuchi said:

Notice how ‘static’ properties are added after extension.

It’s deprecated because it doesn’t give the interpreter a way to know beforehand that the object (function, in this case) has a different prototype chain than the standard one. Every JS interpreter implements it, and that’s because there’s still no perfect agreement on Object.setPrototypeOf, in fact for performance reasons IMO.

And looks like that 6to5 wants to be as compatible as possible to ES6 semantics, so setting Child.proto to Parent is an acceptable tradeoff.

The detailed discussion you can find by the link: https://github.com/babel/babel/issues/87#issuecomment-60139066

Also, you can look at the good question from basarat about mutating [[Prototype]] and performance by the link: Why is mutating the [[prototype]] of an object bad for performance?

ebaranov
  • 575
  • 7
  • 17
  • 1
    Your answer is useless without the link. Answers should be self-contained. Please quote the relevant part in your answer. – Felix Kling Feb 24 '15 at 16:09
  • I'm already added the link to the long and detailed discussion from the authors of code from question, this is very useful I guess. – ebaranov Feb 25 '15 at 00:47
  • Again, answers should be **self-contained**. If the link is unavailable for any reason, your answer is useless. Please see http://stackoverflow.com/help/how-to-answer . – Felix Kling Feb 25 '15 at 00:48
  • 1
    Thanks for the notice Felix Kling, I just don't took into account the fact what the link can be broken for **any reason**. Hope the answer looks good at the moment. – ebaranov Feb 25 '15 at 22:21