重新实现的构造函数[Symbol.hasInstance]但它仍然不会被调用

时间:2016-12-05 20:39:44

标签: javascript metaprogramming

所以,我正在编写一些示例代码,为Constructor[Symbol.hasInstance]实现另一个函数,我注意到我的新实现刚刚被调用。

以下脚本是我预期会发生的事情:

function Pirate(name) {
    this.name = name;
}

const jackSparrow = {
    isPirate: true
};

// Notice how `jackSparrow` is not yet considered an instance of the `Pirate` object
console.log(jackSparrow instanceof Pirate); // false

// Now let's assign another function for `Pirate[Symbol.hasInstance]`
Pirate[Symbol.hasInstance] = function (anObj) {
    return anObj.isPirate;
};

// This will cause Pirate[Symbol.hasInstance] to be called with `jackSparrow`
console.log(jackSparrow instanceof Pirate); // true

我尝试将console.log调用添加到我的Pirate [Symbol.hasInstance]实现中,但它不会将任何内容记录到控制台。

有没有人知道发生了什么?为什么我的实现没有被调用?

我在节点6.9.1上运行它。

2 个答案:

答案 0 :(得分:6)

如果你这样做,你可以找到答案

Object.getOwnPropertyDescriptor( Function.prototype, Symbol.hasInstance).writable

它返回false:您无法使用赋值Symbol.hasInstance运算符写入函数的=属性。该属性永远不会被设置,因此永远不会被调用。 (对于我来说,失败的感觉就像是无益的行为,但是你去了。如果你处于严格模式,TypeError会被抛出一条有用的信息,这是你应该一直使用它的众多原因之一。)你可以仅在Symbol.hasInstance的函数上定义Object.defineProperty属性。

Object.defineProperty(Pirate, Symbol.hasInstance, {
    value: function(anObj) {
        console.log('Is he a pirate?');
        return anObj.isPirate;
    }
});

现在jackSparrow instanceof Pirate首先记录问题,然后返回true

答案 1 :(得分:2)

@lonesomeday's answer解释了原因。如果对象已将该属性继承为不可写,则赋值不会定义属性。

如果您不想使用显式属性定义,请考虑使用类语法:

class Pirate {
  constructor(name) {
    this.name = name;
  }
  static [Symbol.hasInstance](anObj) {
    return anObj.isPirate;
  }
}
const jackSparrow = {
  isPirate: true
};
console.log(jackSparrow instanceof Pirate); // true