博客地址javascript
本篇主要說一些基礎知識點,關於多項賦值順序,對象引用等,期間插入一點es6只是以及解決問題的思路。java
開頭先來作一道面試題git
var a={n:1};
var b=a;
a.x=a={n:2};
console.log(a.x);
console.log(b.x);
複製代碼
最後輸出的是什麼? 先不說答案,咱們來分析一下es6
L2(第二行) 咱們把a賦值給b, 因爲a是對象類型,這就意味着b和a指向同一個內存地址github
L3 a.x = a = { n: 2}
面試
這裏咱們有個疑惑,這句語句執行順序是 a = {n: 2} && a.x = {n:2}
仍是 a.x = {n:2} && a= {n:2}
仍是這種 a = {n: 2} && a.x = a
json
咱們這裏能夠藉助 Object.defineProperty
或 ES6的 Proxy
來驗證多項賦值的順序是怎樣的數組
const obj = new Proxy({}, {
set(target, key, value, r) {
console.log(key, value)
if (key === 'a') Reflect.set(target, key, 'isA', r);
else Reflect.set(target, key, value, r);
}
});
obj.b = obj.a= {n: 1};
// 輸出:
// "a" {n: 1}
// "b" {n: 1}
obj.a; // isA
obj.b; // {n: 1}
複製代碼
因此咱們能夠得出 賦值的順序是從右邊開始到左邊的。並且是直接 a = {n: 1}, a.x = {n:1 }
,而不是 a.x = a
這樣去賦值微信
如今咱們再借助 Proxy 來分析一開始part1這道題,用obj.a, obj.b 來代替原題目的 a和b。
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
obj.a = {n: 1 };// getting a;
obj.b = obj.a; // getting a; setting b;
obj.a.x = obj.a = {n:2 }; // getting a; setting a;
複製代碼
能夠看到 obj.a.x = obj.a = {n: 2}
這段語句執行時,會先輸出一個 getting a 再輸出 setting a。
這就意味着在對 obj.a.x
賦值時,程序是先獲取 obj.a
指向的對象的內存地址,此時觸發了 getting a,而後再對右邊 obj.a
進行賦值,觸發了 setting a, 賦值完最後一步纔是對 obj.a.x
賦值 {n:2 }
。
重點: 在對obj.a.x賦值的時刻已經獲取了obj.a該對象指向的內存地址,因此後面a就算指向其餘地址,也和這裏的obj.a.x無關。此時指向該地址的還有obj.b
咱們再用三張圖來捋一捋整理的思路
執行 obj.a = {n: 1}; obj.b = obj.a
後obj對應的引用是這樣的
執行 obj.a.x = xxx
時
執行obj.a.x = obj.a = {n:2}
後
至此,這道面試題相信你們都有答案了,能夠本身去控制檯驗證一下。 假如這時候再執行 obj.a.n = 3
, 打印obj.b
會輸出什麼呢?
接下來咱們來看另外一道題,關於對象循環引用的
var a = { n: 1}
a.b = a;
複製代碼
這裏的a明顯是循環引用,那麼咱們要怎樣才能判斷一個對象是不是循環引用呢?
其實這道題我一開始除了遞歸判斷外沒有很好的解決方案,後面是羣裏一個叫話費
的大佬說(這道題也是他出的)直接用 JSON.stringify
,微信小遊戲的源碼裏面就是這麼去判斷。
JSON.stringify
若是遇到參數裏有循環引用的,就會拋出一個循環調用的錯誤 Uncaught TypeError: Converting circular structure to JSON
那若是不用JSON.stringify或者想要本身實現一個去檢測循環調用,該怎麼寫呢?(面試官和部門前端leader最喜歡這麼問)
通常遇到這種,最簡單的方法就是去找這個方法的 polyfill, json3。我找的是 json3的 polyfill 裏面大概是遍歷對象存到stack數組,再在解析的時候去判斷是否有循環引用的狀況。 json3.js#L482
照着他的思路大概寫了一個,其實就是前面說到的簡單遞歸判斷
var stack = [];
function fn(obj) {
var len;
for (len = stack.length; len--;) {
if (stack[len] === obj) throw TypeError()
}
stack.push(obj);
for (let k in obj) {
const value = obj[k]
if (typeof value === 'object') fn(value);
}
}
複製代碼
最後第一次講關於語言知識點的,若是發現有錯誤的地方 歡迎指出~
謝謝惠顧,請笑納