为什么在JavaScript中,“Object instanceof Function”和“Function instanceof Object”返回true? [英] Why in JavaScript both "Object instanceof Function" and "Function instanceof Object" return true?

查看:142
本文介绍了为什么在JavaScript中,“Object instanceof Function”和“Function instanceof Object”返回true?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么在JavaScript中同时执行 Object instanceof Function 函数instanceof Object return true



我在Safari WebInspector中试了一下。

解决方案

我花了一段时间才弄清楚,但它真的值得花时间。首先,让我们看看 instanceof 是如何工作的。



MDN


instanceof 运算符测试对象是否在其原型链中包含原型 >

现在,让我们看看 instanceof 由ECMA 5.1规范定义,
$ b


生产 RelationalExpression: RelationalExpression instanceof ShiftExpression 的计算方法如下:


  1. lref 是评估 RelationalExpression 的结果。

  2. lval code> GetVa lue(lref)

  3. rref 成为评估 ShiftExpression的结果

  4. rval GetValue(rref) Type(rval)不是Object,则抛出 TypeError rval 没有 [[HasInstance]] c>内部方法,抛出 TypeError 异常。
  5. 返回调用 [[HasInstance] ] 内部方法 rval 带参数 lval


首先评估左右手表达式( GetValue )和那么右边的结果应该是一个带 [[HasInstance]] 内部方法的对象。不是所有的对象都有 [[HasInstance]] 内部方法,但是函数。例如,以下将失败

  console.log(Object instanceof {}); 
#TypeError:期望在instanceof check中有一个函数,但得到#< Object>



[[HasInstance]]



现在,让我们看看 [[HasInstance ]] 已在ECMA 5.1规范中定义


假设 F 是一个Function对象。



[[HasInstance]] internal方法 F 用值 V 调用,则采取以下步骤:


  1. 如果 V 不是对象,则返回 false

  2. O 成为调用 [[Get]] 内部结果方法 F ,属性名称prototype

  3. c $ c> Type(O)不是Object,抛出 TypeError 异常。
  4. 重复


    1. V [[Prototype]] V 的内部属性。

    2. 如果 V null ,返回 false

    3. 如果 O V 引用同一个对象,则返回 true <



它非常简单。取原型属性 F ,并将其与 [[Prototype]] O 的内部属性,直到它变成 null prototype F O 相同。



[[prototype]] 内部属性



首先让我们看看什么是 [[prototype]] 内部属性


所有对象都有一个名为 [[Prototype]] 的内部属性。该属性的值是 null 或一个对象,用于实现继承。本地对象是否可以将主对象作为其 [[Prototype]] 取决于实现。每个 [[Prototype]] 链必须具有有限长度(也就是说,从任何对象开始,递归地访问 [[Prototype]] 内部属性必须最终导致 null 值)。

注意:我们可以使用 Object.getPrototypeOf 功能。



原型属性



[[HasInstance]] 也会谈到另一个名为 prototype ,这是特定于 Function 对象的。


原型属性的值用于初始化 [[Prototype ]] 调用Function对象作为新创建对象的构造函数之前新创建对象的内部属性。

这意味着,当一个函数对象被用作构造函数时,将会创建一个新对象并且新对象将拥有它内部 [[Prototype]] 用这个 prototype 属性初始化。例如,

 函数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); 
#[功能:空]
console.log(Object.getPrototypeOf(Object));
#[功能:空]
console.log(Object.getPrototypeOf(Object)=== Function.prototype);
$ true

由于 Function.prototype 匹配 Object 的内部属性 [[Prototype]] ,它返回真正



现在让我们来看第二种情况

  console.log(Function instanceof Object); 
#true
console.log(Object.prototype);
#{}
console.log(Object.getPrototypeOf(Function));
#[功能:空]
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 的原型链中是否存在相同的对象 {} 函数的直接父项是和空函数。

  console.log Object.getPrototypeOf(功能)); 
#[功能:空]

它与 Object.prototype

  console.log(Object.getPrototypeOf(Function)=== Object。原型); 
#false

[[HasInstance]] 算法并不止于此。它重复并且获得了更多的级别。

  console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function))); 
#{}

这与 Object相同。原型。这就是为什么这会返回 true


Why in JavaScript do both Object instanceof Function and Function instanceof Object return true?

I tried it in Safari WebInspector.

解决方案

It took a while for me to figure out but its really worth the time spent. First, let us see how instanceof works.

Quoting from MDN,

The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

[instanceof]

Now, let us see how instanceof is defined by ECMA 5.1 Specification,

The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating ShiftExpression.
  4. Let rval be GetValue(rref).
  5. If Type(rval) is not Object, throw a TypeError exception.
  6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
  7. Return the result of calling the [[HasInstance]] internal method of rval with argument lval.

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]]

Now, let us see how [[HasInstance]] has been defined in the ECMA 5.1 specification,

Assume F is a Function object.

When the [[HasInstance]] internal method of F is called with value V, the following steps are taken:

  1. If V is not an object, return false.
  2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype".
  3. If Type(O) is not Object, throw a TypeError exception.
  4. Repeat

    1. Let V be the value of the [[Prototype]] internal property of V.
    2. If V is null, return false.
    3. If O and V refer to the same object, return true.

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]] internal property

First let us see what is the [[prototype]] internal property,

All objects have an internal property called [[Prototype]]. The value of this property is either null 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 a null value).

Note: We can get this internal property with the Object.getPrototypeOf function.

prototype property

[[HasInstance]] also talks about another property called prototype, which is specific to the Function objects.

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.

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

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

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

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]

It is not the same as Object.prototype

console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false

But the [[HasInstance]] algorithm doesn't stop there. It repeats and gets up one more level

console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}

And this is the same as Object.prototype. That is why this returns true.

这篇关于为什么在JavaScript中,“Object instanceof Function”和“Function instanceof Object”返回true?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆