javascript - 难以手动走原型(prototype)链

标签 javascript constructor prototype

我想尝试手动遍历几个对象的原型(prototype)链,看看我在这个过程中找到了什么。但是,我卡在了我尝试的第一个上。这是代码:

function MyObject() { }
var x = new MyObject();
console.log('--------------------------------------------');
console.log('x.constructor.name: ' + x.constructor.name);
console.log('x.constructor.prototype.constructor.name: ' + x.constructor.prototype.constructor.name);
console.log(x.constructor.prototype === Function.prototype ? 'Good guess.' : 'No, you are wrong.');
console.log(x.constructor === MyObject ? 'Good guess.' : 'No, you are wrong.');
console.log('--------------------------------------------');

上述代码会在 Google Chrome 的开发者工具控制台中产生以下输出:

--------------------------------------------
x.constructor.name: MyObject
x.constructor.prototype.constructor.name: MyObject
No, you are wrong.
Good guess.
--------------------------------------------

x 的构造函数是 MyObject 函数是有道理的,因为 x 是使用 MyObject 上的 new 关键字实例化的(这遵循构造函数的定义)。因此,我理解了第一行输出(注意:我开始从零开始计算输出行数)。然而,第二行让我感到困惑。我想知道 MyObject 的原型(prototype)是什么。显然,它不是函数类型的对象,如输出的第 3 行所示,这告诉我我错了。第四行输出只是加强了第一行的输出。

更笼统地说,我假设遍历对象原型(prototype)链的正确方法是从所讨论的对象到它的构造函数,然后从构造函数到构造函数的原型(prototype),假设这是最后一个引用不为空。我假设应该重复这个两步过程(包括转到构造函数,然后转到构造函数的原型(prototype)),直到达到从构造函数到原型(prototype)的空引用,从而表示原型(prototype)链的结尾。不过,这似乎不起作用,因为将此算法应用于上述场景只会导致循环引用。

总结起来,我有两个问题:

  1. 为什么 x.constructor === x.constructor.prototype.constructor(或者,换句话说,为什么循环引用),以及 x.constructor.prototype 是一个什么样的对象,无论如何(或者,换句话说,话说,它是如何实例化的/它从哪里来的)?
  2. 如何修正上述算法才能正确遍历对象 x 的原型(prototype)链?

编辑

我在 StackOverflow 上遇到了类似的问题 here ,但它没有明确询问遍历原型(prototype)链的正确方法。它确实指出了循环引用,但是......

最佳答案

在 Javascript 术语中,对象 a 的“原型(prototype)”是指 a 从中继承属性的对象。访问它的基于标准的方法是使用 Object.getPrototypeOf:

var protoOfA = Object.getPrototypeOf(a);

还有一些旧方法,非标准但受某些浏览器支持:

var protoOfA = a.__proto__;

但是如果你有一个函数 F,F.prototype 不会引用 F 从中继承任何东西的对象。相反,它指的是 F 创建的实例 继承自的对象:

function F() {};
a = new F();
console.log(Object.getPrototypeOf(a) === F.prototype); // true

当您定义一个函数时,会创建一个对象作为该函数创建的实例的原型(prototype),并且这个新对象存储在该函数的 prototype 属性中。

--

函数在很多方面表现得像对象(例如,它们可以具有属性)但它们与其他对象并不完全相同:

console.log(typeof a); // "object"
console.log(typeof F); // "function"

他们的“原型(prototype)”定义不明确(示例在 Chrome 中运行)(这显然是 Chrome-specific behavior )

console.log(Object.getPrototypeOf(F)); // "function Empty() {}"
console.log(Empty);                    // ReferenceError: Empty is not defined

--

constructor 属性很奇怪。 The interpreter doesn't care about it . MDN says, confusingly :

Returns a reference to the Object function that created the instance's prototype.

此外,您可以更改对象上 constructor 的值,但这对对象是什么或它的行为方式没有影响 - 它只是描述性的。

--

所以,回答你的问题:

Why is x.constructor === x.constructor.prototype.constructor

没有充分的理由。这是浏览器收敛的任意行为。

what kind of an object is x.constructor.prototype, anyway

在这个例子中,t 是x 的原型(prototype),与Object.getPrototypeOf(x) 相同。但一般来说,您不能依赖 x.constructor 或任何派生自它的东西,因为它是任意的。

How can the above algorithm be corrected in order to correctly walk the prototype chain for object x?

for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) {
  // do something with p
}

关于javascript - 难以手动走原型(prototype)链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29975939/

相关文章:

javascript - 从模板调用时不会注入(inject) EmberJS 第二级服务

javascript - 通过点击而不是悬停的 jQuery 导航大型菜单

javascript - 如何在 JavaScript 中创建带有 lang 属性的 HTML 元素?

javascript - 将 Stripe JS 集成到 Laravel 6.0 : [Vue warn]: Error compiling template:

c++ - 通过两个隐式构造函数构造一个值?

C++基本构造函数问题

c# - 构造函数初始化期间出现问题-下一步是什么?

javascript - 范围 javascript - 字符串和数组/对象时不同

javascript - 向函数添加属性并设置其原型(prototype)

javascript - 如何更改 "animal"的原型(prototype)并添加方法 "sayName"到打印语句