为什么在 JavaScript 中既有“Object instanceof Function"和“对象的函数实例"返回真? [英] Why in JavaScript both "Object instanceof Function" and "Function instanceof Object" return true?
问题描述
为什么在 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
属性.
The
instanceof
operator tests whether an object has in its prototype chain theprototype
property of a constructor.
[instanceof]
现在,让我们看看 ECMA 5.1 规范如何定义 instanceof
,
产生式RelationalExpression: RelationalExpression instanceof ShiftExpression
的计算方式如下:
The production
RelationalExpression: RelationalExpression instanceof ShiftExpression
is evaluated as follows:
- 让
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 对象.
Assume
F
is a Function object.
当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]]
内部属性最终必须导致 <代码>空代码>值).
All objects have an internal property called
[[Prototype]]
. The value of this property is eithernull
or an object and is used for implementing inheritance. Whether or not a native object can have a host object as its[[Prototype]]
depends on the implementation. Every[[Prototype]]
chain must have finite length (that is, starting from any object, recursively accessing the[[Prototype]]
internal property must eventually lead to anull
value).
注意:我们可以通过Object.getPrototypeOf<获取这个内部属性/code>
函数.
[[HasInstance]]
还谈到了另一个名为 prototype的属性code>
,特定于 Function
对象.
[[HasInstance]]
also talks about another property called prototype
, which is specific to the Function
objects.
prototype
属性的值用于在将 Function 对象作为构造函数调用之前初始化新创建对象的 [[Prototype]]
内部属性那个新创建的对象.
The value of the
prototype
property is used to initialise the[[Prototype]]
internal property of a newly created object before the Function object is invoked as a constructor for that newly created object.
这意味着,当一个函数对象用作构造函数时,将创建一个新对象,并且新对象的内部 [[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"和“对象的函数实例"返回真?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!