个人笔记
数据劫持
值得是访问或修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果 经典应用:vue双向绑定原理(vue双向绑定 = 数据劫持 + 发布者订阅模式)
数据劫持实现思路
- 利用Object.defineProperty 设置set和get
- 利用ES6新增的proxy设置代理
Object.defineProperty
这个方法接受三个参数
- 操作对象
- 操作属性
- 描述符对象(数据属性/访问器属性)
描述符对象(数据属性)他可以有以下4个属性来进行描述对象属性
configurable表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认为falseenumerable表示能否通过for in循环访问属性,默认为falsewritable表示能否修改属性的值,默认为falsevalue这个属性的数据值,默认为undefinded
栗子
configurable 属性
let p1 = {
name: '张三',
age: 18
}
Object.defineProperty(p1,"age",{
enumerable: false
})
delete p1.age // 无法删除
console.log(p1); //{name: '张三', age: 18}
enumerable 属性
let p1 = {
name: '张三',
age: 18
}
Object.defineProperty(p1,"age",{
enumerable : false
})
for(let key in p1){
console.log(p1[key]) // "张三"
}
writable属性
let p1 = {
name: '张三',
age : 18
}
Object.defineProperty(p1,"age",{
writable : false
})
p1.age = 20// 无法删除
console.log(p1)// {name: '张三', age: 18}
value属性
let p1 = {
name: '张三',
age : 18
}
Object.defineProperty(p1,"age",{
value:20
})
console.log(p1)// {name: '张三', age: 20}
描述符对象(访问器属性)
- get:在读取属性值的时候调用的函数,默认值是undefined
- set:在设置属性值的时候调用的函数,默认值是undefined
栗子
let p1 = {
name : '张三',
age : 18
}
// 错误栗子 这两种写法会导致栈溢出
Object.defineProperty(p1,"age",{
get:function() {
// 当return p1.age 他会再次调用get 函数,无限循环
return p1.age
},
set:function(value) {
// 当设置p1.age 他会再次调用set函数,无限循环
p1.age = value
}
})
// 正确栗子
let initValue = 20 // 存储初始值
Object.defineProperty(p1,"age",{
get:function() {
console.log("获取了age") // 进行一些操作
return initValue // 返回 initValue
},
set:function(value) {
console.log("设置了age的值") // 进行一些操作
initValue = value // initValue重新赋值
}
})
console.log(p1.age) // 获取了age , 20
p1.age = 30
console.log(p1.age) // 设置了age , 30
进阶 处理对象属性值为对象
利用递归 + Object.defineProperty实现
Proxy
Object.defineProperty 的getter 和 setter 是属性级别的拦截,代理是对象级别的拦截!功能更加强大
更多Proxy的解释,方法请移步[(35条消息) 猿创征文|一文带你深入掌握ES6 Proxy数据代理_es6的proxy实现原理_海底烧烤店ai的博客-CSDN博客]
let user = { name: 'Jimmy',age:18 }
function makeProxy(target) {
return new Proxy(target, {
get: (target, key) => {
console.log('这里获取了这个数据,上报!')
return target[key]
},
set: (target, key, value) => {
console.log('设置的值是',key,value)
target[key] = value
},
})
}
let proxy = makeProxy(user)
console.log(proxy)//输出Proxy {name: 'Jimmy', age: 18}
proxy.age = 20 //输出设置的值是 age 20
console.log(proxy.age) //输出这里获取了这个数据,上报! 20
资料来源 b站up主Jimmyhao, csdn[(35条消息) Object.defineProperty方法(详解)_objectdefineproperty_搞前端的小菜的博客-CSDN博客]