最近在學習JavaScript中的閉包,涉及到其中一個案例,想着改寫一下。案例挺簡單,可是改bug過程有些曲折,在此分享一下在改bug過程當中的自我懷疑自我否認直到曲徑通幽的心路歷程。
需求說明:咱們知道arguments對象若是想調用Array的push方法,須要使用Array.prototype.push.apply(argument,[1,2])這樣的方式,但每次都寫這麼一長串代碼特別繁瑣,想着提取一個push方法,方便之後直接調用。
廢話很少說,,直接貼代碼。node
//提取的方法 var push = (function(){ return function(){ var obj = Array.prototype.shift.apply(arguments); Array.prototype.push.apply(obj,arguments); return arguments; } })()
方法洋洋灑灑寫完以後,進入自測階段。爲了偷懶,再次使用了自執行函數,代碼以下:git
//自測代碼 (function(){ push(arguments,4) console.log(arguments); })(1,2,3)
在node環境中執行,結果拋錯以下:github
Array.prototype.push.apply(obj,arguments); ^ TypeError: Cannot assign to read only property 'length' of function 'function (){ push(arguments,4) console.log(arguments); }'
這個報錯很明顯,當給一個function調用Array.porotype.push方法時會拋出這樣的錯誤,由於一個function的length屬性是隻讀的,而push的源碼中length屬性是須要能夠修改的,即一個對象具備可讀寫的length屬性以後才能夠調用Array.porototype.push方法。
回到我提取的push方法中分析,Array.prototype.push.apply(obj,arguments);此刻個人obj應該是一個類數組{ '0': 1, '1': 2, '2': 3 },因此報錯提示沒法直觀解決問題。數組
首先爲了排除測試案例的緣由,我修改了個人測試案例,避免function的介入,代碼以下:
//測試案例 var fn = function(){ push(arguments,4); console.log(arguments); } fn(1,2,3);
修改完成以後發現測試順利經過,說明我提取的方法沒有問題。到此,牽扯出了一個新問題,我使用自執行函數時爲啥會致使出錯。閉包
首先來到我腦海的緣由是自執行函數的執行順序,是否有異步一說。由於我提取push方法也是用的自執行函數,測試案例也是自執行函數,有可能兩自執行函數的前後執行順序致使了問題,爲了驗證這個答案,我決定將自測案例延時執行,代碼以下:
setTimeout(function(){ (function(){ push(arguments,4) console.log(arguments); })(1,2,3) },10);
測試發現順利經過,這個測試結果更加懷疑了剛纔的假設(雖然內心一萬個不相信)。而後開始查js自執行函數的執行順序的問題,未果,說明你們都沒遇到這樣的問題,那頗有可能我這假設不對。沒辦法,只能繼續修改測試,既然是由於調用push.apply時候出錯,我先註釋掉它試試。代碼以下:app
//提取方法代碼 var push = (function(){ return function(){ var obj = Array.prototype.shift.apply(arguments); // Array.prototype.push.apply(obj,arguments); return arguments; } })() //測試案例代碼 (function(){ // push(arguments,4) console.log(arguments); })(1,2,3)
運行結果,拋出了不同的錯誤,不同的煙花,錯誤以下異步
D:\github\jsStudy\heightFn.js:174 })(1,2,3) ^ TypeError: (intermediate value)(...)(...) is not a function
這個錯誤提示很容易定位到了問題,自執行函數結尾未寫分號致使。
這個問題實際上是一個小問題致使的,無關乎技巧。分享這個主要是想表達:在遇到問題時,咱們看到的問題可能只是表象,尋找解決方案的過程就是一個不斷自我猜測,驗證猜測,不斷否認的過程,須要持續不斷的挖掘。
最後貼出最終代碼:函數
var push = (function(){ return function(){ var obj = Array.prototype.shift.apply(arguments); Array.prototype.push.apply(obj,arguments); return arguments; } })(); //測試案例 ;(function(){ push(arguments,4) console.log(arguments); })(1,2,3);