那些前端工作中遇到的坑(01)
前段時間接手一個老專案(jQuery+React混在一塊)的遷移工作,除了用React
重寫一些vm+jQuery
的老頁面(這種至少是自己寫的,心裡有數,調起來也省心),剩下的就是將原有的React遷到新倉庫裡,複製!貼上!改路徑!完事!是個體力活。
你以為這樣就結束了?一大堆bug在等著,整整改了半個月,雖然都是些小問題,但整天被測試釘來釘去還是蠻頭疼的。
現在來說說今天的主角吧,這是一個不起眼的問題,最初發現的時候很讓人摸不著頭腦。
part one
const res = request(url);
console.log(res); // { stat: 'ok', data: { value: 1, childs: [1, 2, 3] } }
複製程式碼
上面的程式碼很普通,但是開啟控制檯的Network去看這個介面的返回結果是:{ stat: 'ok', data: { value: 1, children: [1, 2, 3] } }
,你沒有看錯,返回的資料中是children
,而console.log
打印出來的是childs
,是不是很不可思議?接下來我們逐一排查問題。
part two
const res = request(url);
console.log(JSON.stringify(res)); // { stat: 'ok', data: { value: 1, children: [1, 2, 3] } }
console.log(res); // { stat : 'ok', data: { value: 1, childs: [1, 2, 3] } }
複製程式碼
這裡我們把res
轉成字串再輸出,和直接輸出對比發現轉成字串後的結果是和介面返回的結果一樣的,都是children
。看到這裡相信有不少小夥伴已經清楚是怎麼回事了,但應該也有部分同學腦子裡全是問號了(比如當時的我)。
res
,那就順藤摸瓜,找到使用他的地方。然後就發現了這段程式碼:
res.data.children = res.data.childs;
delete res.data.childs;
複製程式碼
原來是為了換欄位,直接操作了源資料,而物件,陣列都是引用型別的,so...
那難道console.log
難道是非同步執行的嗎,不然程式碼順序執行的話前面輸出的結果應該是對的呀?
這麼說其實不準確,我們把同樣的程式碼換個方式執行,比如node.js:
然後跟在瀏覽器中執行對比一下:
這樣就很清晰了,我們都知道js需要一個執行環境,而console.log
的執行跟執行的環境有關。而通過JSON.stringify
轉成字串再輸出相當於給res
拍了一次快照(記錄了他最初的樣子),後面再操作該物件也不會影響到這個字串(你操作物件關我字串什麼事)。
問題搞清楚了,下面要考慮的就是怎麼解決以及以後如何避免。
歸根到底就是一句話:
不要操作源資料!
不要操作源資料!
不要操作源資料!
使用之前深拷貝一下,可以使用最簡單粗暴的JSON.parse(JSON.stringify(res))
。
雞湯:坑踩多了不要緊,反正後面還多著呢