Array.prototype.map()详解
今天在地铁上看到这样一个小例子:
- ["1","2","3"].map(parseInt);
相信很多人和我一样,觉得输出的结果是[1,2,3]。no!no!!no!!!正确的答案是[1,NaN,NaN]。当时我百思不得其解,于是到了公司之后就开始查阅资料,终于弄明白了。
我们先来介绍一下map()方法:
概述:
map()方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组,它不会改变原来的数组。
语法:
array.map(callback[, thisArg])
参数:
callback
原数组中的元素调用该方法后返回一个新数组。它接收三个参数,分别为 currentValue、index、array。
currentValue
callback的第一个参数,数组中当前被传递的元素。
index
callback的第二个参数,数组中当前被传递的元素的索引。
array
callback的第三个参数,调用map()方法的数组,即原数组。
thisArg
执行callback函数时this指向的对象。
描述
map()方法会给原数组中的每个元素都按顺序调用一次callback函数。callback每次执行后的返回值组合起来形成一个新的数组。callback函数只会在有值的索引上被调用,那些从来没被赋过值或者使用delete删除的索引则不会被调用。
callback函数会被自动传入三个参数:数组元素、数组元素索引、原数组本身。
如果thisArg参数有值,则每次调用callback函数时,this都会指向thisArg参数上的这个对象。如果省略了thisArg参数,或者赋值为null或undefined,则this指向全局对象。
使用map()方法处理数组时,数组元素的范围是在callback函数第一次被调用之前就确定了。在map()方法执行的过程中:原数组中新增加的元素将不会被callback访问到;若已经存在的元素被改变或删除了,则它们传递到callback的值是map()方法遍历到它们那一时刻的值;而被删除的元素将不会被访问到。
总结
通常情况下,map()方法中的callback函数只接受一个参数,就是正在被遍历的数组元素本身。但这并不意味着map只给callback传了一个参数。这个思维惯性可能会让我们犯一个很容易犯的错误。
兼容旧环境
map()方法是在最近的 ECMA-262 标准中新添加的方法;所以一些旧版本的浏览器可能没有实现该方法。在那些没有原生支持 map() 方法的浏览器中,你可以使用下面的 Javascript 代码来实现它。
所使用的算法正是 ECMA-262,第 5 版规定的。假定Object、TypeError和 Array 有他们的原始值。而且callback.call的原始值也是 Function.prototype.call
- // 实现 ECMA-262, Edition 5, 15.4.4.19
- // 参考: http://es5.github.com/#x15.4.4.19
- if (!Array.prototype.map) {
- Array.prototype.map = function(callback, thisArg) {
- var T, A, k;
- if (this == null) {
- throw new TypeError(" this is null or not defined");
- }
- // 1. 将O赋值为调用map方法的数组.
- var O = Object(this);
- // 2.将len赋值为数组O的长度.
- var len = O.length >>> 0;
- // 3.如果callback不是函数,则抛出TypeError异常.
- if (Object.prototype.toString.call(callback) != "[object Function]") {
- throw new TypeError(callback + " is not a function");
- }
- // 4. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
- if (thisArg) {
- T = thisArg;
- }
- // 5. 创建新数组A,长度为原数组O长度len
- A = new Array(len);
- // 6. 将k赋值为0
- k = 0;
- // 7. 当 k < len 时,执行循环.
- while(k < len) {
- var kValue, mappedValue;
- //遍历O,k为原数组索引
- if (k in O) {
- //kValue为索引k对应的值.
- kValue = O[ k ];
- // 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
- mappedValue = callback.call(T, kValue, k, O);
- // 返回值添加到新数组A中.
- A[ k ] = mappedValue;
- }
- // k自增1
- k++;
- }
- // 8. 返回新数组A
- return A;
- };
- }
了解了map()方法,现在我们回过头来看看文章开头提到的那个小例子。
通常使用parseInt时,只需要传递一个参数。但实际上,parseInt可以有两个参数,第二个参数是进制数,可以通过语句“alert(parseInt.length) === 2”来验证。
map()方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素、元素索引、原数组本身。第三个参数parseInt会忽视,但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用,而parseInt的第二个参数的范围为2~36(不包含2但包含36),如果省略该参数或者其值为0,则数字将以10为基数来解析;如果小于2或者大于36,parseInt()将返回NaN,所以最终返回了[1,NaN,NaN]。
实际上,这个小例子可以分解成这样理解:
- parseInt("1",0); //基数为0,以十进制来解析,返回1
- parseInt("2",1) //基数为1,小于2,返回NaN
- parseInt("3",2) //基数为2,小于2,返回NaN
注意:在测试parseInt()方法第二个参数范围的过程中发现,当传入的值为1,基数为2时,也会返回1,这点需要注意一下。
我们再来看一下其他小例子:
1、将数组中的单词转换成复数形式。
- function fuzzyPlural(single){
- var result = single.replace(/o/g,"e");
- if(single === "kangaroo"){
- result += "se";
- }
- return result;
- }
- var words = ["foot","goose","moose","kangaroo"];
- console.log(words.map(fuzzyPlural));
- //返回["feet","geese","meese","kangareese"];
2、求数组中每个元素的平方根。
- var numbers = [1, 4, 9];
- var roots = number.map(Math.sqrt);
- //返回[1, 2, 3]
3、在字符串上使用map方法,实现如何在一个String上使用map方法获取字符串中每个字符所对应的ASCII码组成的数组:
- var map = Array.prototype.map;
- var a = map.call("hello world",function(x){ return x.charCodeAt(0);})
- //a的值为[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
Array.prototype.map()详解的更多相关文章
- Javascript中Array.prototype.map()详解
map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数.callback 每次执行后的返回值组合起来形成一个新数组. callback 函数只会在有值的索引上被调用:那些从来没被赋 ...
- JavaScript的Array.prototype.filter()详解
摘抄与:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter 概述 ...
- Array.prototype.map()方法详解
Array.prototype.map() 1 语法 const new_array = arr.map(callback[, thisArg]) 2 简单栗子 let arr = [1, 5, 10 ...
- Javascript中prototype属性详解 (存)
Javascript中prototype属性详解 在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不 ...
- 深入理解 Array.prototype.map()
深入理解 Array.prototype.map() map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果. 语法 let new_array = arr.map ...
- Array.prototype.map()
mdn上解释的特别详细 概述 map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组. 语法 array.map(callback[, thisArg]) 参数 callb ...
- Sass map详解
作为一个CSS预处理器,Sass正受到越来越多的青睐,诸如Github.Codepen.CSS-Tricks.SitePoint.w3cplus等网站采用Sass组织.管理CSS文件,Sass正在逐渐 ...
- Array.prototype.map()和Array.prototypefilter()
ES5 => 筛选功能 Array.prototypefilter(): 代码: var words = ['spray', 'limit', 'elite', 'exuberant', 'd ...
- ECMAScript5中新增的Array方法实例详解
ECMAScript5标准发布于2009年12月3日,它带来了一些新的,改善现有的Array数组操作的方法.(注意兼容性) 在ES5中,一共有9个Array方法:http://kangax.githu ...
随机推荐
- HDU 4608 I-number(模拟)
I-number Time Limit: 5000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描写叙述 The I-number of x is defined t ...
- 【09】绝不在构造和析构过程中调用virtual方法
1.绝不在构造和析构过程中调用virtual方法,为啥? 原因很简单,对于前者,这种情况下,子类专有成分还没有构造,对于后者,子类专有成分已经销毁,因此调用的并不是子类重写的方法,这不是程序员所期望的 ...
- C++ 过载,重写,隐藏
1.过载:在一个类中(也就是一个作用域),方法名相同,形参表不同的方法. 2.重写:父类方法使用virtual,子类方法和方法的方法名,形参表,返回类型相同,子类可以不使用virtual,但是建议使用 ...
- 关于Excel Networkdays方法的实现
最近一个程序要求excel输出的日期差为Networkdays. 在网上找了下,没有找到很好的具体实现方法. 要说明的是,微软的Microsoft.Office.Interop.Excel已经实现的N ...
- linux就是这个范儿之融于心而表于行(1)
原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 .作者信息和本声明.否则将追究法律责 时间总是过得那么快,如流水一般哗啦啦的就淌走了一大堆!周遭事事沧桑变迁喧哗或耳语中流传的故事已渐模糊 ...
- 通过IP控制登录系统
项目中有这么一个需求,就是系统仅仅能在指定ip下登录,能够理解为内部系统,仅仅能够在公司訪问 我的代码是这样写的:入不入流不知道,但能解决这个问题. 获得訪问IP代码: String ip = req ...
- WaterWave
WaterWave.rar
- Qt界面设计1
最近刚接触Qt 对于QML做界面感觉已经很轻松了,但是想尝试一下GUI..准备做一个理财的小软件 ....慢慢记录我的一点一滴的学习经历. 自己封装界面UI 遇到了好多新手级别的问题=_=!!! 1. ...
- ios开发——实用技术OC篇&地图与定位
地图与定位 11.1 iOS定位服务 11.2 iOS地图 11.3 Web地图 1 iOS定位服务 iOS中有三个定位服务组件: Wifi定位,通过查询一个Wifi路由器的地理位置的信息.比较省电, ...
- iOS7 设置隐藏状态栏(status bar)
在info.plist 添加 UIViewControllerBasedStatusBarAppearance(View controller-based status bar appearance) ...