Javascript:仍然被instanceof运算符搞糊涂了

时间:2015-05-22 11:50:01

标签: javascript inheritance instanceof

article定义instanceof,如下所示:

  

instanceof运算符测试对象是否在其原型中   链接构造函数的prototype属性。

这是一个公平的解释和生活是好的,直到我从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;
};
&#13;
&#13;
&#13;

让我们创建一个RTextCell实例并执行以下c

var rt = new RTextCell("ABC");
console.log(rt instanceof RTextCell); // true
console.log(rt instanceof TextCell); // true

我理解为什么第二个console.log的输出是&#34; true&#34; - 因为构造函数TextCell是原型链的一部分。

然而,第一个console.log让我感到困惑。

如果查看代码(从下面开始的第10行),RTextCell的原型将更新为新的Object,其原型设置为TextCell.prototype。

RTextCell.prototype = Object.create(TextCell.prototype);

查看下面的快照,没有提到构造函数&#34; RTextCell&#34;在对象&#34; rt&#34;的原型链中。那么,按照我在帖子开头提到的定义,输出是否应该是假的?为什么它会返回真值?

我还阅读了this,但没有帮助我理解这个具体问题。

请按顺序查看rt,RTextCell,TextCell的快照。

snapshot of "rt" snapshot of RTextCell snapshot of TextCell

3 个答案:

答案 0 :(得分:4)

您确实更改了RTextCell.prototype,但在构建任何RTextCell实例之前更改了。考虑这个大不相同的示例,其中在使用原始原型创建实例后修改RTextCell.prototype

var rt = new RTextCell();
RTextCell.prototype = somethingTotallyDifferent;
rt instanceof RTextCell; // false!

创建rt时,rt.__proto__ === RTextCell.prototype为真。一旦RTextCell.prototype发生变化,就会停止变为真。

如果rt的原型链中的prototype具有原始 RTextCell属性,则您不会进行测试。相反,您正在测试对象的原型链中是否存在RTextCell.prototype 的值 。对RTextCell个实例始终如此,因为RTextCell构造函数创建的实例始终在其原型链中获取当前值RTextCell.prototype,并且您永远不会更改RTextCell.prototype你开始构建实例。

答案 1 :(得分:1)

wait

正在测试RTextCell.prototype是否存在于obj的原型链中。因为obj是使用新的RTextCell制作的。 RTextCell.prototype具有原型TextCell.prototype的事实就在这里,并且似乎在抛弃你。

obj instanceof RTextCell

没有摆脱RTextCell.prototype,它仍然是一个对象,但它的原型恰好是TextCell.prototype。

答案 2 :(得分:1)

确切的措辞很重要。你谈到原型链中的构造函数,但原始引用并没有:

  

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对象也是。