【问题标题】:How does instanceof work in JavaScript?JavaScript 中的 instanceof 是如何工作的?
【发布时间】:2014-08-18 15:37:23
【问题描述】:

在下面的代码示例中,以 instanceof 结尾的 obj2 和 obj3 的检查都返回 true,即使它们的构造方式不同并且返回的结果 name属性不同。

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

识别 obj2obj3 不同的最佳方法是什么? instanceof 实际上是如何工作的?

【问题讨论】:

  • 您创建了两个不同的对象,都以 Obj1 作为其基础 - 然后您询问它们是否是 Obj1 的实例。嗯,是的,他们都是。如果您想知道它们是否不同,只需使用=== 运算符即可。
  • @AHM 我看到你的回复来自很多年前,但是我从未见过使用严格相等来直接比较 JavaScript 对象的方法。你介意扩展你上面关于“objA === objB”的评论的意思吗? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 对于对象,只有当比较的两个对象是同一个对象时,=== 运算符才会返回 true。虽然您通常不会将对象与其自身进行比较,但如果您想找出已知集合中的哪个对象,您有参考,这可能会很有用。

标签: javascript


【解决方案1】:

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

这在很大程度上取决于您对它们的处理方式。一种方法是使用instanceof Obj2instanceof Obj3。由于这两个对象都是在其原型链中使用Obj1.prototype 创建的,因此将它们标识为我们在基于类的 OOP 中称为超类型的实例是有道理的。

instanceof 实际上是如何工作的?

短版

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

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

var obj = new F2();
console.log(obj instanceof F1); // true
console.log(obj instanceof F2); // true

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

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

例如:

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

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


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

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

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

function F1() {}
function F2() {}
F1.prototype = F2.prototype = {};
var obj = new F1();
console.log(obj instanceof F2); // true

或者这个:

function F1() {}
function F2() {}
var obj = new F2();
console.log(obj instanceof F1); // false
F1.prototype = F2.prototype;
console.log(obj instanceof F1); // true

【讨论】:

  • @VLAZ - 谢谢,我不知道我的任何答案仍然使用它。我得去打猎了……
  • 哦,对了……我也想写个评论通知你。我在编辑时忘记了这一点。 :) 另外,我尝试找到 repo,但似乎它已经消失了,我认为是因为它不再需要了。
  • @VLAZ - 无需发表评论,所以当您的答案被编辑时会通知您。 :-) 我不记得删除了那个 repo,但我这样做似乎比 github 丢失它更有可能。 :-D 呃,数据浏览器说我有 349 个要修复... ;-( 以每两分钟计算,这几乎是 12 个小时的工作。我将每天做 5-10 个,持续一两个月...
  • 也许你可以automate it :) 我也可以偶尔伸出援手。我最近开始更新一些较旧的帖子,主要是让 sn-ps 可运行。我仍在探索查找要更新的帖子的方法,我主要是浏览和审查引起我注意的整个问答。所以,它现在是无指导的和零星的 - 你的帖子给出了一个更直接的目标,我可以努力实现。
  • @VLAZ - 太好了!我可以点点滴滴地做到这一点,但如果你想加入,here's the list,只需将你所做的任何事情更改为删除线文本(请不要删除它们)。如果您在我的旧式 ASCII-art 中看到任何使用 - 而不是 - 的内容,您可以添加注释吗?我去修理它们。 :-) 但同样,只有如果你真的想要,否则我会去找他们。 (我已经做了一些不在那个列表中的,所以不再是 349 了……)
【解决方案2】:

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

有少量语法允许您将constructor 的原型放在obj 的原型链中。它们中的任何一个都将导致obj instanceof constructor 成为true。在您的示例中,obj2obj3 在其原型链中都有 Obj1

因此,当您询问您的 JavaScript 引擎是否任一 obj2obj3 的行为类似于 Obj1 的实例时,JavaScript 假定 true - 这是他们不会的唯一情况' t 是你是否已经覆盖了Obj1 的行为。

【讨论】:

  • @FrédéricHamidi 很好的区别。
  • 这是错误的答案。 T.J.的回答克劳德是正确的。
猜你喜欢
  • 2011-08-20
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 2011-12-19
  • 2023-03-10
  • 1970-01-01
  • 2011-01-27
  • 2013-04-04
相关资源
最近更新 更多