vue2.x數(shù)組劫持原理的實(shí)現(xiàn)
接上篇Vue2.x 對象劫持,繼續(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ù)的層次過多 需要遞歸的去解析對象中的屬性,依次增加set和get方法
// value.__ob__ = this; // 我給每一個(gè)監(jiān)控過的對象都增加一個(gè)__ob__屬性
def(value,'__ob__',this);
if(Array.isArray(value)){
// 如果是數(shù)組的話并不會(huì)對索引進(jìn)行觀測 因?yàn)闀?huì)導(dǎo)致性能問題
// 前端開發(fā)中很少很少 去操作索引 push shift unshift
value.__proto__ = arrayMethods;
// 如果數(shù)組里放的是對象我再監(jiān)控
this.observerArray(value);
}else{
// 對數(shù)組監(jiān)控
this.walk(value); // 對對象進(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è)對象
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è)對象
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ù)是不是對象
*/
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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue+elementUI實(shí)現(xiàn)多文件上傳與預(yù)覽功能實(shí)戰(zhàn)記錄(word/PDF/圖片/docx/doc/xlxs/txt)
這篇文章主要給大家介紹了關(guān)于利用vue+elementUI實(shí)現(xiàn)多文件上傳與預(yù)覽功能的相關(guān)資料,包括word/PDF/圖片/docx/doc/xlxs/txt等格式文件上傳,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Vue引入路徑正確但一直報(bào)錯(cuò)問題:Already included file name&n
這篇文章主要介紹了Vue引入路徑正確但一直報(bào)錯(cuò):Already included file name ‘××ב differs from file name ‘××ב only in casing.具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
vue.js中使用echarts實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)刷新功能
這篇文章主要介紹了vue.js中使用echarts實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)刷新功能,需要的朋友可以參考下2019-04-04

