关于JavaScript中继承的难题

时间:2015-12-27 08:38:42

标签: javascript inheritance prototype

我知道JavaScript中继承的概念是通过原型链,但我不确定我是否正确理解。当读取属性时,引擎将首先搜索实例自己的属性,如果未找到则将搜索实例的[[Prototype]]属性,该属性是对创建实例的函数原型的引用,搜索将继续进行,直到达到Object.prototype。对于以下代码:

var person1 = {
    name: "Qiushi",
    sayName: function() {
        console.log(this.name);
    }
};

person1.sayName();  // Qiushi

var person2 = Object.create(person1);
person2.name = "Alex";
console.log(person2.hasOwnProperty("sayName")); // false
person2.sayName();  // Alex

当person2继承自person1时,person2可以使用person1中定义的方法。但是 sayName 方法不是person1原型的属性,而是它只是它自己的属性。我的问题是,方法搜索是单独跟随原型链, person2 如何使用不在此链中的方法?

-------------------------------最终编辑-------------- -----------

如果您对此问题有同样的疑虑,请阅读我和Jimbo之间的对话。

2 个答案:

答案 0 :(得分:6)

作为其他对象原型的对象并没有什么特别之处,它们只是对象。

当引擎转到读取属性时,首先它会查看对象本身以查看它是否具有它,如果有,则使用它。如果它没有,它会查看对象的原型,然后查看原型等。

在您的代码中,person1person2的原型,因此在sayName上查找person2时,由于引擎在person2上找不到它{1}},它会查看person2的原型person1,并找到它。

这是您在代码中设置的简单的ASCII艺术图表:

                                  +-------------------+
person1-----------------------+-->|     (object)      |
                              |   +-------------------+
                              |   | __proto__         |-->(not shown, Object.prototype)
                              |   | name: "Qiushi"    |
                              |   | sayName: function |
                              |   +-------------------+
                              |
            +--------------+  |
person2---->|   (object)   |  |
            +--------------+  |
            | __proto__    |--+
            | name: "Alex" |
            +--------------+

这是一个更完整但尚未完全完整的版本:

          +------------+                                  
Object--->| (function) |  +->(not shown, Function.prototype)                              
          +------------+  |                                 
          | __proto__  |--+                                  +--------------------+
          | prototype  |---------------------------------+-->|      (object)      |
          +------------+                                 |   +--------------------+
                                  +-------------------+  |   |   __proto__: null  |
person1-----------------------+-->|     (object)      |  |   | toString: function |
                              |   +-------------------+  |   | valueOf: function  |
                              |   | __proto__         |--+   | ...                |
                              |   | name: "Qiushi"    |      +--------------------+
                              |   | sayName: function |   
                              |   +-------------------+   
                              |                           
            +--------------+  |
person2---->|   (object)   |  |
            +--------------+  |
            | __proto__    |--+
            | name: "Alex" |
            +--------------+

答案 1 :(得分:1)

Object.create返回一个新对象,其中提供的参数 是新对象的原型对象。

所以你现在得到了这个:

{person2}
    - name:'Alex'
    - {prototype}
        - name:'Quishi'
        - sayName:function

因此,如果您在person2上查找属性name,它将在person2上找到该属性,而不是查看原型。如果您查找sayName,它将无法在person2上找到它,因此它将查看原型并在那里找到它。

函数中引用的this关键字取决于函数调用FROM的位置。这就是this的工作原理。当您在对象上调用方法时,该对象将是该方法中的this。因此,即使该方法在原型上,如果您调用thisperson2.sayName();仍将引用person2。如果您要更改(例如通过.call),您可以更改输出。

console.log(person2.name); // -> Alex

person2.sayName(); // -> Alex
person2.sayName.call(person2.__proto__); // -> Quishi, even though called on person2

person1.sayName(); // -> Quishi
person1.sayName.call(person2); // -> Alex, even though called on person1

我指出这一点是因为在这个例子中误解this的可能性与误解原型一样多。