正式的 “方法” 定义

ES6 之前,“方法” 的概念从未被正式定义,它此前仅指对象的函数属性(而非数据属性)。ES6 则正式做出了定义:方法是一个拥有 [[HomeObject]] 内部属性的函数,此内部属性指向该方法所属的对象。研究以下例子:

let person = {

    // method
    getGreeting() {
        return "Hello";
    }
};

// not a method
function shareGreeting() {
    return "Hi!";
}

此例定义了拥有单个 getGreeting() 方法的 person 对象。由于 getGreeting() 被直接赋给了一个对象,它的 [[HomeObject]] 属性值就是 person 。而另一方面,shareGreeting() 函数没有被指定 [[HomeObject]] 属性,因为它在被创建时并没有赋给一个对象。大多数情况下,这种差异并不重要,然而使用 super 引用时就完全不同了。

任何对 super 的引用都会使用 [[HomeObject]] 属性来判断要做什么。第一步是在 [[HomeObject]] 上调用 Object.getPrototypeOf() 来获取对原型的引用;接下来,在该原型上查找同名函数;最后,创建 this 绑定并调用该方法。这里有个例子:

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

// prototype is person
let friend = {
    getGreeting() {
        return super.getGreeting() + ", hi!";
    }
};
Object.setPrototypeOf(friend, person);

console.log(friend.getGreeting());  // "Hello, hi!"

调用 friend.getGreeting() 返回了一个字符串,也就是 person.getGreeting() 的返回值与 ", hi!" 的合并结果。此时 friend.getGreeting()[[HomeObject]] 值是 friend,并且 friend 的原型是 person,因此 super.getGreeting() 就等价于 person.getGreeting.call(this)