【问题标题】:How instanceof is implemented in JavaScript [duplicate]如何在 JavaScript 中实现 instanceof [重复]
【发布时间】:2015-04-09 14:05:57
【问题描述】:

让我们考虑以下代码 sn-p:

function A() {}
var obj = new A();
function B() {};
obj.constructor = B;
console.info("1: ", obj.constructor); //Function B
console.info("2: ", obj instanceof A); //true
console.info("3: ", obj instanceof B); //false

我猜测对象是否是某个函数类的实例,JS 引擎必须检查对象是否具有相同的构造函数属性。但这似乎并没有发生,因为即使覆盖对象的构造函数属性也不会改变它的 instanceof 输出。

【问题讨论】:

  • 您正在寻找规范。
  • 为了好玩,在您的 Chrome 控制台或类似设备中运行您刚才谈到的代码。你会注意到obj 有一个__proto__ 方法,它仍然被称为A。我真的不知道你的问题的答案,但我认为这与此有关。它不仅仅是 JavaScript。
  • 几个重复:stackoverflow.com/…
  • @FelixKling 是的,问题是重复的,我的错,我尝试删除问题但不能... :(

标签: javascript


【解决方案1】:

ECMAScript 262 规范会告诉您这一点。直接从其The `instanceof operator 部分引用:

11.8.6instanceof 运算符

产生式 RelationalExpression : RelationalExpression instanceof ShiftExpression 的评估如下:

  1. 设 lref 为计算 RelationalExpression 的结果。
  2. 令 lval 为 GetValue(lref)。
  3. 设 rref 为计算 ShiftExpression 的结果。
  4. 令 rval 为 GetValue(rref)。
  5. 如果 Type(rval) 不是 Object,则抛出 TypeError 异常。
  6. 如果 rval 没有 [[HasInstance]] 内部方法,则抛出 TypeError 异常。
  7. 返回调用rval的[[HasInstance]]内部方法的结果,参数为lval。

至于[[HasInstance]]是什么,规范还在其Object Internal Properties and Methods部分定义为:

[[HasInstance]]

返回一个布尔值,指示参数是否可能是由该对象构造的对象。在标准的内置 ECMAScript 对象中,只有 Function 对象实现了 [[HasInstance]]

进一步阅读:http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.5.3

【讨论】:

  • @T.J.Crowder 我认为我已经链接到规范,现在两次。如果我们要继续引用 this section 的话,那么您可能会争辩说我还需要说出 [[TargetFunction]] 是什么,而且它会一直持续下去。
  • 您的来电。以上所有内容基本上都是“instanceof 将调用[[HasInstance]] 内部方法(在函数对象上)”,其中括号中的位仅在您可以阅读规范的情况下。这与解释它做什么(在我看来,不代表其他人)相差甚远。并不是说链接不好。
【解决方案2】:

这个link 声明:

instanceof 操作符测试constructor.prototype 在 对象的原型链。

【讨论】:

    【解决方案3】:

    (我现在已经回答了上一个问题的问题,这是here 的副本,所以标记了这个CW。这个答案基本上只是这个答案的一个副本,概括了一点。 )


    短版

    obj instanceof A 查看A.prototype 引用的对象是否在obj 的原型链中的任何位置。它根本不使用constructor

    更多详情

    §11.8.5 - The instanceof Operator 在规范中对此进行了介绍,它说(间接地,通过§8.6.2)它调用函数对象的[[HasInstance]] 内部方法,传入我们正在测试的对象。 Function[[HasInstance]](在§15.3.5.3 中)表示它从函数的prototype 属性中获取对象引用,然后如果该对象在目标对象的原型链中的任何位置,则返回truefalse 如果它没有。

    它不使用constructor(实际上,JavaScript 本身没有使用)——如果你仔细想想,它不能,因为对象的 constructor 属性只能指向一个函数,但是对象可以是instanceof 多个函数——例如,在伪经典继承的情况下:

    function A() {}
    
    function B() {
      A.call(this);
    }
    B.prototype = Object.create(A.prototype);
    B.prototype.constructor = B;
    
    var obj = new B();
    snippet.log(obj instanceof A); // true
    snippet.log(obj instanceof B); // true
    <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
    <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

    两者都是真的,因为A.prototypeB.prototype 引用的两个对象都在obj 的原型链中。

    instanceof 为真并不一定意味着obj 是通过直接或间接调用A 创建的;它只是表明它们之间存在模糊的联系(A.prototype 指的是也在obj 的原型链中的对象)。它通常意味着A参与了创建对象,但不能保证。

    例如:

    function A() {}
    var obj = Object.create(A.prototype);
    snippet.log(obj instanceof A); // true
    &lt;script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"&gt;&lt;/script&gt;

    请注意,根本没有调用 A 来创建对象。


    或者也许更清楚和/或戏剧性地:

    function A() {}
    var p = {};
    var obj = Object.create(p);
    snippet.log(obj instanceof A); // false
    A.prototype = p;
    snippet.log(obj instanceof A); // true
    &lt;script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"&gt;&lt;/script&gt;

    还有这个不寻常但完全可能的版本:

    function A() {}
    function B() {}
    A.prototype = B.prototype = {};
    var obj = new A();
    snippet.log(obj instanceof B); // true
    &lt;script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"&gt;&lt;/script&gt;

    或者这个:

    function A() {}
    function B() {}
    var obj = new B();
    snippet.log(obj instanceof A); // false
    A.prototype = B.prototype;
    snippet.log(obj instanceof A); // true
    &lt;script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 2012-07-06
      • 1970-01-01
      • 1970-01-01
      • 2012-07-16
      • 1970-01-01
      • 1970-01-01
      • 2014-01-15
      • 2013-01-12
      • 2020-11-01
      相关资源
      最近更新 更多