为何直接赋值Symbol.hasInstance无法自定义JavaScript的@@hasInstance方法?
关于
@@hasInstance定义方式的疑问与解析 MDN推荐的定义方式
MDN明确建议,定义@@hasInstance(对应Symbol.hasInstance)方法时,可采用两种方式:class结合static关键字,或者使用Object.defineProperty()。示例代码如下:
function Foo() {} Object.defineProperty(Foo, Symbol.hasInstance, { value(instance) { return false }, });
直接赋值为何无法生效?
但如果采用直接赋值的方式,却无法创建@@hasInstance方法:
function Foo() {} Foo[Symbol.hasInstance] = function(instance) { return false }
通过测试可以看到,这种方式甚至没能在Foo上生成对应自有属性:
console.dir(Foo) // 未显示Foo[Symbol.hasInstance]属性 Foo[Symbol.hasInstance] === Function.prototype[Symbol.hasInstance] // 结果为true Object.hasOwn(Foo, Symbol.hasInstance) // 结果为false
对比其他Symbol的表现
有意思的是,使用其他Symbol(比如Symbol.iterator)时,直接赋值却能正常创建属性:
function Foo() {} Foo[Symbol.iterator] = function(instance) { return false } console.dir(Foo) // 显示Foo[Symbol.iterator]属性 Object.hasOwn(Foo, Symbol.iterator) // 结果为true
测试环境:Firefox 113、Chrome 114
背后的原因
问题出在Function.prototype上的Symbol.hasInstance属性特性——它被设置为不可写(writable: false)。当你尝试直接给Foo[Symbol.hasInstance]赋值时,由于原型链上的同名属性不可写,普通赋值操作会静默失败(如果是严格模式下,还会抛出错误),不会在Foo自身上创建新的自有属性。
而Object.defineProperty()不受这个限制,它可以直接在对象自身上添加新属性,哪怕原型链上的同名属性不可写,最终会覆盖原型属性的访问优先级。
至于Symbol.iterator这类Symbol,要么Function.prototype上原本就没有定义它们,要么它们的属性特性是可写的,所以直接赋值能顺利在Foo上生成自有属性。
内容的提问来源于stack exchange,提问作者czerny
相关产品推荐
相关产品推荐

