JavaScript浅析 -- 数组方法(下)

一、数组遍历

Array提供了5种遍历操作数组元素的方法,有map、forEach、filter、some、every,他们分别适用于不同的场合,下面一一解析。

1. map方法

map方法接受两个参数,第一个参数是函数,第二个参数可以用来绑定函数执行中的this。map会把每个元素作为参数传入函数,然后将每个函数结果组成新数组返回。会跳过空位,不会跳过null和undefined。

2. forEach方法

forEach方法接受两个参数,第一个参数是函数,第二个参数指定函数执行中的this指向。forEach会把每个元素作为参数传入函数进行处理(仅处理,不会有返回结果)。且无法用breakcontinue中断执行,若要中断请用for。

3. filter方法

filter同样接受两个参数,把每个元素作为函数参数传入,将函数结果为true的元素组成的新数组

4. some方法

some也接受两个参数,把每个元素作为函数参数传入,只要函数结果有一个返回true则some返回true。对于空数组some返回false,且回调函数不执行。

5. every方法

every也接受两个参数,把每个元素作为函数参数传入,所有函数结果都返回true时则every返回true。对于空数组every返回true,且回调函数不执行。

总结补充:
  • 除了forEach没返回值,其他4个都有返回值,some和every返回的是布尔值,map和filter返回的是数组。由于filter和map返回的都是数组,可以链式调用,即map的结果可以再调用map。
  • 上面的是Array提供的遍历方法,而可以用来遍历数组还有forfor-offor-in。其中for-of是es6增加的用来遍历具有iterator接口的数据结构的的,而数组原生具备iterator接口,所以可用来遍历数组。for-in是用来遍历对象属性的,而数组也是对象的一种(但不推荐用此法遍历数组,因为for-in会遍历所有可枚举属性包括继承的)。用法如下:
var arr = ['first', 'second', 'third'];
// for用法
for (var i=0,len=arr.length; i<len; i++) { // 先将len存起来以免动态增加或多次重复读取len
  console.log(arr[i]);
}

// for-of用法
for (var value of arr) {
  console.log(value);
}

// for-in用法
for (var key in arr) {
  console.log(arr[key]);
}
// 上面三种都依次打印出 first second third
  • 遍历效率:for > for-of > forEach > map > for-in

二、数组的截取

slice用于截取某个区域段的元素,然后返回这些元素组成的新数组,原数组不发生改变。该方法接受两个参数,第一个参数表示从数组哪个位置(包含)开始截取,第二个表示到哪个位置(不包含)停止截取,若没有第二个参数则默认为arr.length。两个参数若为负数则倒着算,如果第一个参数大于第二个则返回空数组。

var arr = [1, 2, 3, 4];
arr.slice(1); // [2, 3, 4],相当于arr.slice(1, arr.length)
arr.slice(1, 3); // [2, 3]
arr.slice(-4, -1); // [1, 2, 3],相当于arr.slice(arr.length-4, arr.length-1)
arr.slice(3, 2); // []

slice还有一个作用,可以用来将类数组对象转换为真正的数组。详细见下文。

三、数组判断

判断某个变量是否某种类型我们一般用typeof,但是typeof返回的只有基本数据类型(number, string, boolean, undefined, null, object, symbol;在此基础上去掉了null增加了function)。而Array也是一种对象,所以返回的也是object,并不会返回array,如下:

typeof 1; // "number"
typeof 'hello'; // "string"
typeof true; // "boolean"
typeof Symbol(); // "symbol",es6新增数据类型
typeof undefined; // "undefined"
typeof null; // "object"
typeof function(){}; // "function"
typeof new Object(); // "object"
typeof new Array(); // "object"

所以使用typeof来判断一个变量是否为数组并不可行。若要判断是否为数组,主要有以下四种方法:

1. 通过instanceof判断

instanceof主要用来判断某对象是否为另一个对象的实例的,而所有数组都是Array的实例,所以可以用此法判断变量是否为数组。instanceof的主要实现原理是判断某构造函数的prototype是否在被检测对象的原型链上。用法如下:

var arr = [1, 2];
arr instanceof Array;  // true
2. 通过constructor判断

由于所有数组都是Array的实例,而实例的constructor会返回对应的构造函数,所以所有数组的constructor都是Array,可以通过此法来判断是否为数组。

var arr = [1, 2];
arr.constructor === Array; // true
3. 通用Object.prototype.toString()判断

Object.prototype.toString()会返回对象的字符串形式,如[object Object],该字符串第一个是typeof的值,第二个是constructor的值,所以数组返回的是[object Array]。由于基本所有实例的原型链上都有Object.prototype,所以数组实例可以调用借用此法然后判断返回值是否是[object Array]来判断是不是数组。

var arr = [];
Object.prototype.toString.apply(arr) === '[object Array]'; // true
4. 通过Array.isArray()判断

ES6新增了一个Array.isArray()专门用于判断数组,这样的写法比上面几种更简洁明了表明了意图,使用起来也非常方便。

var arr = [];
Array.isArray(arr); // true

四、数组转化

有时候,我们会有一些类似数组的但实际又不是数组的对象,我们称为类数组对象,如string、DOM节点的NodeList、方法参数arguments等,他们一般都有数字作为索引且有length属性。由于他们不是真正的数组,所以无法使用数组的push等方法,要想使用需要先转为真正的数组(虽然可以call借用数组方法但效率没比处理真正的数组高)。一般有如下三种方法:

1. 通过slice来转化
var str = 'hello';
Array.prototype.slice.call(str); // ["h", "e", "l", "l", "o"]
Array.prototype.slice.apply(str); // ["h", "e", "l", "l", "o"]
Array.prototype.slice.bind(str)(); // ["h", "e", "l", "l", "o"]
2. Array.from()

ES6提供了真正转数组的方法Array.from(),他可以用来将类数组对象具有Iterator接口的对象转为真正的数组,用法如下:

var str = 'hello';
Array.from(str); // ["h", "e", "l", "l", "o"]
3. 扩展运算符

ES6的扩展运算符...能将具有Iterator接口的对象展开成多个序列元素。

var str = 'hello';
[...str]; // // ["h", "e", "l", "l", "o"]

五、创建数组

创建数组主要有3种方法,但也还可以借用转换成数组的方法生成数组:

1. 字面量法
var = [1, 2, 3]; // 最直接也最容易的方法
2. new构造函数法

用Array构造函数来生成数组实例,可以接受多个参数作为数组元素,当只有一个参数是表示数组长度。

var arr1 = new Array(1, 2, 3); // [1, 2, 3]
var arr2 = new Array(3); // [empty × 3] 即 [ , , ]
var arr3 = new Array('3'); // ["3"]
3. Array.of()

可以看到,上面的new构造法当只传一个数值元素的时候,会把他当做数组的长度,这样就没法生成一个只有一个数值元素的数组了,所以ES6有了Array.of()来统一都把参数都当做元素。

var arr1 = Array.of(1, 2, 3); // [1, 2, 3]
var arr2 = Array.of(3); // [3]
var arr3 = Array.of('3'); // ["3"]
4. 转数组法

如果想指定生成多少个元素的数组,还可以借助Array.from()Array.apply()等转换数组的方法,可以创造如下只有长度的类数组对象。

Array.from({length: 3}); // [undefined, undefined, undefined]
Array.apply(null, {length: 3}); // [undefined, undefined, undefined]
[...Array(3)]; // [undefined, undefined, undefined]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容