如題商模,Vue是一個js框架渠脉,MobX則是React進(jìn)行狀態(tài)管理的一個庫焚刚,兩者看起來并沒有什么關(guān)聯(lián)劝评,但是由于都使用了Object.defineProperty感局,使得兩者在數(shù)據(jù)綁定操作上不禁有些相似
由于Vue3.X已經(jīng)用Proxy重寫了他的數(shù)據(jù)綁定機(jī)制环疼,所以順帶了解一下Proxy
本文介紹了什么
- Object.defineProperty與Proxy的使用
- Object.defineProperty與Proxy的缺點(diǎn)
- Object.defineProperty在Vue和MobX中造成的問題和解決辦法
Object.defineProperty與Proxy的使用
Object.defineProperty Object.defineProperty - MDN
/*
* obj : 要定義屬性的對象
* prop : 要定義或修改的屬性的名稱或 [`Symbol`]
* descriptor : 要定義或修改的屬性描述符
* value: 該屬性對應(yīng)的值
* writable
* enumerable
* configurable
* get
* set
*/
var o = {};
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true,
get: function () {},
set: function () {}
});
在 descriptor 中不能 同時設(shè)置訪問器 (get 和 set) 和 wriable 或 value娩井,否則會錯设江,就是說想用(get 和 set)锦茁,就不能用(wriable 或 value中的任何一個)
Proxy Proxy - MDN
const proxy = new Proxy({}, {
get: function(target, key, receiver) {
return receiver;
}
});
const d = Object.create(proxy);
d.a === d // true
//d對象本身沒有a屬性,所以讀取d.a的時候叉存,會去d的原型proxy對象找码俩。
//這時,receiver就指向d歼捏,代表原始的讀操作所在的那個對象
});
get和set方法中的receiver參數(shù)參考Proxy get中的receiver問題
小結(jié)
- Object.defineProperty是直接對原始對象進(jìn)行操作并返回稿存,Proxy是進(jìn)行一個類似多例的操作够傍,不會影響原始對象
- Object.defineProperty的屬性較少,Proxy對數(shù)據(jù)劫持對handler方法較多挠铲,但兩者都有最基礎(chǔ)的get和set
Object.defineProperty與Proxy的缺點(diǎn)
Object.defineProperty的缺點(diǎn)
因?yàn)閐efineProperty的屬性限制冕屯,導(dǎo)致了三個問題
1、無法監(jiān)聽到數(shù)組的長度變化
2拂苹、由于只能劫持對象的屬性安聘,對于復(fù)雜對象需要對每個屬性進(jìn)行深度遍歷
3、由于只能劫持對象的屬性瓢棒,對象屬性有新增時浴韭,需要將對象的所有屬性都進(jìn)行遍歷進(jìn)行監(jiān)聽
為什么defineProperty不能檢測到數(shù)組長度的“變化”
數(shù)組的length屬性被初始化為如下
configurable為false也就是說length屬性不能修改,不能刪除脯宿,所以想我們想要通過get/set方法來監(jiān)聽length屬性是不可行的
{
writable: true,
enumerable: false,
configurable: false,
}
驗(yàn)證對象新增的屬性在definproperty中能否被監(jiān)聽
let person = Object.defineProperty({age: 20}, 'name', {
get: function() {
console.log('get!!!');
return name;
},
set: function(newName) {
console.log('set!!!');
name = newName;
},
enumerable: true,
configurable: true
});
person.name; // 'get!!!' 'piers'
person.name = 'zhangpeng' // 'set!!!' 'zhangpeng'
person.age; // 'piers' 此時不會被get監(jiān)聽
person.age = '30'; // '30' 此時不會被set監(jiān)聽
Proxy的缺點(diǎn)
- 由于是es6的特性念颈,所以存在瀏覽器兼容性問題
小結(jié)
- Object.defineProperty有三個缺點(diǎn)
1、無法監(jiān)聽到數(shù)組的長度變化
2连霉、由于只能劫持對象的屬性榴芳,對于復(fù)雜對象需要對每個屬性進(jìn)行深度遍歷
3、由于只能劫持對象的屬性跺撼,對象屬性有新增時窟感,需要將對象的所有屬性都進(jìn)行遍歷進(jìn)行監(jiān)聽 - Proxy有一個缺點(diǎn)
1、存在瀏覽器兼容性問題
Object.defineProperty在Vue和MobX中造成的問題
由于Object.defineProperty的三個缺點(diǎn)歉井,在Vue中有如下問題
// 在Vue中這種數(shù)組操作和對象操作柿祈,不會被Vue監(jiān)聽到
let vm1 = new Vue({
data: {
list: [1, 2, 3, 4]
}
})
let vm2 = new Vue({
data: {
a: 1
}
})
vm1.list[index] = newValue // 非響應(yīng)式的
vm1.list.length = newLength // 非響應(yīng)式的
vm2.a = 2 // `vm.a` 是響應(yīng)式的
vm2.b = 2 // `vm.b` 是非響應(yīng)式的
對于Object.defineProperty的三個缺點(diǎn),我們一次來看Vue和MobX是如何進(jìn)行處理的
1哩至、無法監(jiān)聽數(shù)組長度屬性變化的問題
- Vue重寫了push躏嚎、pop、shift菩貌、unshift卢佣、splice、sort菜谣、reverse這七個數(shù)組方法珠漂,是的這些方法可以響應(yīng)式晚缩,參考Vue文檔說明
- MobX則是會在定義的時候尾膊,默認(rèn)把類數(shù)組長度預(yù)留999個單位
這樣其實(shí)不會對性能有損耗,因?yàn)閖s中對數(shù)據(jù)的遍歷除了for循環(huán)還有forEach荞彼、map冈敛、filter、some等鸣皂,除了for循環(huán)外(for,for...of)抓谴,其他的遍歷都是對鍵值的遍歷
let arr = [1];
arr[1000] = 1;
function a () {
console.time();
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
}
function b () {
console.time();
arr.forEach((item) => {
console.log(item);
})
}
a(); //default: 567.1669921875ms
b(); //default: 0.81982421875ms
2暮蹂、需要對對象的深層屬性或者新增屬性進(jìn)行遍歷,達(dá)到監(jiān)聽的目的
- Vue提供了Vue.set(object, propertyName, value)方法向嵌套對象添加響應(yīng)式property
或者用watch的deep參數(shù)監(jiān)聽對象上深層屬性的變化 - MobX一樣癌压,需要遍歷對象的所有屬性進(jìn)行修改屬性仰泻,只不過MobX沒有幫你去做這個深層遍歷,而是需要你在使用MobX的@observable的時候提前將需要雙向綁定的數(shù)據(jù)提前定義出來滩届,或者強(qiáng)制將對象強(qiáng)制更新關(guān)于在MobX中如何observe觀察深層的數(shù)據(jù)變動
總結(jié)
- Object.defineProperty與Proxy的使用上的區(qū)別
1集侯、Object.defineProperty是直接對原始對象進(jìn)行操作并返回,Proxy是進(jìn)行一個類似多例的操作帜消,不會影響原始對象
2棠枉、Object.defineProperty的屬性較少,Proxy對數(shù)據(jù)劫持對handler方法較多泡挺,但兩者都有最基礎(chǔ)的get和set辈讶,可以將Proxy看成是Object.defineProperty的加強(qiáng)版 - Object.defineProperty與Proxy的缺點(diǎn)
1、Object.defineProperty無法監(jiān)聽到數(shù)組的長度變化
2娄猫、Object.defineProperty由于只能劫持對象的屬性贱除,對于復(fù)雜對象需要對每個屬性進(jìn)行深度遍歷
3、Object.defineProperty由于只能劫持對象的屬性媳溺,對象屬性有新增時勘伺,需要將對象的所有屬性都進(jìn)行遍歷進(jìn)行監(jiān)聽
4、Proxy存在瀏覽器兼容性問題 - Object.defineProperty在Vue和MobX中造成的問題和解決辦法
1褂删、Vue通過重寫數(shù)據(jù)的七個方法飞醉,MobX通過提前將類數(shù)組聲明為長度999,避免無法監(jiān)聽數(shù)組長度的問題
2屯阀、Vue和MobX都是用遍歷的方式來監(jiān)聽深層對象屬性和新增的屬性