我想尝试手动走几个对象的原型链,只是为了看看我在路上找到了什么。但是,我遇到了我尝试过的第一个问题。这是代码:
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的原型是什么。显然,它不是Function类型的对象,如输出的第3行所示,它告诉我我错了。第四行输出只是增强了第一行的输出。
更一般地说,我认为走一个对象的原型链的正确方法是从有问题的对象到它的构造函数,然后从构造函数到构造函数的原型,假设最后一个引用不为空。我假设应该重复这个两步过程(包括转到构造函数,然后转到构造函数的原型),直到从构造函数到原型的null引用,从而表示原型链的结束。但是,这似乎不起作用,因为将此算法应用于上述场景只会导致循环引用。
总之,我有两个问题:
修改
我在StackOverflow here上遇到了类似的问题,但它没有明确地询问走原型链的正确方法。它确实指出了循环引用,但是......
答案 0 :(得分:3)
在Javascript术语中,对象a
""原型"是指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
属性中。
-
函数在很多方面表现得像对象(例如,它们可以具有属性),但它们与其他对象完全不同:
console.log(typeof a); // "object"
console.log(typeof F); // "function"
他们的"原型"是不明确的(例如在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:
返回对创建实例原型的Object函数的引用。
此外,您可以更改对象上constructor
的值,但这不会影响对象的内容或行为方式 - 它只是描述性的。
-
所以,回答你的问题:
为什么x.constructor === x.constructor.prototype.constructor
没有充分的理由。这是浏览器融合的任意行为。
无论如何,x.constructor.prototype是什么类型的对象
在此示例中,t x
的原型与Object.getPrototypeOf(x)
相同。但一般来说,你不能依赖x.constructor
或从中衍生的任何东西,因为它是任意的。
如何纠正上述算法以便正确地遍历对象x的原型链?
for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) {
// do something with p
}
答案 1 :(得分:1)
是的,起初可能有点难以掌握。我不能为你提供一些链接。当我遇到麻烦时,这些总能帮助我。
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
http://mckoss.com/jscript/object.htm
http://zeekat.nl/articles/constructors-considered-mildly-confusing.html
Q1:对于"为什么"见上面的参考文献。 x.constructor.prototype
x.__proto__
是内部"真实的&#34}。 x的原型,至少在没有prototype
和constructor
属性被覆盖的情况下。它是在您定义MyObject函数时创建的。
__proto__
属性,但请参阅
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto