vue2.x數(shù)組劫持原理的實(shí)現(xiàn)
接上篇Vue2.x 對(duì)象劫持,繼續(xù)來寫數(shù)組劫持
實(shí)現(xiàn)原理:
1 重新定義原生數(shù)組方法push unshift shift pop splice sort reverse 因?yàn)檫@些方法可以修改原數(shù)組。
2 拿到原生數(shù)組方法 Object.create(Array.prototype)
3 AOP攔截,再執(zhí)行重寫數(shù)組方法前,先執(zhí)行原生數(shù)組方法
核心監(jiān)聽Observer代碼
// 把data中的數(shù)據(jù) 都使用Object.defineProperty重新定義 es5 // Object.defineProperty 不能兼容ie8 及以下 vue2 無法兼容ie8版本 import {arrayMethods} from './array.js' import { isObject,def } from '../util/index' // 后續(xù)我可以知道它是不是一個(gè)已經(jīng)觀察了的數(shù)據(jù) __ob__ class Observer{ constructor(value){ // 僅僅是初始化的操作 // vue如果數(shù)據(jù)的層次過多 需要遞歸的去解析對(duì)象中的屬性,依次增加set和get方法 // value.__ob__ = this; // 我給每一個(gè)監(jiān)控過的對(duì)象都增加一個(gè)__ob__屬性 def(value,'__ob__',this); if(Array.isArray(value)){ // 如果是數(shù)組的話并不會(huì)對(duì)索引進(jìn)行觀測 因?yàn)闀?huì)導(dǎo)致性能問題 // 前端開發(fā)中很少很少 去操作索引 push shift unshift value.__proto__ = arrayMethods; // 如果數(shù)組里放的是對(duì)象我再監(jiān)控 this.observerArray(value); }else{ // 對(duì)數(shù)組監(jiān)控 this.walk(value); // 對(duì)對(duì)象進(jìn)行觀測 } } observerArray(value){ // [{}] for(let i = 0; i < value.length;i++){ observe(value[i]); } } walk(data){ let keys = Object.keys(data); // [name,age,address] // 如果這個(gè)data 不可配置 直接reurn keys.forEach((key)=>{ defineReactive(data,key,data[key]); }); } } function defineReactive(data,key,value){ observe(value); // 遞歸實(shí)現(xiàn)深度檢測 Object.defineProperty(data,key,{ configurable:true, enumerable:false, get(){ // 獲取值的時(shí)候做一些操作 return value; }, set(newValue){ // 也可以做一些操作 console.log('更新數(shù)據(jù)') if(newValue === value) return; observe(newValue); // 繼續(xù)劫持用戶設(shè)置的值,因?yàn)橛锌赡苡脩粼O(shè)置的值是一個(gè)對(duì)象 value = newValue; } }); } export function observe(data) { let isObj = isObject(data); if (!isObj) { return } return new Observer(data); // 用來觀測數(shù)據(jù) }
重寫原生數(shù)組方法
// 我要重寫數(shù)組的那些方法 7個(gè) push shift unshift pop reverse sort splice 會(huì)導(dǎo)致數(shù)組本身發(fā)生變化 // slice() let oldArrayMethods = Array.prototype; // value.__proto__ = arrayMethods 原型鏈查找的問題, 會(huì)向上查找,先查找我重寫的,重寫的沒有會(huì)繼續(xù)向上查找 // arrayMethods.__proto__ = oldArrayMethods export const arrayMethods = Object.create(oldArrayMethods); const methods = [ 'push', 'shift', 'unshift', 'pop', 'sort', 'splice', 'reverse' ] methods.forEach(method=>{ arrayMethods[method] = function (...args) { const result = oldArrayMethods[method].apply(this,args); // 調(diào)用原生的數(shù)組方法 // push unshift 添加的元素可能還是一個(gè)對(duì)象 let inserted; // 當(dāng)前用戶插入的元素 let ob = this.__ob__; switch (method) { case 'push': case 'unshift': inserted = args; break; case 'splice': // 3個(gè) 新增的屬性 splice 有刪除 新增的的功能 arr.splice(0,1,{name:1}) inserted = args.slice(2) default: break; } if(inserted) ob.observerArray(inserted); // 將新增屬性繼續(xù)觀測 return result; } })
工具方法定義如下:
/** * * @param {*} data 當(dāng)前數(shù)據(jù)是不是對(duì)象 */ export function isObject(data) { return typeof data === 'object' && data !== null; } export function def(data,key,value){ Object.defineProperty(data,key,{ enumerable:false, configurable:false, value }) }
到此這篇關(guān)于vue2.x數(shù)組劫持原理的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue2.x 數(shù)組劫持內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.js實(shí)戰(zhàn)之利用vue-router實(shí)現(xiàn)跳轉(zhuǎn)頁面
對(duì)于單頁應(yīng)用,官方提供了vue-router進(jìn)行路由跳轉(zhuǎn)的處理,這篇文章主要給大家介紹了Vue.js實(shí)戰(zhàn)之利用vue-router實(shí)現(xiàn)跳轉(zhuǎn)頁面的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-04-04詳解vue-meta如何讓你更優(yōu)雅的管理頭部標(biāo)簽
這篇文章主要介紹了詳解vue-meta如何讓你更優(yōu)雅的管理頭部標(biāo)簽,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01vue-loader中引入模板預(yù)處理器的實(shí)現(xiàn)
這篇文章主要介紹了vue-loader中引入模板預(yù)處理器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09vue3 與 vue2 優(yōu)點(diǎn)對(duì)比匯總
隨著用vue3 的開發(fā)者越來越多,其必定是又她一定的有帶你,接下來這篇文章小編就為大家介紹vue3 對(duì)比 vue2 有什么優(yōu)點(diǎn)?感興趣的小伙伴請(qǐng)跟小編一起閱讀下文吧2021-09-09element-ui中select下拉框加載大數(shù)據(jù)渲染優(yōu)化方式
這篇文章主要介紹了element-ui中select下拉框加載大數(shù)據(jù)渲染優(yōu)化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11