为什么在方法的简写语法中[[HomeObject]]会与普通语法不同?

4

这个问题源自super keyword unexpected here

被接受的回答说:

因为 super 只在方法内部有效。

但在MDN中,它们两个看起来都是方法:

let person = {
    greeting() {
        return "Hello";
    }
};

let friend = {
    // shorter syntax for method?
    greeting() {
        return super.greeting() + ", hi!";
    }

//  method?
//  greeting: function() {
//      return super.greeting() + ", hi!"; // Throw error: Uncaught SyntaxError: 'super' keyword unexpected here
//  }

};

Object.setPrototypeOf(friend, person);
console.log(friend.greeting());   

理解 ES6 中,Nacholas 提到:

在简洁方法之外尝试使用 super 会导致语法错误。

方法 只是包含函数而不是数据的对象属性。

任何对 super 的引用都使用 [[HomeObject]] 确定要执行的操作。 第一步是在 [[HomeObject]] 上调用 Object.getPrototypeOf() 以检索原型的引用。 然后,在原型中搜索具有相同名称的函数。 最后,设置 this 绑定并调用该方法。

所以看起来在简写方法语法中 [[HomeObject]] 是不同的?我很好奇为什么?

你能展示一下两个代码块所在的上下文吗?它们是放在哪里的呢?greet: function() {} 这只是一个普通对象上的属性声明,可能在 super 看来并不是技术上的"方法"。它只是一个简单的属性。无论如何,为什么不使用 class 语法,避免整个问题呢?你已经要求可用的 super,所以你可以信任 class - jfriend00
感谢 @jfriend00,1. 代码块已经完成。2. 在MDN中,“greet:function(){}”似乎满足“方法”的定义?这让我感到困惑。3. “class”语法是另一个话题,我只是在看这本书,对“super”行为感到好奇。 - Tina Chen
嗯,“super()”是设计用于“类”的。如果您在这里使用它,那么您就不需要解决这些难题。 - jfriend00
1
我现在没有精力去尝试跟随EMCASCript规范中复杂的语法网络,但正是MakeMethod()调用设置了[[HomeObject]],然后允许使用super。您必须跟随语法定义链才能找出确切的语法是什么,哪些语法会导致调用或不调用MakeMethod()。MDN不是文档来源 - EMCAScript规范是来源。 - jfriend00
1
看起来它在这里:https://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer。只有快捷语法是[MethodDefinition](https://www.ecma-international.org/ecma-262/6.0/#sec-method-definitions)(具有超级功能)。常规属性语法只是一个属性,不是Javascript定义和初始化所谓的“方法”的方式。 - jfriend00
显示剩余3条评论
2个回答

10
首先,MDN不是官方的JavaScript文档。虽然它通常很有帮助,但它不是与语言相关的任何事情的权威来源。官方规范应该在ECMAScript specification中。那里定义了JavaScript语法。
在那个文档中,有一个叫做MethodDefinition的东西。有几种语法可以用于方法定义。 greeting() {}语法就是一种可用于MethodDefinition的语法。典型的对象字面量属性定义propName: function() {}则不是。这是它的定义方式:

enter image description here

然后,要了解什么是MethodDefinition,您可以转到第14.3.8节,其中记录了MethodDefinition的步骤如下:

enter image description here

在第七步,它调用 MakeMethod()。如果你前往规范的那个部分,你会看到那里设置了 [[HomeObject]] 的值。

enter image description here

所以,正如您已经发现的那样,super 依赖于设置 [[HomeObject]],并且查阅规范,这是唯一设置它的方法。因此,为了允许使用 super,它必须调用 MakeMethod(),而 MakeMethod() 被调用的唯一方式是使用上述语法之一和常规对象字面量语法来设置属性,例如 propName: fn 不在其中。

如果函数声明不像方法一样,而是像属性一样具有值函数,则对我来说非常有趣。哪个部分在规范中解释了这个过程? - Murad Sofiyev
@MuradSofiyev - 我不明白你的意思。 - jfriend00

0

[[HomeObject]]属性在类和普通对象的方法中定义。但对于对象,方法必须声明为method(),而不是“method:function()”。

对于我们来说没有区别,但对JavaScript来说是有区别的。

下面的示例使用非方法、属性函数语法。因此,它没有[[HomeObject]],继承不起作用:

 let animal = {
  eat: function(){ 
    console.log(this)
  }
};

let rabbit = {
  __proto__: animal,
  eat: function() {
    super.eat();
  }
};

rabbit.eat(); 

// 调用超类时出错(因为没有[[HomeObject]])

如上所述

[[HomeObject]]值在MakeMethod()方法中设置,只对符合该方法角色的函数可用,即声明为:

PropertyName ( StrictFormalParameters ) { FunctionBody } 规范的那部分


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接