多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# Vue如何实现对象和数组的监听? 由于Object.defineProperty()只能对属性进行数据劫持,而不能对整个对象(数组)进行数据劫持,因此Vue框架通过遍历数组和对象,对每一个属性进行劫持,从而达到利用Object.defineProperty()也能对对象和数组(部分方法的操作)进行监听 直接给一个数组项赋值,Vue能检测到变化吗? 由于JavaScript的限制,Vue不能检测到以下数组的变动 当利用索引直接设置一个数组项时,例如vm.items[indexOfItem] = newValue 当修改数组的长度时,例如vm.items.length = newLength 为了解决第一个问题,Vue提供了以下操作方式 ``` // Vue.set Vue.set(vm.items, indexOfItem, newValue) // vm.$set,Vue.set的一个别名 vm.$set(vm.items, indexOfItem, newValue) // Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue) ``` 为了解决第二个问题,`Vue`提供了以下操作方式 ``` // Array.prototype.splice vm.items.splice(newLength) ``` ## 讲一讲Vue是如何检测数组的变化? > 核心思想:使用了函数劫持的方式,重写了数组的方法(push,pop,unshift,shift···) Vue将data中的数组,进行了原型链的重写,指向了自己所定义的数组原型方法,当调用数组的API时,可以通知依赖更新,如果数组中包含着引用类型,会对数组中的引用类型再次进行监控 ### Vue如何通过`vm.$set()`来解决对象新增/删除属性不能响应的问题? Vue.$set的出现是由于Object.defineProperty的局限性:无法检测对象属性的新增或删除。 > 由于`JavaScript`的限制,Vue无法检测到对象属性的添加或删除。这是由于Vue会在初始化实例时对属性的`getter`和`setter`进行劫持,所以属性必须在data对象上存在才能让Vue将它们转换为响应式数据。 `Vue`提供了`Vue.set(object, propertyName, value) / vm.$set(object, propertyName, value)`来实现为对象添加响应式属性,其原理如下: * 如果目标是数组,直接使用数组的`splice`方法触发响应式 * 如果目标是对象,会先判断对象属性是否存在,对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用`defineReactive()`方法进行响应式处理(`defineReactive()`是Vue对`Object.defineProperty()`的二次封装)