神奇的Object.defineProperty()
Object.defineProperty()可以动态地给对象定义属性, 可以实现数据代理.
Object.defineProperty(obj, prop, descriptor)的3个参数:
- obj 代表要定义属性的对象
- prop代表要定义的属性名
- descriptor代表关于属性的配置, 包括是否可枚举, 是否可删除, 是否可修改, setter, getter.
以下代码动态地给obj对象添加了age属性
1 let obj = { 2 name: "小红" 3 } 4 5 Object.defineProperty(obj, "age", { 6 value: 18 7 }) 8 9 console.log(obj) // {"name":"小红"}, age属性虽然添加上了, 但是因为age属性默认不可枚举, 所以没有打印出来 10 console.log(obj.age) // 18 11 console.log(delete obj.age) // false, age属性默认无法被删除 12 obj.age = 19 // 尝试将age属性的值改成19 13 console.log(obj.age) // 还是18, 上一行虽然给age属性赋值了, 但是因为age属性默认不可修改, 所以没有赋值成功
上面代码的注释中做了一些说明.
如果想要age属性可枚举, 只要在descriptor中增加enumerable为true即可.
如果想要age属性可删除, 只要在descriptor中增加configurable为true即可.
如果想要age属性可修改, 只要在descriptor中增加writable为true即可.
1 let obj = { 2 name: "小红" 3 } 4 5 Object.defineProperty(obj, "age", { 6 value: 18, 7 enumerable: true, 8 configurable: true, 9 writable: true 10 }) 11 12 console.log(obj) // {"name":"小红","age":18} 13 console.log(obj.age) // 18 14 console.log(delete obj.age) // true, age属性无法被删除 15 obj.age = 19 // 尝试将age属性的值改成19 16 console.log(obj.age) // 19
下面介绍descriptor中2个最神奇的属性: get 和 set
顾名思义, get方法就是获取属性的值, 没有参数; set方法就是设置属性的值, 有一个参数用来接收传来的值.
1 let obj = { 2 name: "小红" 3 } 4 5 let obj2 = { 6 age: 18 7 } 8 9 Object.defineProperty(obj, "age", { 10 get() { 11 return obj2.age 12 }, 13 set(value) { 14 obj2.age = value 15 } 16 }) 17 18 console.log(obj.age) // 此处会调用get方法, 返回的是obj2.age 19 obj.age = 19 // 修改obj.age的值, 通过下面两行代码发现obj2.age也被修改了 20 console.log(obj.age) // 19 21 console.log(obj2.age) // 19 22 obj2.age = 20 // 修改obj2.age的值, 通过下面两行代码发现obj.age也被修改了 23 console.log(obj.age) // 20 24 console.log(obj2.age) // 20
上面的代码中, obj与obj2的age属性已经绑定在一起, 修改其中一个就会影响到另一个, 也就是实现了一个简单的数据代理.
最后, 需要注意的是, get 和 set 不能与value 和 writable一起使用, 否则会报异常, 猜测是因为都影响了属性值的获取和修改, 所以不能一起使用.
再补充一个小应用, 实现简单的数据代理, vue底层就是如此使用的.
1 let data = { 2 name: 'tom', 3 address: 'NewYork' 4 } 5 6 let obs = new Observer(data); 7 8 let vm = {} 9 vm._data = data = obs 10 11 function Observer(obj) { 12 let keys = Object.keys(obj) 13 14 keys.forEach(key => { 15 Object.defineProperty(this, key, { // 这里使用this是一个技巧 16 get() { 17 return obj[key] 18 }, 19 set(v) { 20 obj[key] = v 21 } 22 }) 23 }) 24 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?