笔记
ECMA组织,正在尝试将 Object身上有用的东西移植到 Reflect身上。
例如:
let obj = {a:1,b:2}
//为 obj 添加 属性c
Object.defineProperty(obj,'c',{get(){return 3}})
//如果再次添加 属性c,就会导致当前线程因报错停止往下执行。
Object.defineProperty(obj,'c',{get(){return 4}})如果改用 Refect, 则不会出现因重复定义出错而终止线程继续执行:
let obj = {a:1,b:2}
//为 obj 添加 属性c
const x1 = Refect.defineProperty(obj,'c',{get(){return 3}})
console.log("x1=",x1) //x1=true
//如果再次添加 属性c,虽出错但可继续往下执行。
const x2 = Refect.defineProperty(obj,'c',{get(){return 4}})
console.log("x2=",x2) //x2=false为了及时发现上面类型x2这种出错,需要借助try{}catch{}:
try {
Object.defineProperty(obj,'c',{
get(){
return 3
}
})
Object.defineProperty(obj,'c',{
get(){
return 4
}
})
} catch (error) {
console.log(error)
} Reflect的这种 出错不终止执行 是为了 封装函数 相对更加友好一些 ^_^。
源码
模拟Vue3 实现响应式
//#region
//window.Proxy
const p = new Proxy(person,{ //捕获属性变化
//有人读取p的某个属性时调用
// propName: 属性名
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
//return target[propName]
return Reflect.get(target,propName)
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`)
//target[propName] = value
Reflect.set(target,propName,value)
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`)
//return delete target[propName] //如果真删掉,返回true 否则,返回false
return Reflect.deleteProperty(target,propName)
}
})调试:
Chrome浏览器 F12 控制台:
person
p.name='李四'
person总结
Vue3.0中的响应式原理
vue2.x的响应式
实现原理:
对象类型:通过
Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', { get () {}, set () {} })
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
Vue3.0的响应式
实现原理:
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect(反射): 对源对象的属性进行操作。
MDN文档中描述的Proxy与Reflect:
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
new Proxy(data, { // 拦截读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦截设置属性值或添加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦截删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) proxy.name = 'tom'
