【问题标题】:instanceof check works on subclass without setting constructor [duplicate]instanceof检查适用于子类而不设置构造函数[重复]
【发布时间】:2016-06-02 22:56:22
【问题描述】:

我有以下 JavaScript 代码

function Parent() {
}

function Child() {
}

Child.prototype = Object.create(Parent.prototype);

注意声明的缺失

Child.prototype.constructor = Child;

我的理解是,由于尚未设置 constructor 属性,instanceofChild 类的新实例的检查应该会失败。

var child = new Child();
child instanceof Child; //Should give false

我验证构造函数设置不正确

但是当我运行 child instanceof Child 时,它给了我真实的感受

但它应该是false,因为构造函数属性没有在Child的原型上设置为Child

环境

Google Chrome Version 48.0.2564.109 (64-bit)
Ubuntu 14.04 LTS

【问题讨论】:

  • @Bergi 虽然这个问题的答案可能与这个问题有关,但 IMO 的问题确实不同。
  • @AseemBansal:SO 对“重复”的定义(也许令人惊讶)不是关于 questions 是否相同,而是 answer 是否相同较早的问题也回答了这个问题。 (这也不是贬义的;通过不同的问题措辞,重复提高了人们找到答案的几率。)我认为 Bergi 是对的。 (他擅长复制。)

标签: javascript constructor prototype subclass prototypal-inheritance


【解决方案1】:

我的理解是,由于尚未设置构造函数属性,因此对 Child 类的新实例的 instanceof 检查应该失败。

instanceof 根本不使用 constructor 属性。事实上,直到 ES2015(又名 ES6),constructor 属性并没有用于 JavaScript 本身的 anything。它定义存在于运行时分配给函数的prototype属性的默认对象上,但未使用

让我们看看instanceof 是如何工作的。考虑:

o instanceof Foo

从 ES2015 开始,instanceof 将检查 Foo 是否实现了一个名为 @@hasInstance 的内部操作,如果是,它将使用该操作询问 Foo o 是否是一个实例。

在 ES5 和更早版本中(或者如果 Foo 没有该内部操作),instanceof 将查看 Foo.prototype 指向的对象是否位于 o 原型链上的任何位置。 (如果“原型链”不是一个熟悉的术语,请看答案末尾的*,然后再回来。)如果是,则返回true;如果不是,则返回false

例如,这是instanceof 的概念实现,省略了一些细节:

function isAnInstance(obj, func) {
    // Start: ES2015+ part
    const hasInstance = func[Symbol.hasInstance];
    if (hasInstance) {
        return hasInstance.call(func, obj);
    }
    // End: ES2015+ part
    // Start: The OrdinaryHasInstance specification operation
    for (let p = Object.getPrototypeOf(obj); p; p = Object.getPrototypeOf(p)) {
        if (p === func.prototype) {
            return true;
        }
    }
    return false;
    // End: The OrdinaryHasInstance specification operation
}

JavaScript 内置的函数do@@hasInstance(它们从Funtion 继承它),但它所做的只是上面显示的 OrdinaryHasInstance 操作。请参阅规范hereherehere

我们可以从您的问题中看到constructor 没有涉及,从这个简单的演示中也可以看出:

var p = {};
var o = Object.create(p);
var Foo = function() {};
Foo.prototype = p;
console.log(o instanceof Foo);                // true
console.log(o.hasOwnProperty("constructor")); // false
console.log(
    Object.getPrototypeOf(o).constructor === Object
);                                            // true

注意:

  1. o 不是通过 Foo 创建的。
  2. 事实上,Foo 甚至在o 创建之后才存在
  3. o 没有自己的 constructor 属性。
  4. o 原型的constructor 属性是Object,而不是Foo

...然而instanceof 说“是的,看起来它是一个 Foo。” :-) 纯粹是因为Foo.prototype 指向的对象也在o 的原型链上。


* “原型链”

您清楚地知道 JavaScript 中的对象具有原型,它们可以从原型中继承属性。这些原型是对象,所以它们有原型。所以你会得到一个原型“链”。

考虑一个两级(可以说是三级)继承层次结构,这里在 ES5 中:

function Base() {
}

function Derived() {
    Base.call(this);
}
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;

...或在 ES2015 中:

class Base {
}
class Derived extends Base {
}

现在我们使用它:

var d = new Derived();

(你在下面看到“d 对象”和类似的东西,当然我的意思是“d 所指的对象”——但这真的很冗长。) p>

现在,d 对象的原型是 Derived.prototypeDerived.prototype 的原型是 Base.prototypeBase.prototype 的原型是 Object.prototypeObject.prototype 没有原型(其[[Prototype]] 内部插槽为null)。

这些对象是d 底层的原型链,它们意味着dinstanceof Objectinstanceof Baseinstanceof Derived

【讨论】:

  • 能否请您改写一下-“使用您使用的函数的原型属性的对象”?我无法理解它的含义。也许是一个简单的例子?
  • @AseemBansal:你知道,我写了那句话,然后想“嗯,像泥巴一样清晰?”让我们看看我能不能解决这个问题。 :-)
  • @Bergi:它涉及class 的非糖方面,主要是herehere。我认为这是使数组和承诺子类化成为可能的一部分。例如,Promise.prototype.then 使用 SpeciesConstructor,它使用 Promise 上的 constructor 属性。
  • @AseemBansal:不,那里的答案没有过时。也许还可以看看What it the significance of the Javascript constructor property? - 很方便。
  • @AseemBansal:不,TJ 提醒我的是一个非常特殊的情况,不适用于 ES5 子类化,如果 you需要明确设置 .constructor > 需要它。如果你要继承数组或 Promise,你必须使用 ES6 class 语法自动设置属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-06
  • 1970-01-01
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多