vue 为什么没用Object.defineProperty来实现对数组属性的监听
Object.defineProperty 可以做到对数组的监听,它是支持数组的
例如
let array = [1,2,3,4,5] array.forEach((c,index) => { defineReactive(array, index, c) })
function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { enumerable: true, // 属性可枚举 configurable: true, get() { return val; }, set(newVal) { if (val === newVal) return val = newVal } }) }
我们可以遍历数组,用数组的索引作为 key,来给每一项打上getter/setter。
Object.defineProperty 有这个能力,但是vue 为什么没用它来实现对数组属性的监听
原因:
- 如果你知道数组的长度,理论上是可以预先给所有的索引设置 getter/setter 的。但是一来很多场景下你不知道数组的长度
- 性能问题,数组可能会很长,综合考虑不对数组属性进行监听
VUE针对数组情况的做法
重写了数组原型链上的七种方法('push','pop','shift','unshift','splice','sort','reverse'),
在内部调用了数组的原始方法,最后通过ob.dep.notify()更新视图
var arrayProto = Array.prototype; var arrayMethods = Object.create(arrayProto); var methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ]; /** * Intercept mutating methods and emit events */ methodsToPatch.forEach(function (method) { // cache original method var original = arrayProto[method]; // def给arrayMethods对象添加method属性 def(arrayMethods, method, function mutator () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; var result = original.apply(this, args); var ob = this.__ob__; var inserted; switch (method) { case 'push': case 'unshift': inserted = args; break case 'splice': inserted = args.slice(2); break } if (inserted) { ob.observeArray(inserted); } // notify change // 更新视图 ob.dep.notify(); return result }); }); var arrayProto = Array.prototype; var arrayMethods = Object.create(arrayProto); var methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ]; /** * Intercept mutating methods and emit events */ methodsToPatch.forEach(function (method) { // cache original method var original = arrayProto[method]; // def给arrayMethods对象添加method属性 def(arrayMethods, method, function mutator () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; var result = original.apply(this, args); var ob = this.__ob__; var inserted; switch (method) { case 'push': case 'unshift': inserted = args; break case 'splice': inserted = args.slice(2); break } if (inserted) { ob.observeArray(inserted); } // notify change // 更新视图 ob.dep.notify(); return result }); });
observeArray 会把数组里面的对象数据变成是可侦测的响应式数据