instanceof如何在JavaScript中运行?

时间:2014-06-27 13:40:10

标签: javascript

在下面的代码示例中,最后使用 instanceof 检查obj2和obj3,即使构造的方式不同,返回 name 的结果也会返回true财产是不同的。

var Obj1 = function() {
    this.name = "foo1";
};
Obj1.prototype.name = "foo1onProt";
var obj1 = new Obj1();

var Obj2 = function() {};
Obj2.prototype = new Obj1();
Obj2.prototype.constructor = Obj2;
var obj2 = new Obj2();

var Obj3 = function() {};
Obj3.prototype = Object.create(Obj1.prototype);
Obj3.prototype.constructor = Obj3;
var obj3 = new Obj3();

console.dir(obj1);
console.log("obj1.name: " + obj1.name);

console.dir(obj2);
console.log("obj2.name: " + obj2.name);

console.dir(obj3);
console.log("obj3.name: " + obj3.name);

console.log("obj2 instanceof Obj1: " + (obj2 instanceof Obj1));
console.log("obj3 instanceof Obj1: " + (obj3 instanceof Obj1));

在Chrome中运行的结果:

Obj1
  name: "foo1"
  __proto__: Object
    constructor: function () {
    name: "foo1onProt"
    __proto__: Object
obj1.name: foo1
Obj2
  __proto__: Obj1
    constructor: function () {}
    name: "foo1"
    __proto__: Object
      constructor: function () {
      name: "foo1onProt"
      __proto__: Object
obj2.name: foo1
Obj3
   __proto__: Object
   constructor: function () {}
   __proto__: Object
     constructor: function () {
     name: "foo1onProt"
     __proto__: Object
obj3.name: foo1onProt

obj2 instanceof Obj1: true
obj3 instanceof Obj1: true

识别 obj2 obj3 的最佳方式是什么? 实际上 instanceof 是如何工作的?

2 个答案:

答案 0 :(得分:16)

  

认识到obj2和obj3不同的最佳方法是什么?

这在很大程度上取决于你在做什么。一种方法是使用instanceof Obj2instanceof Obj3。由于这两个对象都是在原型链中使用Obj1.prototype创建的,因此它们确定为我们在基于类的OOP中称为超类型的实例。

  

实际上如何工作?

短版

obj instanceof F查看F.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 F1() {}

function F2() {
  F1.call(this);
}
F2.prototype = Object.create(F1.prototype);
F2.prototype.constructor = F2;

var obj = new F2();
snippet.log(obj instanceof F1); // true
snippet.log(obj instanceof F2); // 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>F1.prototype引用的两个对象都在F2.prototype的原型链中。

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

例如:

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

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


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

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


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

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


或者这个:

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

答案 1 :(得分:2)

最简单:当obj instanceof constructor在其构造函数/原型链中具有true原型时,obj会产生constructor。换句话说,您询问引擎是否可以将obj视为constructor的实例/ obj是否与constructor对象相似。

有一些语法允许您将constructor的原型放在obj的原型链中。任何和所有这些都会导致obj instanceof constructor成为true。在您的示例中,obj2obj3在其原型链中都有Obj1

因此,当您向javascript引擎询问 obj2obj3是否与Obj1的实例相似时,JavaScript会假设true - - 唯一的情况是他们不会超越Obj1的行为。