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

问题描述

为什么在 JavaScript 中 Object instanceof FunctionFunction 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 的计算方式如下:

  1. lref 成为对 RelationalExpression 求值的结果.
  2. lvalGetValue(lref).
  3. rref 成为对 ShiftExpression 求值的结果.
  4. rvalGetValue(rref).
  5. 如果 Type(rval) 不是 Object,则抛出 TypeError 异常.
  6. 如果 rval 没有 [[HasInstance]] 内部方法,则抛出 TypeError 异常.
  7. 返回调用带有参数lvalrval[[HasInstance]]内部方法的结果.
  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.

首先对左侧和右侧的表达式求值 (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:

  1. 如果 V 不是对象,则返回 false.
  2. O 成为使用属性名称 "prototype" 调用 F[[Get]] 内部方法的结果.
  3. 如果 Type(O) 不是 Object,则抛出 TypeError 异常.
  4. 重复
  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. V 成为 V[[Prototype]] 内部属性的值.
  2. 如果Vnull,返回false.
  3. 如果OV指向同一个对象,返回true.
  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.

就是这么简单.取Fprototype属性与O[[Prototype]]内部属性比较,直到它成为 nullFprototypeO 相同.

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,特定于 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"和“对象的函数实例"返回真?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-30 05:17