Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using super in an object created with Object.create

Today morning I came across a tweet from Šime Vidas where he presented the following possibility of using super in object literals:

let A = {
  run() {
    console.log('A runs');
  }
};

let B = {
  run() {
    super.run();
  }
};

Object.setPrototypeOf(B, A);

B.run(); // A runs

This works, and assigning B.__proto__ = A; instead seems to work as well, both in Firefox and Chrome.

So I figured I could do the same with Object.create:

let A = {
  run() {
    console.log('A runs');
  }
};

let B = Object.create(A);
B.run = function() { super.run() };

Unfortunately, this results in an error in both Firefox:

SyntaxError: use of super property accesses only valid within methods or eval code within methods

And Chrome:

Uncaught SyntaxError: 'super' keyword unexpected here

The same happens when I try to pass a property descriptor object to the second argument of Object.create.

Semantically, they both seem equal to me, so I'm not quite sure what is happening (is it because of the object literal?).

Now I'm wondering, is this standard behaviour that is exactly defined (spec reference appreciated)? Are there some implementations missing for Object.create, or should object literals not work in the first place?

like image 725
nils Avatar asked May 12 '16 14:05

nils


People also ask

What is the difference between object assign and object create?

Object. assign() provides shallow copying (Only properties and methods) and it will override the method and property declared. while Object. create() provides Deep copying provides prototype chain.

What does super () do in JS?

The super keyword in JavaScript acts as a reference variable to the parent class. It is mainly used when we want to access a variable, method, or constructor in the base class from the derived class.

What is the use of object create?

The Object. create() method creates a new object, using an existing object as the prototype of the newly created object.

What is object create null?

prototype while Object. create(null) doesn't inherit from anything and thus has no properties at all. In other words: A javascript object inherits from Object by default, unless you explicitly create it with null as its prototype, like: Object. create(null) .


2 Answers

Allen Wirfs-Brock, the editor of the ES2015 spec, was kind enough to answer my question on twitter.

Why is this an error?

super property references can only occurs in “concise methods” within a class def or obj lit http://tc39.github.io/ecma262/#sec-function-definitions-static-semantics-early-errors

In that section of the spec, Static Semantics: Early Errors, there are four points that seem to be relevant:

  • It is a Syntax Error if FormalParameters Contains SuperProperty is true.
  • It is a Syntax Error if FunctionBody Contains SuperProperty is true.
  • It is a Syntax Error if FormalParameters Contains SuperCall is true.
  • It is a Syntax Error if FunctionBody Contains SuperCall is true.

So, super properties calls are neither allowed in function parameters, nor in regular function bodies. Thus my problem.

Why is it necessary to use a method definition?

the reason is that super requires a back link from the method to its containing object. http://tc39.github.io/ecma262/#sec-runtime-semantics-definemethod

Meaning, if I have a super call in a method, and I assign that method to another variable, it still has to work:

let B = {
  run() {
    super.run();
  },
  walk() {
    console.log(typeof this.run);
  }
};

var run = B.run;
run(); // the 'super' binding still works, thanks to the internal MakeMethod

var walk = B.walk;
walk(); // 'undefined': the 'this' binding on the other hand is lost, as usual

This is specified in step 7 of the section defining the method semantics, which currently does not happen for regular assignments to an object:

  1. Perform MakeMethod(closure, object).

Could these semantics change in the future?

The back link is essential. Ways to dynamically set it were considered and could be again. Left out b/c error prone

So it would be possible that something like .toMethod, which can set the object super references to, could be introduced into the language after all, making my initial example with Object.create possible.

like image 94
nils Avatar answered Nov 11 '22 22:11

nils


I mean you can do this:

let A = {
  run() {
    console.log('A runs');
  }
};

let B = {
  run() {
    super.run();
  }
};

Object.setPrototypeOf(B, A);

let C = Object.create(B);
C.run(); //A runs

By the way, this also fails:

let A = {
  run() {
    console.log('A runs');
  }
};

let B = {
  run: function() {
    super.run(); // 'super' keyword unexpected here
  }
};

Object.setPrototypeOf(B, A);

B.run();
like image 45
Arg0n Avatar answered Nov 11 '22 23:11

Arg0n