如何在JavaScript中实现instanceof

时间:2015-04-09 14:05:58

标签: javascript

让我们考虑以下代码段:

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引擎必须检查对象是否具有相同的构造函数属性。但它似乎并没有发生,因为即使重写对象的构造函数属性也不会改变它的输出实例。

3 个答案:

答案 0 :(得分:3)

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

  

11.8.6 instanceof运算符

     

Shiftalpression的生产RelationalExpression:RelationalExpression实例的评估如下:

     
      
  1. 让lref成为评估RelationalExpression的结果。
  2.   
  3. 让lval成为GetValue(lref)。
  4.   
  5. 让rref成为评估ShiftExpression的结果。
  6.   
  7. 让rval为GetValue(rref)。
  8.   
  9. 如果Type(rval)不是Object,则抛出TypeError异常。
  10.   
  11. 如果rval没有[[HasInstance]]内部方法,则抛出TypeError异常。
  12.   
  13. 返回使用参数lval调用rval的[[HasInstance]]内部方法的结果。
  14.   

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

  

[[HasInstance]]

     

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

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

答案 1 :(得分:2)

link个州:

  

instanceof运算符测试了constructor.prototype的存在   对象的原型链。

答案 2 :(得分:1)

(我现在回答了上一个问题确定的问题,这是here的副本,因此标记了这个CW。答案基本上只是这一个的副本,概括为a位。)


短版

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

更多详情

这在§11.8.5 - The instanceof Operator的规范中有所说明,它(间接地,通过§8.6.2)说它调用了函数对象的[[HasInstance]]内部方法,传入了我们的对象重新测试。 Function的{​​{1}}(在§15.3.5.3中)表示它从函数的[[HasInstance]]属性获取对象引用,如果该对象在任何位置,则返回prototype目标对象的原型链true,如果没有。

它不使用false(实际上JavaScript中没有任何东西) - 如果你考虑它,它就不能,因为对象的constructor属性只能指向一个函数,但一个对象可以是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.prototype引用的两个对象都在B.prototype的原型链中。

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

例如:

A
function A() {}
var obj = Object.create(A.prototype);
snippet.log(obj instanceof A); // true

请注意,根本没有调用<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>来创建对象。


或者可能更清楚和/或更显着:

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


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

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


或者这个:

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