为什么原型链的执行方式不同?

时间:2016-10-31 18:18:11

标签: javascript prototype object-create prototype-chain

我正在尝试更多地了解Javascript并深入了解原型链。当我遇到这个问题时,我想为HTMLElement创建一个小扩展。

我理解Object.create的方式是传递给它的对象用于为新对象创建上下文,并且新创建的对象的原型链中的第一个链接将指向该对象传递给Object.create方法。既然如此,下面的bar方法中使用的扩展方法对我来说似乎是正确的方法,因为这个新创建的对象将被赋予其HTMLElement作为其上下文。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <span id="test"></span>

    <script>
      HTMLElement.prototype.foo = function() {
        let foo = Object.create(null);
        foo.parentElement = this;
        foo.parentElement.appendChild(document.createElement('div'));
      }

      HTMLElement.prototype.bar = function() {
        let fooRenderer = Object.create(this);
        fooRenderer.appendChild(document.createElement('div'));
      }

      document.getElementById('test').foo();
      document.getElementById('test').bar();
    </script>
</body>
</html>

但是,foo方法可以通过将新的div子元素附加到<span id="test"></span>来正常工作,但bar却没有。

当我在浏览器中打开开发人员工具并尝试跟踪调用appendChild的两个对象的原型链时,它们看起来几乎相同:

foo Object
    .parentElement <span#test2>
        .__proto__ HTMLSpanElementPrototype
            .__proto__ HTMLElementPrototype
                .__proto__ ElementPrototype
                    .__proto__ NodePrototype
                        .appendChild
                        .__proto__ EventTargetPrototype
                            .__proto__ Object
                                .__proto__
                                    get
                                    set

fooRenderer Object
    .__proto__ <span#test2>
        .__proto__ HTMLSpanElementPrototype
            .__proto__ HTMLElementPrototype
                .__proto__ ElementPrototype
                    .__proto__ NodePrototype
                        .appendChild
                        .__proto__ EventTargetPrototype
                            .__proto__ Object
                                .__proto__
                                    get
                                    set

我已使用此示例创建了jsFiddle

有人可以向我解释为什么bar无效吗? bar实际上是更正确的方法吗?如果是这样,应如何设置才能正常工作?

提前感谢您的帮助!!!

1 个答案:

答案 0 :(得分:0)

这两个例子都不“正确”。在原型方法中,您不应该尝试实例化已经附加到的对象的新副本。您需要做的就是:

HTMLElement.prototype.bar = function() {
    let div = document.createElement('div');
    div.innerHTML = 'fooRenderer';
    this.appendChild(div);
}

第一个示例仅起作用,因为foo.parentElement将是有效的本机HTMLElement,而不是自定义创建的对象。

请参阅this answer,了解为何无法在自定义对象上调用appendChild等“原生”浏览器方法。