问题描述
为什么在 JavaScript 中 Object instanceof Function
和 Function instanceof Object
都返回 true
?
Why in JavaScript do both Object instanceof Function
and Function instanceof Object
return true
?
我在 Safari WebInspector 中尝试过.
I tried it in Safari WebInspector.
推荐答案
我花了一段时间才弄明白,但它确实值得花时间.首先,让我们看看 instanceof
是如何工作的.
It took a while for me to figure out but its really worth the time spent. First, let us see how instanceof
works.
引用自 MDN,
instanceof
运算符测试对象的原型链中是否具有构造函数的 prototype
属性.
[instanceof]
现在,让我们看看 ECMA 5.1 规范如何定义 instanceof
,
产生式RelationalExpression: RelationalExpression instanceof ShiftExpression
的计算方式如下:
- 让
lref
成为对RelationalExpression
求值的结果. - 设
lval
为GetValue(lref)
. - 让
rref
成为对ShiftExpression
求值的结果. - 设
rval
为GetValue(rref)
. - 如果
Type(rval)
不是 Object,则抛出TypeError
异常. - 如果
rval
没有[[HasInstance]]
内部方法,则抛出TypeError
异常. - 返回调用带有参数
lval
的rval
的[[HasInstance]]
内部方法的结果.
- Let
lref
be the result of evaluatingRelationalExpression
. - Let
lval
beGetValue(lref)
. - Let
rref
be the result of evaluatingShiftExpression
. - Let
rval
beGetValue(rref)
. - If
Type(rval)
is not Object, throw aTypeError
exception. - If
rval
does not have a[[HasInstance]]
internal method, throw aTypeError
exception. - Return the result of calling the
[[HasInstance]]
internal method ofrval
with argumentlval
.
首先对左侧和右侧的表达式求值 (GetValue
),然后右侧的结果应该是一个带有 [[HasInstance]]
内部方法的对象.不是所有的对象都有 [[HasInstance]]
内部方法,而是函数.例如,以下将失败
First the left and right hand side expressions are evaluated (GetValue
) and then right hand side result should be an Object with [[HasInstance]]
internal method. Not all objects will have [[HasInstance]]
internal method, but functions. For example, the following will fail
console.log(Object instanceof {});
# TypeError: Expecting a function in instanceof check, but got #<Object>
[[HasInstance]]
现在,让我们看看 [[HasInstance]]
在 ECMA 5.1 规范中定义,
[[HasInstance]]
Now, let us see how [[HasInstance]]
has been defined in the ECMA 5.1 specification,
假设 F
是一个 Function 对象.
当F
的[[HasInstance]]
内部方法以V
值被调用时,执行如下步骤:
When the [[HasInstance]]
internal method of F
is called with value V
, the following steps are taken:
- 如果
V
不是对象,则返回false
. - 让
O
成为使用属性名称"prototype" 调用
.F
的[[Get]]
内部方法的结果 - 如果
Type(O)
不是 Object,则抛出TypeError
异常. - 重复
- If
V
is not an object, returnfalse
. - Let
O
be the result of calling the[[Get]]
internal method ofF
with property name"prototype"
. - If
Type(O)
is not Object, throw aTypeError
exception. - Repeat
- 让
V
成为V
的[[Prototype]]
内部属性的值. - 如果
V
为null
,返回false
. - 如果
O
和V
指向同一个对象,返回true
.
- Let
V
be the value of the[[Prototype]]
internal property ofV
. - If
V
isnull
, returnfalse
. - If
O
andV
refer to the same object, returntrue
.
就是这么简单.取F
的prototype
属性与O
的[[Prototype]]
内部属性比较,直到它成为 null
或 F
的 prototype
与 O
相同.
It is so simple. Take the prototype
property of F
and compare it with the [[Prototype]]
internal property of O
until it becomes null
or prototype
of F
is the same as O
.
首先让我们看看什么是[[prototype]]
内部属性,
First let us see what is the [[prototype]]
internal property,
所有对象都有一个名为 [[Prototype]]
的内部属性.该属性的值为null
或一个对象,用于实现继承.本机对象是否可以将宿主对象作为其[[Prototype]]
取决于实现.每个 [[Prototype]]
链都必须有有限长度(即从任何对象开始,递归访问 [[Prototype]]
内部属性最终必须导致 值).
注意:我们可以通过Object.getPrototypeOf
函数.
[[HasInstance]]
还谈到了另一个名为 prototype的属性code>
,特定于 Function
对象.
[[HasInstance]]
also talks about another property called prototype
, which is specific to the Function
objects.
prototype
属性的值用于在将 Function 对象作为构造函数调用之前初始化新创建对象的 [[Prototype]]
内部属性那个新创建的对象.
这意味着,当一个函数对象用作构造函数时,将创建一个新对象,并且新对象的内部 [[Prototype]]
将使用此 prototype 进行初始化
属性.例如,
This means that, when a function object is used as a constructor, a new object will be created and the new object will have its internal [[Prototype]]
initialized with this prototype
property. For example,
function Test() {}
Test.prototype.print = console.log;
console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
# true
实际问题
现在让我们回到实际问题.先说第一种情况
Actual problem
Now let us get back to the actual question. Lets take the first case
console.log(Object instanceof Function);
# true
它将首先获取Function.prototype
,并尝试查找该对象是否在Object
的原型层次结构中.让我们看看结果如何
It will fetch Function.prototype
first and it will try and find if that object is in the prototype hierarchy of Object
. Let us see how that turns out
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代码>.
Since the Function.prototype
matches the Object
's internal property [[Prototype]]
, it returns true
.
现在我们来看第二种情况
Now lets take the second case
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
的直接父类是和 Empty 函数.
Here, first we get the Object.prototype
, which is {}
. Now it is trying to find if the same object {}
is there in the Function
's prototype chain. Immediate parent of Function
is and Empty function.
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
与Object.prototype
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
但是 [[HasInstance]]
算法并不止于此.它重复并上升一级
But the [[HasInstance]]
algorithm doesn't stop there. It repeats and gets up one more level
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
这与 Object.prototype
相同.这就是返回 true
的原因.
And this is the same as Object.prototype
. That is why this returns true
.
这篇关于为什么在 JavaScript 中既有“Object instanceof Function"和“对象的函数实例"返回真?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!