原型链 - 在这种情况下使用原型链吗?

时间:2014-09-28 16:50:27

标签: javascript

我在frontendmasters.com跟随凯尔辛普森的YouDontKnowJS,并对他的一个例子感到困惑。

以下是示例代码:

function Foo(who){
    this.me = who;
}

Foo.prototype.identify = function() {
    return "I am " + this.me;
};

function Bar(who) {
    Foo.call(this, who);
}


Bar.prototype = Object.create(Foo.prototype);

Bar.prototype.speak = function() {
    alert("Hello, " + this.identify() + ".");
}

var b1 = new Bar("b1");
var b2 = new Bar("b2");

b1.speak();
b2.speak();

致电new Bar("b1")时;当你调用b1.speak()时,他会引导你了解原型链发生的事情

  • Bar.prototype调用alert函数时,也会调用this.identify()。
  • 当调用this.identify()时,在this对象(b1)上找不到它,所以它会查看它的原型。
  • 查看Bar.prototype它找不到识别方法,因此它再次查找原型链。
  • 现在找到Foo.prototype
  • 上的识别方法

这是我不清楚的。当我们致电Bar.prototype = Object.create(Foo.prototype)时,现在不应该Bar.prototype引用一个新对象,该对象是Foo.prototype的副本,其上会有identify()方法吗?为什么要在原型链中又向Foo.prototype添加一步才能找到identify()方法?

来自文档的Object.create()的官方定义:

  

Object.create()方法使用指定的原型对象和属性

创建一个新对象

2 个答案:

答案 0 :(得分:4)

  

当我们致电Bar.prototype = Object.create(Foo.prototype)时,不应该Bar.prototype引用一个新对象,该对象是Foo.prototype的副本...

Object.create没有复制对象。它创建了一个新对象,其底层原型是我们传入的。所以从这开始:

+---------------+
| Foo.prototype |
+---------------+     +----------------------+
| [[Prototype]] |---->|   Object.prototype   |
+---------------+     +----------------------+
| identify: ... |     | [[Prototype]]: null  |
+---------------+     +----------------------+
                      | ...                  |
                      +----------------------+

(为简单起见,我遗漏了identify的函数对象。)

......当我们Bar.prototype = Object.create(Foo.prototype)时,它会创建:

+---------------+
| Bar.prototype |
+---------------+     +---------------+
| [[Prototype]] |---->| Foo.prototype |
+---------------+     +---------------+     +----------------------+
                      | [[Prototype]] |---->|   Object.prototype   |
                      +---------------+     +----------------------+
                      | identify: ... |     | [[Prototype]]: null  |
                      +---------------+     +----------------------+
                                            | ...                  |
                                            +----------------------+

稍后,执行Bar.prototype.speak = function...行后,Bar.prototype也会拥有speak属性。

+---------------+
| Bar.prototype |
+---------------+     +---------------+
| [[Prototype]] |---->| Foo.prototype |
+---------------+     +---------------+     +----------------------+
| speak: ...    |     | [[Prototype]] |---->|   Object.prototype   |
+---------------+     +---------------+     +----------------------+
                      | identify: ... |     | [[Prototype]]: null  |
                      +---------------+     +----------------------+
                                            | ...                  |
                                            +----------------------+

var b1 = new Bar("b1");之后,我们有:

+---------------+
|      b1       |
+---------------+     +---------------+                                                   
| [[Prototype]] |---->| Bar.prototype |                                                   
+---------------+     +---------------+     +---------------+                             
| me: "b1"      |     | [[Prototype]] |---->| Foo.prototype |                             
+---------------+     +---------------+     +---------------+     +----------------------+
                      | speak: ...    |     | [[Prototype]] |---->|   Object.prototype   |
                      +---------------+     +---------------+     +----------------------+
                                            | identify: ... |     | [[Prototype]]: null  |
                                            +---------------+     +----------------------+
                                                                  | ...                  |
                                                                  +----------------------+

[在上文中,[[Prototype]]指的是对象与其原型的内置链接;名称为[[Prototype]]的对象上没有真正的属性。 实际上,在ES5中,没有办法从对象本身直接访问原型的链接,尽管ES5添加了Object.getPrototypeOf,它允许您通过传入对象引用来检索它,例如, var p = Object.getPrototypeOf(someObject)。 ES6将添加更多与对象原型交互的方式,包括Mozilla的JavaScript多年来拥有的__proto__属性。]

答案 1 :(得分:1)

&#34;当我们调用Bar.prototype = Object.create(Foo.prototype)时,不应该Bar.prototype引用一个新对象,它是Foo.prototype的副本。&#34; < / p>

Object.create不会创建对象的副本,但会创建对该对象的委派。所以你必须再向上一级Foo.prototype,因为那是Bar.prototype所委托的。