Vue2响应式

107 阅读2分钟

Vue2响应式原理:

let obj = {
      name: "Jack",
      age: 18,
      hobby: {
        name1: 'basketball',
        name2: 'pingpang'
      }
    }

    // let obj = [1, 3, 5, 7, 9]

    function defineReactive(obj, key, value) {
      // 当需要监听的属性对应的值也是引用类型,则还需要再次遍历监听,这样才可以监听到该引用类型中属性的变化
      observe(value)
      Object.defineProperty(obj, key, {
        get() {
          console.log(`Get: ${key}`)
          return value
        },
        set(newVal) {
          console.log('newval', newVal, 'value', value);
          if (newVal !== value) {
            console.log(`Set: ${newVal}`)
            value = newVal
          }
        }
      })
    }

    function observe(obj) {
      if (typeof obj !== 'object' || !obj) return;//排除null类型和基本类型
      Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]))
    }
    observe(obj)

    obj.age //Get: age
    obj.age = 88;//newval 88 value 18  //Set: 88
    obj.hobby.name1 //Get: hobby //Get: name1
    obj.hobby.name2 = 'football'//Get: hobby //newval football value pingpang //Set: football
    obj.sex = 'man'//无法监听 不会触发任何的get和set 由于添加的属性在初次遍历所有属性添加监听之后,所以无法监听


    // obj[0]=888 //newval 88 value 1  //Set: 888 但通过这种方式修改或添加的属性,是无法和页面中绑定的数据同步响应的。
    // obj.length=10//无法监听 不会触发任何的get和set
    //obj[5]=100//无法监听 不会触发任何的get和set

在 Vue2的响应式原理中,Object.defineProperty存在以下一些缺陷: 1.对于一个已经创建好的对象,如果后续通过直接赋值的方式新增属性,无法将这个新属性变为响应式的。 2.直接通过下标修改数组元素的值,不会触发响应式更新。 3.通过修改数组的长度也无法触发响应式更新。 4.当需要对一个对象的深层属性进行响应式监听时,需要递归地使用 Object.defineProperty 去定义每个属性,这可能会导致性能问题,特别是对于大型复杂的对象结构

解决方案:Vue.set(target,propertyName/index,value)给对象或数组设置添加值。Vue.delete(target,propertyName/index)给对象或数组删除值. 参数类型:target{Object|Array},propertyName/index{String|Number},value{any}