微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

JS数组的map兼容注意事项以及“数组也是对象”的理解

2015-07-27 21:49 前端大全

(点击上方,可快速关注)


作者:slife的博客

网址:http://segmentfault.com/a/1190000002995303

点击“阅读原文”可查看本文网页版


先说结论吧:


数组的map方法在IE9以下是不支持的,因此需要写一个兼容方法来实现此行为,在实现兼容的时候:必须注意:对于数组中被删除(delete)或者根本从未赋值的索引项,map中第一个函数参数是不会执行的。


关于这一点,在ECMA标准和MDN参考文档都是有说明的:


MDN:

it is not invoked for indexes that are undefined, those which have been deleted or which have never been assigned values.


ECMA:

callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.


我看到一些用来兼容的方法,都没有注意到这种情形,那么不注意这种情形会出现什么问题呢?为什么MDN上给的兼容方法会这么曲折呢?


我先把我在培训班的老师给出的兼容方法贴出来:


Array.prototype.myMap = function (fn, context) {

context = context || window;

var ary = [];

if (Array.prototype.map) {

ary = this.map(fn, context);

} else {

for (var i = 0; i < this.length; i++) {

ary[i] = fn.apply(context, [this[i], i, this]);

}

}

return ary;

}


这个实现比较简单,流程很清晰,如果浏览器有原生数组map方法,调用该方法,否则执行else中的语句;但是如果是下面这样一个数组,在没有实现原生map方法的浏览器中,结果跟原生map方法调用不一样:


var arr=[1,2,,,3];

console.dir(arr.myMap(function(e,i,a){return e*2;}));


原生map方法执行上述代码的输出是



而如果浏览器不支持原生map方法,会执行else语句,这样的输出是:




你看,这两者执行区别就在于一开始的结论:原生的map方法跳过了那些从未赋值的索引对应的项。


数组也是对象!!


简单来说,对象就是一系列属性名值对,即某个属性名对应某个属性值;当我们遍历对象时,不在对象中的属性当然不会被访问到。


而在JS中,数组就是对象,甚至数组的一些遍历方法,在内部执行的时候,都是先将数组转化为对象,


var O=Object(this);


然后遍历数组对象中,所有已经定义的,且索引为数字的项。在绝大部分情况下,这些数字刚好是连续的。那什么时候会出现不连续呢?我所知道有这两种;


  1. 以字面量方式新创建数组的时候,连续的逗号,会形成数字索引不连续;如var arr=[1,2,,,3],你可以在浏览器控制台中试试输出console.dir([1,2,,,3])的结果(注意,一定要用console.dir方法);

  2. 利用delete操作符删除数组中的某项。我们知道delete操作符用于删除对象中某个属性,而JS中,数组就是对象的一种,数组的索引就是其属性名,对应的项就是属性值。用delete删除后,数组中的这对属性名值对(又称键值对)就不存在了,这时候对其采用遍历方法,当然不会针对不存在名值对进行调用了。


有一点要特别注意,数组中被删除的项或者从未定义的项,与人为将其值设置为undefined的项,尽管如果强行访问,结果都是undefined,但是是不太一样的,比如这样一个数组,[1,,undefined];,该数组(现在我们可以更准确得说:数组对象)中不存在索引为1的项,但是却存在索引为2的项,可以用console.dir输出看出区别。

数组的length属性还能反映数组长度吗?


说到上面这些,你肯定已经意识到了,既然数组的索引可以被跳过,那数组的length属性还能反映其长度吗?


关于这个问题,我是这么理解的,


  1. 数组的length属性并不能反应数组中元素的数目,在绝大多数情况(即没有人工干预length属性,且数组中没有跳过的索引),它只是刚好,刚好等于最大的索引加一。当我们从对象的角度来看待数组时,像0、1、2、3、4、5、6等等这些数字索引和length一样,都只是数组对象的属性。

  2. 用delete操作符删除数组任意一项,或者将任意一项值赋值为undefined,length不改变;

  3. 当人为地设置数组的length属性值时,length随之改变,同时索引不小于该值的都会被从数组中彻底删除。



前端大全

微信号:FrontDev

打造东半球最好的 前端技术 微信号

--------------------------------------

商务合作QQ:2302462408

招聘和猎头服务QQ:2302462408

投稿网址:top.jobbole.com

 
前端大全 更多文章 5个典型的JavaScript面试题(上) Limu:JavaScript的那些书 Web开发:我希望得到的编程学习路线图 JavaScript基础工具清单 常用排序算法之JavaScript实现
猜您喜欢 第五讲 gets()&&getchar() 从编程的角度理解gradle脚本﹘﹘Android Studio脚本构建和编程 你不牛逼 认识再多牛逼的人 也与你无关 浅谈安卓开发代码混淆技术 我眼中的移动网络测试