// 響應式原理 defineProperty //數據 const data = { obj: { a: 4, b: 6 }, arr: [1, 5, 9] } // 觀察數據 function observe(data) { Object.keys(data).forEach(function(key) { let value = data[key] if (value && typeof value === 'object') observe(value) // 遞歸 Object.defineProperty(data, key, { get() { console.log(`get ${key}`) return value }, set(newVal) { console.log(`set ${key} = ${newVal}`) if (newVal && typeof newVal === 'object') observe(newVal) value = newVal } }) }) } observe(data) let obj = data.obj // get obj let arr = data.arr // get arr obj.a = 8 // set a = 8 obj.a // get a delete obj.b // 無反應 obj.c = 9 // 無反應 obj.c // 無反應 data.obj = {...obj, c: 7} // set obj = [object Object] obj = data.obj // get obj obj.c = 9 // set c = 9 obj.c // get c arr.push(9) // 包括pop,shift,unshift,splice,sort,reverse // 無反應 data.arr = [...arr,9] // set arr = 1,5,9,9,9
const arr = [5, 9, 8] const push = Array.prototype.push Array.prototype.push = function () { const result = push.apply(this, arguments) console.log('作本身喜歡的事情') return result } arr.push(7) console.log(arr)
vue代碼片斷javascript
/* * not type checking this file because flow doesn't play well with * dynamically accessing methods on Array prototype */ var arrayProto = Array.prototype; var arrayMethods = Object.create(arrayProto);[ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] .forEach(function (method) { // cache original method var original = arrayProto[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 }); }); /* */
// 響應式原理 defineProperty //數據 const data = { obj: { a: 4, b: 6 }, arr: [1, 5, 9] } function Dep() {} Dep.target = null // 當前函數 function watcher(fn) { // 函數 Dep.target = fn fn() } // 初始化 function init() { const a = () => { console.log(data.obj.a) } const mix = () => { const c = data.obj.a + data.obj.b console.log(c) } watcher(a) watcher(mix) } // 觀察數據 function observe(data) { Object.keys(data).forEach(function(key) { let value = data[key] const dep = [] // 存放函數的容器 if (value && typeof value === 'object') observe(value) // 遞歸 Object.defineProperty(data, key, { get() { dep.push(Dep.target) return value }, set(newVal) { if (newVal && typeof newVal === 'object') observe(newVal) value = newVal dep.forEach(fn => fn()) } }) }) } observe(data) init() setTimeout(() => { data.obj.a = 10 }, 2000)
以上代碼能夠看出,當obj.a值變化的時候,會觸發a函數和mix函數,具體執行步驟以下vue