JavaScript数组(ES6)

3 Aug

JavaScript数组一篇中介绍了ES6之前的数组方法。本篇介绍一下ES6里新增的数组方法。

  • find,findIndex,includes
  • fill,copyWithin
  • keys,values,entries
  • 静态方法(from,of)

find,findIndex,includes

find用于找元素,返回第一个满足条件的元素,找不到就返回undefined。函数声明:[].find( function(value, index, array) { … }, [thisArg] );。参照MDN

第一个参数是回调函数,它支持3个参数,第1个是遍历的数组内容,第2个是对应索引,第3个是数组自身。第二个参数thisArg可选,可用于以改变回调函数里面的this指针

var count = [1, 5, 10, 15].find(function(value, index, arr) {
    return value > 9;
});
console.log(count); 	//10

findIndex用于找元素,返回第一个满足条件的元素的位置,找不到就返回-1。函数声明:[].findIndex( function(value, index, array) { … }, [thisArg] );,和上面find一样,不赘述。参照MDN

var idx = [1, 5, 10, 15].findIndex(function(value, index, arr) {
    return value > 9;
});
console.log(idx);   //2

这两个方法都可以发现NaN,弥补了之前indexOf方法的不足。indexOf方法无法识别数组的NaN元素,但findIndex方法可以借助Object.is方法做到:

var idx1 = [NaN].indexOf(NaN);
console.log(idx1);      //-1
var idx2 = [NaN].findIndex(y => Object.is(NaN, y));
console.log(idx2);      //0

includes用于找元素,找到返回true,找不到返回false。函数声明:[].includes(el, [start]);。参照MDN

第一个参数是查找的元素。第二个参数可选,表示开始查找的位置,不指定的话默认为0,指定为负数,表示倒着数。

[1, 2, 3].includes(2);     	// true
[1, 2, 3].includes(4);     	// false
[1, 2, 3].includes(3, 3);  	// false
[1, 2, 3].includes(3, -1); 	// true
[1, 2, NaN].includes(NaN); 	// true

以前要看数组中是否包含某元素用indexOf:if (arr.indexOf(el) !== -1) { … }。除了感觉有点不自然外,也无法判断是否包含NaN。现在用includes就没这些问题了。

fill,copyWithin

fill用于填充当前数组,返回填充后的数组。函数声明:[].fill(value, [start, [end]]);。参照MDN

第一个参数是填充的元素,后两个参数可选,start是起始填充位置,不指定的话默认为0。end是填充到哪个位置之前结束,不指定的话默认到数组尾。位置可以指定负数,表示倒着数。

var arr = [1, 2, 3];
console.log(arr.fill(4));	    // [4, 4, 4]
console.log(arr.fill(4, 1));	    // [1, 4, 4]
console.log(arr.fill(4, 1, 2));	    // [1, 4, 3]
console.log(arr.fill(4, -3, -2));   // [4, 2, 3]

用上面第一行例子,即单个参数,来初始化数组非常方便,数组中原有元素将全部被抹去。

copyWithin和fill很像,它用于将数组指定位置的元素复制到其他位置(会覆盖原来该位置的元素),最后返回修改后的数组。函数声明:[].copyWithin(target, [start, [end]]);。参照MDN

第一个参数和fill有区别,是从该位置开始替换元素。后两个参数参照fill,不赘述

var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(arr.copyWithin(0, 3));   // ['d', 'e', 'f', 'd', 'e', 'f']

表示将从index为3开始直到数组结束的成员(即def)读取出来,替换从0号位开始的元素(即覆盖了abc)。

再看一个负数的例子:

var arr1 = [1, 2, 3, 4, 5];
console.log(arr1.copyWithin(-2, -3, -1));  // [1, 2, 3, 3, 4]

从倒数3位开始直到倒数1位(即34)读取出来,替换倒数2位(即覆盖了45)

keys,values,entries

这3个方法都用于遍历数组。都返回一个遍历器对象,可以用for…of循环进行遍历。区别是keys是对key的遍历,values是value的遍历,entries是对key-value的遍历。

函数声明都非常简单,一个参数都没有,分别是:[].keys();,[].values();,[].entries();。参照MDN

for (let index of ['a', 'b'].keys()) {
    console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
    console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
    console.log(index, elem);
}
// 0 "a"
// 1 "b"

因为返回的是遍历器对象,因此除了for…of循环外,也可以手动调用遍历器对象的next方法来遍历:

var arr = ['a', 'b', 'c'];
var eArr = arr.entries();
console.log(eArr.next().value);   // [0, 'a']
console.log(eArr.next().value);   // [1, 'b']
console.log(eArr.next().value);   // [2, 'c']

静态方法(from,of)

JavaScript数组一篇中介绍了ES6之前的数组方法,包括本篇上面所有Array的方法的函数声明都用了“[].方法名”的形式,等价于“Array.prototype.方法”,表示它们都是Array的实例方法。

但form和of的函数声明用了“Array.方法名”的形式,表示它们是Array的静态方法。(关于JS静态可以参照这里

from用于将类数组对象转为真正的数组。函数声明:Array.from(arrayLike, [mapFn, [thisArg]]);。参照MDN

第一个参数自然就是类数组对象。第二个参数作用类似于map,还可以为map指定this。有关类数组对象和map方法请参照JavaScript数组,不赘述。

现在用ES6的from方法来重写JavaScript数组一篇中的类数组对象中的例子:

处理arguments对象:

//ES5处理arguments对象:
var args = [].slice.call(arguments);

//ES6用from
var args = Array.from(arguments);

处理HTMLCollection对象:

//ES5用forEach遍历页面所有div,输入className
var divs = document.getElementsByTagName("div");
Array.prototype.forEach.call(divs, function(div) {	
    console.log("该div类名是:" + (div.className || "空"));
});

// ES6用from
Array.from(divs).forEach(function (div) {
    console.log("该div类名是:" + (div.className || "空"));
});

处理字面量对象:

//ES5
var arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };
var result = Array.prototype.map.call(arrayLike, function(s) {
    return s.toUpperCase();
});     
console.log(result);    //["A", "B", "C"]

//ES6
var result = Array.from(arrayLike, s => s.toUpperCase());   
console.log(result);    //["A", "B", "C"]

上面from用了第二个参数,该语句等价于Array.from(arrayLike).map(s => s.toUpperCase());

处理字符串:

//ES5
var result = Array.prototype.map.call("abc", function(s) {
    return s.toUpperCase();
});
console.log(result);    //["A", "B", "C"]

//ES6
var result = Array.from("abc", s => s.toUpperCase());     
console.log(result);    //["A", "B", "C"]

of作用和from类似,用于将一组值,转换为数组。函数声明:Array.of(el0, [el1, … , elN]);。参照MDN

和from一样, 同样是Array的静态方法,你无法用数组对象调用of方法。

console.log(Array.of(1,2,3)); 	// [1, 2, 3]

你可能会很疑惑,直接var arr = new Array(1,2,3);不就行了,要of方法有什么用?如果只有1个参数就有区别了:

//只有1个参数的普通构造函数
var arr1 = new Array(3);
console.log(arr1);	// [, , ,]

//ES6用of就和上面有区别了
var arr2 = Array.of(3);
console.log(arr2);	// [3]

可以看出用of的话,可以完全替代构造函数,避免了单个参数导致的非常微妙的区别。它总是能返回一个数组,如果没有参数,就返回空数组[]

Leave a Reply

Your email address will not be published. Required fields are marked *