---恢復內容開始---
前幾天被qq群一個哥們問了一個問題,說他使用array的map的時候,里面回調的this指向指向了window的全局對象,而不是他自己call的數組對象。他的實現代碼如下:
\\
1 '1,2,3,4'.split(',').map(function(item){ 2 console.log(this); 3 console.log(item); 4 });
其實這個問題很簡單。這個和map的實現有關。正好查閱了mozilla網站,找到了兼容舊版本的實現,算法和ECMA262里面規定的算法是一致的,代碼如下(想要自己實現算法請參照EXMA文檔,注釋有標明規范地址):
1 // 實現 ECMA-262, Edition 5, 15.4.4.19 2 // 參考: http://es5.github.com/#x15.4.4.19 3 if (!Array.prototype.map) { 4 Array.prototype.map = function(callback, thisArg) { 5 6 var T, A, k; 7 8 if (this == null) { 9 throw new TypeError(" this is null or not defined"); 10 } 11 12 // 1. 將O賦值為調用map方法的數組. 13 var O = Object(this); 14 15 // 2.將len賦值為數組O的長度. 16 var len = O.length >>> 0; 17 18 // 3.如果callback不是函數,則拋出TypeError異常. 19 if (Object.prototype.toString.call(callback) != "[object Function]") { 20 throw new TypeError(callback + " is not a function"); 21 } 22 23 // 4. 如果參數thisArg有值,則將T賦值為thisArg;否則T為undefined. 24 if (thisArg) { 25 T = thisArg; 26 } 27 28 // 5. 創建新數組A,長度為原數組O長度len 29 A = new Array(len); 30 31 // 6. 將k賦值為0 32 k = 0; 33 34 // 7. 當 k < len 時,執行循環. 35 while(k < len) { 36 37 var kValue, mappedValue; 38 39 //遍歷O,k為原數組索引 40 if (k in O) { 41 42 //kValue為索引k對應的值. 43 kValue = O[ k ]; 44 45 // 執行callback,this指向T,參數有三個.分別是kValue:值,k:索引,O:原數組. 46 mappedValue = callback.call(T, kValue, k, O); 47 48 // 返回值添加到新數組A中. 49 A[ k ] = mappedValue; 50 } 51 // k自增1 52 k++; 53 } 54 55 // 8. 返回新數組A 56 return A; 57 }; 58 }
我們可以看到map是有兩個參數的,如果沒有傳遞第二個參數,那么默認就是undefined \\
1 // 4. 如果參數thisArg有值,則將T賦值為thisArg;否則T為undefined. 2 if (thisArg) { 3 T = thisArg; 4 } 5 //這是循環里面的代碼 6 while(k < len) { 7 ... 8 // 執行callback,this指向T,參數有三個.分別是kValue:值,k:索引,O:原數組. 9 mappedValue = callback.call(T, kValue, k, O); 10 }
所以在執行回調時,T為undefined,默認就會有用頂級對象來調用。這里涉及到了call函數的一些知識點。call函數如果object參數傳入的是null或者undefined的時候,會默認指向頂級對象,在瀏覽器里,就是window對象。\\
用上面算法做兼容要注意的問題是,Object, TypeError, 和 Array 原始的構造器和值未被覆蓋並且callback傳入的回調函數的call是Function.prototype.call的默認實現,否則該實現就不能直接使用了。
\\
''參考:\\
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call \\
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map''