This article defines instanceof as below:
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.
That's a fair explanation and life was good until I came across this code from the book 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;
};
Let's create an instance of RTextCell and execute the below c
var rt = new RTextCell("ABC");
console.log(rt instanceof RTextCell); // true
console.log(rt instanceof TextCell); // true
I understand why the output of the 2nd console.log is "true" - because constructor TextCell is part of the prototype chain.
However the 1st console.log confuses me.
If you look at the code (10th line from bottom), the prototype of RTextCell is updated to a new Object, whose prototype is set to TextCell.prototype.
RTextCell.prototype = Object.create(TextCell.prototype);
.
Looking at the snapshots below, there is no mention of constructor "RTextCell" in the prototype chain of the object "rt". So, going by the definition which I mentioned at the beginning of my post, shouldn't the output be false? Why does it returns a true value?
I also read this but didn't help me to understand this specific problem.
See below for the snapshots of rt, RTextCell, TextCell in that order.
You do change RTextCell.prototype
, but you change it before you construct any RTextCell
instances. Consider this massively different example, where RTextCell.prototype
is modified after an instance is created with the original prototype:
var rt = new RTextCell();
RTextCell.prototype = somethingTotallyDifferent;
rt instanceof RTextCell; // false!
When rt
is created, it is true that rt.__proto__ === RTextCell.prototype
. Once RTextCell.prototype
changes, that stops being true.
You're not testing if rt
has the original prototype
property from RTextCell
in its prototype chain. Rather, you're testing if the value of RTextCell.prototype
right now exists in the object's prototype chain. That will always be true for RTextCell
instances, because instances created by the RTextCell
constructor always get the current value of RTextCell.prototype
in their prototype chain, and you never change RTextCell.prototype
after you start constructing instances.
The exact wording is important. You talk about the constructor being in the prototype chain, but the original quote doesn't:
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.
So the expression rt instanceof RTextCell
actually is testing something like this (keeping in mind that __proto__
is not standard):
var p = rt.__proto__;
while(p)
{
if(p == RTextCell.prototype)
return true;
p = p.__proto__;
}
return false;
So even though the function RTextCell
is not referenced directly in the object trees above, the RTextCell.prototype
object is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With