简体   繁体   English

在使用Object.create创建的对象中使用super

[英]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: 今天早上我发现了来自ŠimeVidas推文 ,他提出了以下在对象文字中使用super可能性:

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; 这是有效的,并指定B.__proto__ = A; instead seems to work as well, both in Firefox and Chrome. 相反,它似乎也适用于Firefox和Chrome。

So I figured I could do the same with Object.create : 所以我想我可以用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: 不幸的是,这导致两个Firefox出错:

SyntaxError: use of super property accesses only valid within methods or eval code within methods SyntaxError:使用超级属性访问仅在方法中的方法或eval代码中有效

And Chrome: 和Chrome:

Uncaught SyntaxError: 'super' keyword unexpected here 未捕获的SyntaxError:'super'关键字在这里意外

The same happens when I try to pass a property descriptor object to the second argument of Object.create . 当我尝试将属性描述符对象传递给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? Object.create是否缺少某些实现,或者对象文字是否应该首先不起作用?

Allen Wirfs-Brock, the editor of the ES2015 spec, was kind enough to answer my question on twitter . ES2015规范的编辑Allen Wirfs-Brock非常友好地在推特上回答了我的问题

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 超级属性引用只能出现在类def或obj中的“简明方法”中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. 如果FormalParameters包含SuperProperty,则为语法错误。
  • It is a Syntax Error if FunctionBody Contains SuperProperty is true. 如果FunctionBody包含SuperProperty为true,则为语法错误。
  • It is a Syntax Error if FormalParameters Contains SuperCall is true. 如果FormalParameters包含SuperCall为true,则为语法错误。
  • It is a Syntax Error if FunctionBody Contains SuperCall is true. 如果FunctionBody包含SuperCall为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. 原因是super需要从方法到其包含对象的反向链接。 http://tc39.github.io/ecma262/#sec-runtime-semantics-definemethod 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: 这在定义方法语义的部分的步骤7中指定,当前对于对象的常规分配不会发生这种情况:

  1. Perform MakeMethod (closure, object). 执行MakeMethod (闭包,对象)。

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 遗漏了b / c容易出错

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. 因此,可能.toMethod可以设置对象super引用的.toMethod这样的东西引入到语言中,这使得我的初始示例可以使用Object.create

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();

Your answer covers most of it. 你的答案涵盖了大部分内容。 super calls are only allowed in methods because methods are tied closely with the object they are declared on. super调用只允许在方法中使用,因为方法与声明它们的对象紧密相关。 That said, your best option would be to do 那就是说,你最好的选择就是做

let B = {
    __proto__: A,
    run(){
        super.run();
    }
};

to declaratively create an object that has A as the prototype without requiring a potentially deoptimizing call to Object.setPrototypeOf(B, A). 以声明方式创建一个具有A作为原型的对象,而不需要对Object.setPrototypeOf(B, A).进行潜在的去优化调用Object.setPrototypeOf(B, A).

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM