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不仅可以对对象进行代理,还可以代理数组,数组的修改都可以检测到。

 

posted @ 2021-09-16 17:20  SLfish  阅读(344)  评论(0编辑  收藏  举报