Object.defineProperty和proxy的简单讲解
1、Vue2.0中使用的Object.defineProperty
Object.defineProperty只能对对象的属性值进行劫持。
function observe(data, key, value) { Object.defineProperty(data, key, { get() { console.log(`访问${key}属性`) return value }, set(val) { console.log(`${key}: ${value} -> ${val}`) value = val } }) } const data = { name: '007', arr: [0, 1, 2] } // 劫持data的name属性 observe(data, 'name', data.name) // 直接访问name console.log(data.name) // 输出 // 访问name属性 // 007 // 改变name属性的值 data.name = '008' console.log(data.name) // 输出 // name: 007 -> 008 // 访问name属性 // 008 // 给data新增属性 data.age = 8 console.log(data.age) // 输出 // 8 // 综上:Object.defineProperty是对对象的属性值进行劫持,无法发现对象中新增的属性。 // 这就是为什么在vue中当你给一个对象添加一个新的属性时,这个新增的属性没有实时更新到视图中。 // 必须通过Vue.$set(obj, key, value)来新增属性才能实时更新视图 // 劫持data的arr属性 observe(data, 'arr', data.arr) console.log(data.arr) // 输出 // 访问arr属性 // [0, 1, 2] // 改变数组中的某一个索引值 data.arr[0] = 2 console.log(data.arr) // 输出 // 访问arr属性 // 访问arr属性 // [ 2, 1, 2 ] // 改变数组长度 data.arr.push(10) console.log(data.arr) // 输出 // 访问arr属性 // 访问arr属性 // [ 2, 1, 2, 10 ] // 综上:用索引修改一个数组项或修改数组长度时,Object.defineProperty不能检测到数组的变动 // 在Vue中可以通过Vue.$set(array, index, value)来改变数组索引值,从而实现视图实时更新。 // Q:为什么在vue中对数组使用push、pop、unshift等方法可以实现视图实时更新呢? // A:是因为Vue将被监听的数组的变更方法进行了包裹,这些方法也会触发视图更新
2、Vue3.0中使用的proxy
Proxy可以劫持整个对象,并返回一个新的对象,Proxy还可以代理数组。
const data = { name: '007', arr: [0, 10, 11] } function observe(data) { return new Proxy(data, { get(data, key) { console.log(`访问${key}属性`) return data[key] }, set(data, key, value) { console.log(`${key}: ${data[key]} -> ${value}`) data[key] = value } }) } let pro = observe(data) console.log(pro.name) // 输出 // 访问name属性 // SLfish // 改变name的值 pro.name = '008' console.log(data.name, pro.name) // data的name属性值也会发生改变 // 输出 // name: 007 -> 008 // 访问name属性 // 008 008 // 新增一个属性值 pro.sex = 'superman' console.log(pro.sex, data.sex) // 输出 // sex: undefined -> superman (出现undefined是因为data一开始没有sex属性,没有设置初始值) // 访问sex属性 // superman superman // 综上:Proxy是对整个对象进行劫持,可以检测到对象的改变。新增的属性值也可以检测到 // 这就是为什么Vue3.0弃用Object.defineProperty而选用Proxy的原因 // 可以发现,对于data里面的数组值改变,proxy也无法检测 pro.arr[0] = 10 console.log(pro.arr) // 输出 // 访问arr属性 // 访问arr属性 // [ 10, 10, 11 ] [ 10, 10, 11 ] // 但是proxy可以对数组进行代理,这是Object.defineProperty做不到的 // 接下来我们就看看proxy是如何代理的吧! let arr = observe(data.arr) console.log(arr[1]) // 输出 // 访问1属性 // 10 arr[1] = 999 console.log(arr) // 输出 // 1: 10 -> 999 // [ 10, 999, 11 ] // 综上:Proxy不仅可以对对象进行代理,还可以代理数组,数组的修改都可以检测到。