---恢复内容开始---
前几天被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''