1. 程式人生 > >那些前端工作中遇到的坑(01)

那些前端工作中遇到的坑(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))

雞湯:坑踩多了不要緊,反正後面還多著呢