我花了一段时间才弄清楚,但确实值得花时间。首先,让我们看看如何instanceof
works.
引用自MDN,
The instanceof
运算符测试对象的原型链中是否有prototype
构造函数的属性。
[instanceof]
现在,让我们看看如何instanceof由 ECMA 5.1 规范定义,
生产RelationalExpression: RelationalExpression instanceof ShiftExpression
评价如下:
- Let
lref
是评估的结果RelationalExpression
.
- Let
lval
be GetValue(lref)
.
- Let
rref
是评估的结果ShiftExpression
.
- Let
rval
be GetValue(rref)
.
- If
Type(rval)
不是对象,抛出一个TypeError
例外。
- If
rval
没有[[HasInstance]]
内部方法,抛出一个TypeError
例外。
- 返回调用结果
[[HasInstance]]
的内部方法rval
有论点lval
.
首先评估左侧和右侧表达式(GetValue
)然后右侧结果应该是一个对象[[HasInstance]]
内部方法。并不是所有的物体都会有[[HasInstance]]
内部方法,但是函数。例如,以下内容将失败
console.log(Object instanceof {});
# TypeError: Expecting a function in instanceof check, but got #<Object>
[[HasInstance]]
现在,让我们看看如何[[HasInstance]]已在 ECMA 5.1 规范中定义,
Assume F
是一个函数对象。
当。。。的时候[[HasInstance]]
的内部方法F
被调用时带有值V
,采取以下步骤:
- If
V
不是对象,返回false
.
- Let
O
是调用的结果[[Get]]
的内部方法F
带有属性名称"prototype"
.
- If
Type(O)
不是对象,抛出一个TypeError
例外。
- Repeat
- Let
V
的值是[[Prototype]]
的内部属性V
.
- If
V
is null
, 返回false
.
- If
O
and V
引用同一个对象,返回true
.
就是这么简单。采取prototype
的财产F
并将其与[[Prototype]]
的内部属性O
直到变成null
or prototype
of F
是相同的O
.
[[prototype]]
内部财产
首先让我们看看什么是[[prototype]]内部财产,
所有对象都有一个内部属性,称为[[Prototype]]
。该属性的值是null
或一个对象,用于实现继承。本机对象是否可以将宿主对象作为其对象[[Prototype]]
取决于实施。每一个[[Prototype]]
链必须具有有限长度(即从任何对象开始,递归访问[[Prototype]]
内部财产最终必须导致null
value).
Note:我们可以通过以下方式获得这个内部属性Object.getPrototypeOf功能。
prototype
财产
[[HasInstance]]
还谈到了另一个称为prototype,这是特定于Function
对象。
的价值prototype
属性用于初始化[[Prototype]]
在将 Function 对象作为新创建的对象的构造函数调用之前,该新创建的对象的内部属性。
这意味着,当函数对象用作构造函数时,将创建一个新对象,并且新对象将具有其内部[[Prototype]]
用这个初始化prototype
财产。例如,
function Test() {}
Test.prototype.print = console.log;
console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
# true
实际问题
现在让我们回到实际的问题。我们来看第一个案例
console.log(Object instanceof Function);
# true
它将获取Function.prototype
首先,它会尝试查找该对象是否在原型层次结构中Object
。让我们看看结果如何
console.log(Function.prototype);
# [Function: Empty]
console.log(Object.getPrototypeOf(Object));
# [Function: Empty]
console.log(Object.getPrototypeOf(Object) === Function.prototype);
# true
自从Function.prototype
匹配Object
的内部属性[[Prototype]]
,它返回true
.
现在我们来看第二种情况
console.log(Function instanceof Object);
# true
console.log(Object.prototype);
# {}
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
Object.getPrototypeOf(Object.getPrototypeOf(Function)) === Object.prototype
# true
在这里,首先我们得到Object.prototype
,即{}
。现在它正在尝试查找是否有相同的对象{}
有没有在Function
的原型链。的直系父辈Function
is 和 Empty 函数。
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
它不一样Object.prototype
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
But the [[HasInstance]]
算法并不止于此。它重复并上升一级
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
这与Object.prototype
。这就是为什么这会返回true
.