Vue数据劫持简单实现

86 阅读1分钟

Vue2 Object.defineProperty 实现

// 使用Object.defineProperty实现数据劫持(简单实现)
function reactive(raw) {
  Object.keys(raw).forEach(key => {
    let value = raw[key]        
    Object.defineProperty(raw, key, {
      get() {
        return value
      },
      set(newValue) {
        if(value !== newValue) {
          value = newValue
        }
      }
    })
    if (Object.prototype.toString.call(value) === '[object Object]') {
      reactive(value)
    }
  })

  return raw
}

// 如果是新增属性,新增的属性没有getter和setter,需要手动实现$set方法
function set(obj, key, value) {
  let tempValue = obj[key] = value
  Object.defineProperty(obj, key, {
    get() {
      return tempValue
    },
    set(newValue) {
      if (tempValue !== newValue) {
        tempValue = newValue
      }
    }
  })
}

eg:调用reactive方法创建一个响应式对象,并且调用set方法,添加一个新的值

let obj = reactive({
  a: 10,
  b: '你好',
  c: 'why',
  d: {
    zhangsan: '123',
    lisi: '555'
  }
})
set(obj, 'e', 'test')
console.log(obj)

image.png

所有的属性都添加了gettersetter

Vue3 Proxy 实现

// 使用Proxy实现数据劫持(简单实现)
function reactive(raw) {
  return new Proxy(raw, {
    get(target, key) {
      return target[key]
    },
    set(target, key, newValue) {
      if (target[key] !== newValue) {
        target[key] = newValue
      }
    }
  })
}

eg:调用reactive方法创建一个响应式对象,并且添加一个新的值

let obj = reactive({
  a: 10,
  b: '你好',
  c: 'why',
  d: {
    zhangsan: '123',
    lisi: '555'
  }
})
obj.e = 'test'
console.log(obj)

image.png