《数据响应式-数组变异》

139 阅读2分钟

如果想给已经声明好的实例新增data里的key,可以使用Vue.set,或者预先定义为undefined。

那如果data中有数组怎么办?对于数组来说长度是不定的,可以随时增加和删除。所以肯定无法提前定义好所有key。那么对于数组来说,就只能每次改变的时候都要使用Vue.set吗,这也太麻烦了。

new Vue({
  data: {
    array: ["a", "b", "c"]
  },
  template: `
    <div>
      {{array}}
      <button @click="setD">set d</button>
    </div>
  `,
  methods: {
    setD() {
      this.array[3] = "d";
    }
  }
}).$mount("#app");

点击按钮,会出现'd'吗?不会

因为数组其实也是对象,它的下标0,1,2...就是key。Vue只会对一开始定义的那些数组下标进行监控。别的都不知道,所以也就不会响应。

使用Vue.set(this.array,3,'d') 也不会自动监听和代理(原因未知)

尤雨溪做了一件事:篡改了数组的API。先说结果:

直接使用:this.array.push('d') 页面数组后边会成功出现'd'

array本来是一个普通的数组对象,但是经过new Vue之后,Vue就对数组进行了篡改。在array对象和Array函数中间插入了一个原型,即array->新原型->Array.

在这个新原型上边,他重新定义了7个push,pop之类和原来同名的API。这个新push会先调用原来的push,给数组增加一个值。然后,自动监听和代理新的key。

所以,我调用this.array.push时,会先把key:value放进数组,再自动监听和代理。这样页面就可以响应了。

我们看看现在的push是什么:console.log(this.array)

他有两层原型链,第一层只有七个API,第二层才是真正Array。

具体是怎么篡改的呢?

这只是原理