为何Symbol.iterator可被getOwnPropertySymbols检测,Symbol.hasInstance却不行?
问题场景
我正在学习JavaScript中的Symbol,遇到一个疑问,示例代码如下:
function Func1() { } Func1[Symbol.iterator] = 111; console.log(Object.getOwnPropertySymbols(Func1)); // [ Symbol(Symbol.iterator) ]; it is ok. /********************/ function Func2() { } Func2[Symbol.hasInstance] = () => { console.log("symbol hasInstance"); return false; }; console.log(Object.getOwnPropertySymbols(Func2)); // []; nothing here, I don't understand. /********************/ class Baz { static [Symbol.hasInstance]() { console.log("symbol hasInstance"); return false; } } console.log(Object.getOwnPropertySymbols(Baz)); // [ Symbol(Symbol.hasInstance) ]; it is also ok.
为何直接给函数Func2赋值Symbol.hasInstance后,无法通过Object.getOwnPropertySymbols检测到,但类Baz的静态Symbol.hasInstance却可以?而Symbol.iterator则无此问题?
原因解析
Symbol.hasInstance的特殊属性描述符:Function.prototype[Symbol.hasInstance]是一个不可配置、不可写的属性。当你直接给Func2赋值这个属性时,由于Func2作为Function的实例,其原型链上已经存在这个不可配置的同名属性,普通的赋值操作无法在Func2自身添加新的自有属性(非严格模式下静默失败,严格模式会抛出错误)。这就是为什么Object.getOwnPropertySymbols找不到它——这个属性根本没被添加成Func2的自有属性。类静态方法的定义逻辑:类的静态方法语法(
static [Symbol.hasInstance]() {})本质是使用Object.defineProperty在类的构造函数(也就是Baz)上定义自有属性。这种方式不受原型链上不可配置属性的限制,会直接在Baz自身创建一个Symbol.hasInstance的自有属性,因此能被Object.getOwnPropertySymbols检测到。Symbol.iterator无此问题的原因:Function.prototype上并没有定义Symbol.iterator属性,所以给Func1赋值这个属性时,会直接在Func1自身添加为自有属性,自然能被检测到。
内容的提问来源于stack exchange,提问作者Westrious

