“为什么在JavaScript中同时使用这两种语言?”;“函数的对象实例”;及;“对象的函数实例”;返回真值?

“为什么在JavaScript中同时使用这两种语言?”;“函数的对象实例”;及;“对象的函数实例”;返回真值?,javascript,function,object,Javascript,Function,Object,为什么在JavaScript中,函数的对象实例和对象的函数实例都返回true 我在Safari WebInspector中试用过它。来自: instanceof操作符测试对象在其原型链中是否具有构造函数的prototype属性 function Dog () {} var myCrazyDog = new Dog(); myCrazyDog.__proto__ === Dog.prototype // true 本质上,它是检查对象(不是对象的实例,而是构造函数本身)是否作为函数的实例。构造函

为什么在JavaScript中,函数的
对象实例
和对象的
函数实例
都返回
true

我在Safari WebInspector中试用过它。

来自:

instanceof操作符测试对象在其原型链中是否具有构造函数的prototype属性

function Dog () {}
var myCrazyDog = new Dog();
myCrazyDog.__proto__ === Dog.prototype // true
本质上,它是检查
对象
(不是
对象
的实例,而是构造函数本身)是否作为
函数的实例。构造函数
位于其原型链的某个位置

事实上:

> Function.__proto__.__proto__ === Object.prototype
true
> Object.__proto__ === Function.prototype
true

这就解释了为什么函数的
对象实例以及相反的情况。

我花了一段时间才弄明白,但花的时间确实值得。首先,让我们看看
instanceof
是如何工作的

引用

instanceof
操作符测试对象的原型链中是否包含构造函数的
prototype
属性

function Dog () {}
var myCrazyDog = new Dog();
myCrazyDog.__proto__ === Dog.prototype // true
[instanceof]
现在,让我们看看ECMA 5.1规范是如何定义的

生产
RelationalExpression:shiftextexpression的RelationalExpression实例计算如下:

  • lref
    作为计算
    RelationalExpression
    的结果
  • lval
    be
    GetValue(lref)
  • rref
    作为计算
    ShiftExpression
    的结果
  • rval
    be
    GetValue(rref)
  • 如果
    Type(rval)
    不是对象,则抛出
    TypeError
    异常
  • 如果
    rval
    没有
    [[HasInstance]]
    内部方法,则抛出
    TypeError
    异常
  • 返回调用带有参数
    lval
    [[HasInstance]]]
    内部方法的结果
  • 首先计算左侧和右侧表达式(
    GetValue
    ),然后右侧结果应该是具有
    [[HasInstance]]]
    内部方法的对象。并非所有对象都有
    [[HasInstance]]
    内部方法,而是函数。例如,以下操作将失败

    console.log(Object instanceof {});
    # TypeError: Expecting a function in instanceof check, but got #<Object>
    
    实际问题 现在让我们回到实际问题上来。让我们看第一个案例

    console.log(Object instanceof Function);
    # true
    
    它将首先获取
    函数.prototype
    ,然后尝试查找该对象是否在
    对象的prototype层次结构中。让我们看看结果如何

    console.log(Function.prototype);
    # [Function: Empty]
    console.log(Object.getPrototypeOf(Object));
    # [Function: Empty]
    console.log(Object.getPrototypeOf(Object) === Function.prototype);
    # true
    
    由于
    函数.prototype
    匹配
    对象的内部属性
    [[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
    
    这里,首先我们得到
    对象.prototype
    ,它是
    {}
    。现在,它正在尝试查找相同的对象
    {}
    是否存在于
    函数的原型链中。
    函数的直接父函数是和空函数

    console.log(Object.getPrototypeOf(Function));
    # [Function: Empty]
    
    它与对象不同。原型

    console.log(Object.getPrototypeOf(Function) === Object.prototype);
    # false
    
    但是
    [[HasInstance]]
    算法并没有就此停止。它重复并上升一级

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

    这与
    Object.prototype
    相同。这就是为什么返回
    true

    问题中的混淆源于JavaScript(ECMAScript)中函数*固有的双重性质

    js中的函数既是常规函数又是对象。把它们想象成算法杰基尔博士和海德先生。它们看起来像是外部的对象,但在内部,它们只是你的好的老js函数和它们的所有怪癖,或者可能是相反的方式

    JavaScript确实是一项棘手的业务:)

    回到你的问题,借用MDN上出现的语法:

    构造函数的对象实例

    将其应用于代码中的第一条语句:

    函数的对象实例

    这里有
    Object
    ,一个用作对象初始值设定项的构造函数,但由于函数在js中具有双重生命,因此它附带了特定于对象的道具和方法,使其有效地成为一个对象

    因此,声明中的第一个条件已经满足。我们还需要研究其他条件或操作数

    Function
    正如您可能已经注意到的,它也是函数构造函数,但是在执行这个特定语句的过程中,我们对它的另一个对象端不感兴趣

    因此,句法条件都满足,即“宾语”和“构造器”。现在我们可以继续调查他们的遗传关系,以及他们之间是否有联系

    由于
    Object
    本身就是一个工作函数,因此假设它的内部原型prop指向
    函数是很有意义的。prototype
    对象引用,因为在js中,所有的函数都通过相同的位置
    函数继承它们的prop和方法。prototype

    true
    无疑是运算符执行的该比较的唯一预期结果

    对于另一种情况:

    对象的函数实例

    因为我们已经确定js中的函数也有对象端。他们从
    object.prototype
    中得到了他们奇特的特定于对象的玩具,这是有道理的,因此他们构成了对象构造函数的实例

    希望我的解释和寓言不会增加混乱。:)


    *:不仅是在js中具有双重生活的功能。js中几乎所有的数据类型都有对象的阴暗面,有助于轻松完成操作和操作。

    最糟糕的特性实际上是函数本身就是一个实例<代码>Functi的函数实例
    console.log(Object instanceof Function)                         // true
    console.log(Object.__proto__ === Function.prototype)            // true
    
    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
    
    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
    
    console.log(Object instance of Function)                    // true
    console.log(Function instance of Function)                  // true
    console.log(Function.prototype instanceof Object);          // true