Javascript:仍然对 instanceof 运算符感到困惑
Posted
技术标签:
【中文标题】Javascript:仍然对 instanceof 运算符感到困惑【英文标题】:Javascript: Still confused by the instanceof operator 【发布时间】:2015-08-04 10:22:07 【问题描述】:article 定义 instanceof 如下:
instanceof 操作符测试一个对象是否在其原型中 链接构造函数的原型属性。
这是一个公平的解释,生活很美好,直到我从 Eloquent javascript 一书中看到这段代码:
function TextCell(text)
this.text = text.split("\n");
TextCell.prototype.minWidth = function()
return this.text.reduce(function(width, line)
return Math.max(width, line.length);
, 0);
TextCell.prototype.minHeight = function()
return this.text.length;
TextCell.prototype.draw = function(width, height)
var result = [];
for (var i = 0; i < height; i++)
var line = this.text[i] || "";
result.push(line + repeat(" ", width - line.length));
return result;
function RTextCell(text)
TextCell.call(this, text);
RTextCell.prototype = Object.create(TextCell.prototype);
RTextCell.prototype.draw = function(width, height)
var result = [];
for (var i = 0; i < height; i++)
var line = this.text[i] || "";
result.push(repeat(" ", width - line.length) + line);
return result;
;
让我们创建一个 RTextCell 的实例并执行下面的 c
var rt = new RTextCell("ABC");
console.log(rt instanceof RTextCell); // true
console.log(rt instanceof TextCell); // true
我理解为什么第二个 console.log 的输出是“真”——因为构造函数 TextCell 是原型链的一部分。
但是第一个 console.log 让我感到困惑。
如果看代码(倒数第 10 行),RTextCell 的原型被更新为一个新的 Object,其原型设置为 TextCell.prototype。
RTextCell.prototype = Object.create(TextCell.prototype);
.
看下面的快照,对象“rt”的原型链中没有提到构造函数“RTextCell”。那么,按照我在文章开头提到的定义,输出不应该是假的吗?为什么会返回真值?
我也阅读了this,但没有帮助我理解这个具体问题。
rt、RTextCell、TextCell 的快照按顺序见下文。
【问题讨论】:
这是一个结构很好的问题。您展示了您之前的所有调查,希望您得到很好的答案。 哦!我应该补充。我在 chrome 43.0.2357.65 和 firefox 33.1.1 上的上述快照中检查了这个原型链树。 【参考方案1】:obj instanceof RTextCell
正在测试 RTextCell.prototype 是否存在于 obj 的原型链中。这是因为 obj 是使用新的 RTextCell 制作的。 RTextCell.prototype 的原型是 TextCell.prototype 的事实在这里是无关紧要的,似乎让你失望了。
RTextCell.prototype = Object.create(TextCell.prototype);
没有去掉RTextCell.prototype,它仍然是一个对象,但它的原型恰好是TextCell.prototype。
【讨论】:
【参考方案2】:准确的措辞很重要。您说 构造函数 在原型链中,但原始引用没有:
instanceof 操作符测试一个对象是否在其原型中 链接构造函数的原型属性。
所以表达式 rt instanceof RTextCell
实际上是在测试类似的东西(请记住 __proto__
不是标准的):
var p = rt.__proto__;
while(p)
if(p == RTextCell.prototype)
return true;
p = p.__proto__;
return false;
因此,即使函数 RTextCell
没有在上面的对象树中直接引用,RTextCell.prototype
对象也是。
【讨论】:
或在单个表达式中,RTextCell.prototype.isPrototypeOf(rt)
:-)
@Dark Falcon:之前我对 instanceof 运算符和 isPrototypeOf() 感到困惑,当我在 MDN 网站上查看定义中的“构造函数”一词时,我完全误解了。你的回答让我停顿了一下,意识到我错过了什么。 “措辞”。现在它是有道理的。我也刚刚阅读了 [this].(***.com/questions/18343545/…) 以了解 instanceof 和 isPrototypeOf() 之间的区别。谢谢老兄。【参考方案3】:
您确实更改了RTextCell.prototype
,但您在构造任何RTextCell
实例之前更改了它。考虑这个完全不同的示例,其中 RTextCell.prototype
在使用原始原型创建实例后被修改:
var rt = new RTextCell();
RTextCell.prototype = somethingTotallyDifferent;
rt instanceof RTextCell; // false!
rt
创建时,rt.__proto__ === RTextCell.prototype
是真的。一旦RTextCell.prototype
发生变化,这就不再是真的了。
您不是在测试 rt
在其原型链中是否具有来自RTextCell
的原始 prototype
属性。相反,您正在测试 RTextCell.prototype
right now 的值是否存在于对象的原型链中。对于RTextCell
实例,这始终是正确的,因为RTextCell
构造函数创建的实例总是在其原型链中获得RTextCell.prototype
的当前值,并且在开始构造实例后您永远不会更改RTextCell.prototype
。
【讨论】:
除了@Dark Falcon 的回答之外,您将原型设置为“somethingTotallyDifferent”的示例对我有所帮助。这是有道理的。谢谢。以上是关于Javascript:仍然对 instanceof 运算符感到困惑的主要内容,如果未能解决你的问题,请参考以下文章
理解Javascript_07_理解instanceof实现原理
javascript typeof 和 instanceof 的区别和联系