實際在開發過程中發現,我們打印data里的數據的時候會發現,他不是我們所看到的以往的很平常的格式,他是一個proxy的格式的,如下圖:
也就是說無論是什么類型的數據,都會在外面包一層proxy的包裝;
這個是作什么的呢?
查資料——————————————
經過這一頓操作之后,數據就可以恢復正常的類型了,
JSON.parse(JSON.stringify(val))
關於Proxy:
Proxy可以理解成,在目標對象之前架設一層 "攔截",當外界對該對象訪問的時候,都必須經過這層攔截,而Proxy就充當了這種機制,類似於代理的含義,它可以對外界訪問對象之前進行過濾和改寫該對象。
如果對vue2.0了解或看過源碼的人都知道,vue2.0中使用 Object.defineProperty()方法對該對象通過 遞歸+遍歷的方式來實現對數據的監控的,
當我們使用數組的方法或改變數組的下標是不能重新觸發 Object.defineProperty中的set()方法的,因此就做不到實時響應了。所以使用 Object.defineProperty 存在如下缺點:
1. 監聽數組的方法不能觸發Object.defineProperty方法中的set操作(如果要監聽的到話,需要重新編寫數組的方法)。
2. 必須遍歷每個對象的每個屬性,如果對象嵌套很深的話,需要使用遞歸調用。
但是vue2.0就是用$set()方法去解決上面的這個問題,Vue3.0呢進行了升級,那就是Proxy。
Proxy基本語法
const obj = new Proxy(target, handler);
這里就和上面的截圖對應上了,有木有發現呢~,再來一個詳細的圖;
參數說明如下:
target: 被代理對象。
handler: 是一個對象,聲明了代理target的一些操作。
obj: 是被代理完成之后返回的對象。
但是當外界每次對obj進行操作時,就會執行handler對象上的一些方法。handler中常用的對象方法如下:
1. get(target, propKey, receiver)
2. set(target, propKey, value, receiver)
3. has(target, propKey)
4. construct(target, args):
5. apply(target, object, args)
如下代碼演示:
const target = {
name: 'kongzhi'
};
const handler = {
get: function(target, key) {
console.log(`${key} 被讀取`);
return target[key];
},
set: function(target, key, value) {
console.log(`${key} 被設置為 ${value}`);
target[key] = value;
}
};
const testObj = new Proxy(target, handler);
/*
獲取testObj中name屬性值
會自動執行 get函數后 打印信息:name 被讀取 及輸出名字 kongzhi
*/
console.log(testObj.name);
/*
改變target中的name屬性值
打印信息如下: name 被設置為 111
*/
testObj.name = 111;
console.log(target.name); // 輸出 111
如上代碼所示:也就是說 target是被代理的對象,handler是代理target的,那么handler上面有set和get方法,當每次打印target中的name屬性值的時候會自動執行handler中get函數方法,當每次設置 target.name 屬性值的時候,會自動調用 handler中的set方法,因此target對象對應的屬性值會發生改變,同時改變后的 testObj對象也會發生改變。同理改變返回后 testObj對象中的屬性也會改變原對象target的屬性的,因為對象是引用類型的,是同一個引用的。如果這樣還是不好理解的話,可以簡單的看如下代碼應該可以理解了:
const target = {
name: 'kongzhi'
};
const testA = target;
testA.name = 'xxx';
console.log(testA.name); // 打印 xxx
console.log(target.name); // 打印 xxx
大概就是這樣的,vue3.0的升級,可直接監聽數組類型的數據變化
監聽的目標為對象本身,不需要像Object.defineProperty一樣遍歷每個屬性,有一定的性能提升。