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

Why is the prototype chain being executed differently?

本文关键字:方式不 执行 原型 为什么      更新时间:2023-09-26

我正在努力学习更多关于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方法通过向<span id="test"></span>添加一个新的div子元素而正常工作,但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实际上是更正确的方法吗?如果是,应该如何设置才能正常工作

提前感谢您的帮助!!!

这两个例子都不是"正确的"。在原型方法中,你不应该试图实例化你已经连接到的对象的新副本。你所需要做的就是:

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

第一个例子之所以有效,是因为foo.parentElement将是一个有效的本地HTMLElement,而不是一个自定义创建的对象。

关于为什么不能在自定义对象上调用appendChild之类的"本机"浏览器方法,请参阅以下答案。