为什么在JavaScript中,“Object instanceof Function”和“Function instanceof Object”都返回true?
为什么在JavaScript中, Object instanceof Function
和Function instanceof Object
返回true
?
我在Safari WebInspector中试了一下。
我花了一段时间才弄清楚,但真正值得花费的时间。 首先,让我们看看instanceof
是如何工作的。
从MDN引用,
instanceof
运算符testing对象是否在其原型链中具有构造函数的prototype
属性。
[instanceof]
现在,让我们看看ECMA 5.1规范定义了instanceof
,
生产
RelationalExpression: RelationalExpression instanceof ShiftExpression
的计算方法如下:
- 让
lref
是评估RelationalExpression
的结果。- 让
lval
成为GetValue(lref)
。- 让
rref
是评估ShiftExpression
的结果。- 让
rval
是GetValue(rref)
。- 如果
Type(rval)
不是Object,则抛出一个TypeError
exception。- 如果
rval
没有[[HasInstance]]
内部方法,则抛出一个TypeError
exception。- 返回用参数
lval
调用rval
的[[HasInstance]]
内部方法的lval
。
首先评估左侧和右侧expression式( GetValue
),然后右侧结果应该是带有[[HasInstance]]
内部方法的对象。 不是所有的对象都有[[HasInstance]]
内部方法,但有函数。 例如,以下将失败
console.log(Object instanceof {}); # TypeError: Expecting a function in instanceof check, but got #<Object>
[[HasInstance]]
现在,让我们看看ECMA 5.1规范中[[HasInstance]]
是如何定义的,
假设
F
是一个函数对象。当
F
的[[HasInstance]]
内部方法被调用值V
,采取以下步骤:
- 如果
V
不是一个对象,则返回false
。- 设
O
是调用属性名称为"prototype"
的F
的[[Get]]
内部方法的结果。- 如果
Type(O)
不是Object,则抛出一个TypeError
exception。- 重复
- 设
V
是V
的[[Prototype]]
内部属性的值。- 如果
V
为null
,则返回false
。- 如果
O
和V
引用同一个对象,则返回true
。
这是如此简单。 取F
的prototype
属性,并将其与O
的[[Prototype]]
内部属性进行比较,直到它变为null
或者F
prototype
与O
相同。
[[prototype]]
内部属性
首先让我们看看[[prototype]]
内部属性是什么 ,
所有对象都有一个名为
[[Prototype]]
的内部属性。 该属性的值是null
或一个对象,用于实现inheritance。 本地对象是否可以将主对象作为其[[Prototype]]
取决于实现。 每个[[Prototype]]
链的长度必须是有限的(也就是说,从任何对象开始,recursion访问[[Prototype]]
内部属性最终必须导致null
值)。
注意:我们可以通过Object.getPrototypeOf
函数获得这个内部属性。
prototype
属性
[[HasInstance]]
也谈到另一个称为prototype
属性,它是Function
对象的特定属性。
在调用Function对象作为新创build对象的构造函数之前,
prototype
属性的值用于初始化新创build对象的[[Prototype]]
内部属性。
这意味着,当一个函数对象被用作构造函数时,将会创build一个新的对象,并且这个新对象将使用这个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
即时父母是和空function。
console.log(Object.getPrototypeOf(Function)); # [Function: Empty]
它与Object.prototype
不一样
console.log(Object.getPrototypeOf(Function) === Object.prototype); # false
但是[[HasInstance]]
algorithm并不止于此。 它重复和起来了一个更高的水平
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function))); # {}
这和Object.prototype
是一样的。 这就是为什么这返回true
。
来自MDN :
instanceof运算符testing对象是否在其原型链中具有构造函数的原型属性。
本质上,它检查Object
(不是Object
一个实例,而是构造函数本身)是否作为Function.constructor
一个实例在原型链的某处。
而且的确如此:
> Function.__proto__.__proto__ === Object.prototype true > Object.__proto__ === Function.prototype true
这就解释了为什么Object instanceof Function
也是相反的。
在你的问题混乱的根源在于JavaScript(ECMAScript)中函数的固有的双重性质。
js中的函数同时是常规函数和对象。 把他们看作算法博士杰基尔和海德先生 。 他们看起来像外面的东西,但在里面,他们只是你的老jsfunction与所有的怪癖,或者也许是相反的方式!
JavaScript真的是一个棘手的业务:)
所以回到你的问题,借用在MDN上出现的语法:
object instanceof constructor
将其应用于代码中的第一条语句上:
Object instanceof Function
这里有Object
,一个用作对象初始值设定项的构造函数,但是由于函数在js中引入了双重生命,所以它具有特定于对象的道具和方法,使得它有效地成为一个对象。
因此,声明中的第一个条件已经得到满足。 我们仍然在调查其他条件或操作数。
你可能已经注意到的函数也是函数的构造函数,但是在执行这个特定的语句的时候,它的另一个对象是我们现在不感兴趣的。
因此,句法条件既是“对象”又是“构造者”。 我们现在可以继续调查它们的世袭关系,以及它们之间是否有联系。
因为Object
本身就是一个工作函数,所以假设它具有指向Function.prototype
对象引用的内部原型道具是很有意义的,因为在js中, 所有函数都通过同一个位置Function.prototype
inheritance它们的道具和方法。
true
是绝对algorithm运算符执行此比较的唯一预期结果。
对于其他情况:
Function instanceof Object
既然我们已经确定js中的函数对他们也有一个客观的一面。 从Object.prototype
得到他们喜欢的对象特定的玩具是Object.prototype
,因此它们构成了Object构造函数的实例 。
希望我没有添加与我的解释和寓言混淆。 🙂
*: 不仅是导致js中双重生活的function。 js中的几乎所有的数据types都有一个对象的黑暗面,以方便完成操作和操作而没有任何麻烦。
最坏的财产实际上是function本身的一个实例。 Function instanceof Function
返回true。
在Kannan的“令人惊讶的优雅的Javascripttypes模型”中可以很好地解释, http: //web.archive.org/web/20140205182624/http://vijayan.ca/blog/2012/02/21/javascript-type-model
在解释结尾引用:
是的,这意味着Function是其自身的一个实例(自然,因为它是一个函数,因此也是函数的一个实例)。 这是我们已经有意或无意地处理了很长一段时间 – 所有的构造函数都是规则的函数,因此函数的实例,而函数本身只是构造其他函数的构造函数,所以它也是函数的一个实例。
所有对象都有一个名为[[Prototype]]的内部属性。 该属性的值是null或一个对象,用于实现inheritance。 如果您尝试查找对象上的某个键,但未find该键,则JavaScript将在原型链中查找该键。
Function构造函数创build新的Function对象(Function构造函数的实例)。 原型属性是特定于Function对象的。 Function构造函数本身就是一个Function对象(Function构造函数的实例)。
当一个Function对象被用作构造函数时,将会创build一个新的对象,并且新的对象将使用构造函数的prototype属性初始化其[[Prototype]]。
function Dog () {} var myCrazyDog = new Dog(); myCrazyDog.__proto__ === Dog.prototype // true
语言规范是所有对象都是Object构造函数的实例,所有函数都是Function构造函数的实例。
Object instanceof Function是true,因为Object是一个函数,因此是Function(Object是Function对象 – Function构造函数的一个实例)的一个实例。 对象从Function.prototypeinheritance。
console.log(Object instanceof Function) // true console.log(Object.__proto__ === Function.prototype) // true
Object instanceof Object是true,因为Objectinheritance自Function.prototype。 由于Function.prototype是一个对象,它inheritance自Object.prototype。 Object的函数实例是真的,因为Function从Function.prototypeinheritance。 由于Function.prototype是一个对象,它inheritance自Object.prototype。 原型链看起来像这样:
Object ---> Function.prototype ---> Object.prototype ---> null Function ---> Function.prototype ---> Object.prototype ---> null console.log(Object instanceof Object) // true console.log(Object.__proto__ === Function.prototype) // true console.log(Object.__proto__.__proto__ === Object.prototype) // true console.log(Function instanceof Object) // true console.log(Function.__proto__ === Function.prototype) // true console.log(Function.__proto__.__proto__ === Object.prototype) // true
函数instanceof Function是true 。 函数本身就是一个实例(自然,因为它是一个函数,因此也是函数的一个实例)。 原型链看起来像这样:
Function ---> Function.prototype ---> Object.prototype ---> null console.log(Function instanceof Function) // true console.log(Function.__proto__ === Function.prototype) // true console.log(Function.__proto__.__proto__ === Object.prototype) // true
因此请记住Function()和Object()构造函数是函数。 由于它们是函数,因此它们是Function()构造函数的实例,并从Function.prototypeinheritance。 由于Function.prototype是一个对象,因此Function.prototype是Object的一个实例,因此inheritance自Object.prototype。
console.log(Object instance of Function) // true console.log(Function instance of Function) // true console.log(Function.prototype instanceof Object); // true