JS转TS重构时,直接赋值属性与仅设value的Object.defineProperties有差异吗?
两种写法运行逻辑存在明确差异,核心来自
Object.defineProperties的属性描述符默认值规则 JS里使用Object.defineProperties/Object.defineProperty定义属性时,未显式声明的描述符项默认值都为false,而直接通过this.title = title赋值创建的属性,三个核心描述符默认值都为true,具体差异体现在三个方面:
- 可写性(writable):第一种写法的
title属性运行时不可被重新赋值,非严格模式下赋值操作会静默失败,严格模式下直接抛出TypeError;第二种写法的title可随意修改 - 可枚举性(enumerable):第一种写法的
title不会被Object.keys()、for...in遍历、JSON.stringify()等枚举操作识别返回;第二种写法的title属于可枚举属性,会参与所有枚举逻辑 - 可配置性(configurable):第一种写法的
title无法被delete操作删除,也无法再次通过Object.defineProperties修改它的描述符配置;第二种写法的title可被删除,也可后续调整描述符
你可以用以下代码验证差异:
// 第一种写法实例表现 const foo1 = new Foo({ name: "测试1", title: "标题1" }); foo1.title = "新标题1"; console.log(foo1.title); // 输出:标题1(赋值无效) console.log(Object.keys(foo1)); // 输出:['name'](title不可枚举) console.log(delete foo1.title); // 输出:false(删除失败) // 第二种写法实例表现 const foo2 = new Foo({ name: "测试2", title: "标题2" }); foo2.title = "新标题2"; console.log(foo2.title); // 输出:新标题2(赋值有效) console.log(Object.keys(foo2)); // 输出:['name', 'title'](title可枚举) console.log(delete foo2.title); // 输出:true(删除成功)
迁移建议
如果原有代码的业务逻辑就是希望title属性不可修改、不可枚举、不可删除,直接改为第二种写法会引发业务故障。如果是当初写第一种写法的开发者不了解默认规则,本来就是要普通属性的行为,那可以放心改第二种写法,或者保留第一种写法的话补充描述符配置即可:
Object.defineProperties(this, { title: { value: title, writable: true, enumerable: true, configurable: true } })
如果是迁移到TypeScript的场景要注意:TS的readonly修饰符仅做编译阶段的赋值校验,不会影响运行时的可写性,如果需要运行时真正不可修改的属性,还是需要保留Object.defineProperties写法。
内容的提问来源于stack exchange,提问作者Fogmeister
相关产品推荐
相关产品推荐

