Reimplemented Constructor[Symbol.hasInstance] but it still won't be called

青春壹個敷衍的年華 提交于 2021-01-27 17:02:20

问题


So, I was writing some example code implementing another function for Constructor[Symbol.hasInstance] and I noticed my new implementation just won't get called.

The script below is what I expected to happen:

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

I tried to add a console.log call to to my Pirate[Symbol.hasInstance] implementation, but it won't log anything to the console.

Does anyone have any idea of what is happening? Why is my implementation not getting called?

I'm running this on Node 6.9.1.


回答1:


You can find the answer if you do

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

It returns false: you cannot write to the Symbol.hasInstance property of a function with the assignment = operator. The property never gets set and so it never gets called. (Failing silently feels like unhelpful behaviour to me, but there you go. A TypeError is thrown with a helpful message if you are in strict mode, one of the many reasons you should use it all the time.) You can only define the Symbol.hasInstance property on a function with Object.defineProperty.

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

Now jackSparrow instanceof Pirate first logs the question, then returns true.




回答2:


@lonesomeday's answer explains the reason. Assignments don't define a property if the object already inherits that property as non-writable.

If you don't want to use explicit property definitions, consider using the class syntax:

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


来源:https://stackoverflow.com/questions/40982924/reimplemented-constructorsymbol-hasinstance-but-it-still-wont-be-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!