Array.map回调this指向问题


---恢复内容开始---

前几天被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''

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM