Array对象

67次阅读

共计 5885 个字符,预计需要花费 15 分钟才能阅读完成。

Array 对象

构造函数
静态方法
Array.isArray()
实例方法
valueOf(),toString()
push(),pop()
shift(),unshift()
join(分隔符) 返回字符串
concat() 新的
reverse()
slice(头尾) 新的
splice(头,长,增) 增(头,0,增)拆成两个(头)返回删除的
sort()
map() 新的 this
forEach()不返回 this
filter()新的 返回 ture 的
some(),every() 新的 返 turee false
reduce(),reduceRight()新的
indexOf(),lastIndexOf() 新的

链式使用

1. 构造函数
Array 构造函数有一个很大的缺陷,就是不同的参数,会导致它的行为不一致。

// 无参数时,返回一个空数组
new Array() // []

// 单个正整数参数,表示返回的新数组的长度
new Array(1) // [empty]
new Array(2) // [empty x 2]

// 非正整数的数值作为参数,会报错
new Array(3.2) // RangeError: Invalid array length
new Array(-3) // RangeError: Invalid array length

// 单个非数值(比如字符串、布尔值、对象等)作为参数,
// 则该参数是返回的新数组的成员
new Array(‘abc’) // [‘abc’]
new Array([1]) // [Array[1]]

// 多参数时,所有参数都是返回的新数组的成员
new Array(1, 2) // [1, 2]
new Array(‘a’, ‘b’, ‘c’) // [‘a’, ‘b’, ‘c’]

// bad
var arr = new Array(1, 2);

// good
var arr = [1, 2];

var a = new Array(3);
var b = [undefined, undefined, undefined];

a.length // 3
b.length // 3

a[0] // undefined
b[0] // undefined

0 in a // false
0 in b // true

2. 静态方法
Array.isArray()
var arr = [1, 2, 3];

typeof arr // “object”
Array.isArray(arr) // true

3. 实例方法
3.1valueOf() 原数组,toString()字符串
3.2push(),pop() 改
3.3shift(),unshift() 改
shift()方法可以遍历并清空一个数组。

var list = [1, 2, 3, 4];
var item;

while (item = list.shift()) {
console.log(item);
}

list // []
上面代码通过 list.shift()方法每次取出一个元素,从而遍历数组。它的前提是数组元素不能是 0 或任何布尔值等于 false 的元素,因此这样的遍历不是很可靠

3.4join(分隔符)字符串
如果数组成员是 undefined 或 null 或空位,会被转成空字符串。

[undefined, null].join(‘#’)
// ‘#’

[‘a’,, ‘b’].join(‘-‘)
// ‘a–b’
通过 call 方法,这个方法也可以用于字符串或类似数组的对象。

Array.prototype.join.call(‘hello’, ‘-‘)
// “h-e-l-l-o”

var obj = {0: ‘a’, 1: ‘b’, length: 2};
Array.prototype.join.call(obj, ‘-‘)
// ‘a-b’

3.5concat()新
concat 方法返回当前数组的一个浅拷贝。所谓“浅拷贝”,指的是新数组拷贝的是对象的引用。

var obj = {a: 1};
var oldArray = [obj];

var newArray = oldArray.concat();

obj.a = 2;
newArray[0].a // 2
上面代码中,原数组包含一个对象,concat 方法生成的新数组包含这个对象的引用。所以,改变原对象以后,新数组跟着改变

3.6reverse()改
3.7slice(头,尾) 新
slice 方法的一个重要应用,是将类似数组的对象转为真正的数组。

Array.prototype.slice.call({0: ‘a’, 1: ‘b’, length: 2})
// [‘a’, ‘b’]

Array.prototype.slice.call(document.querySelectorAll(“div”));
Array.prototype.slice.call(arguments);

3.8splice(头,长,增) 只插入(头,0,增)
起始位置如果是负数,就表示从倒数位置开始删除。

var a = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’];
a.splice(-4, 2) // [“c”, “d”]
上面代码表示,从倒数第四个位置 c 开始删除两个成员。

如果只是单纯地插入元素,splice 方法的第二个参数可以设为 0。

var a = [1, 1, 1];

a.splice(1, 0, 2) // []
a // [1, 2, 1, 1]
如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。

var a = [1, 2, 3, 4];
a.splice(2) // [3, 4]
a // [1, 2]

3.9sort()改
数值会被先转成字符串,再按照字典顺序进行比较,所以 101 排在 11 的前面。

如果想让 sort 方法按照自定义方式排序,可以传入一个函数作为参数。

[10111, 1101, 111].sort(function (a, b) {
return a – b;
})
// [111, 1101, 10111]
上面代码中,sort 的参数函数本身接受两个参数,表示进行比较的两个数组成员。如果该函数的返回值大于 0,表示第一个成员排在第二个成员后面;其他情况下,都是第一个元素排在第二个元素前面。

[
{name: “ 张三 ”, age: 30},
{name: “ 李四 ”, age: 24},
{name: “ 王五 ”, age: 28}
].sort(function (o1, o2) {
return o1.age – o2.age;
})
// [
// {name: “ 李四 ”, age: 24},
// {name: “ 王五 ”, age: 28},
// {name: “ 张三 ”, age: 30}
// ]

3.10map()新
[1, 2, 3].map(function(elem, index, arr) {
return elem * index;
});
// [0, 2, 6]
上面代码中,map 方法的回调函数有三个参数,elem 为当前成员的值,index 为当前成员的位置,arr 为原数组([1, 2, 3])。

map 方法还可以接受第二个参数,用来绑定回调函数内部的 this 变量(详见《this 变量》一章)。

var arr = [‘a’, ‘b’, ‘c’];

[1, 2].map(function (e) {
return this[e];
}, arr)
// [‘b’, ‘c’]
上面代码通过 map 方法的第二个参数,将回调函数内部的 this 对象,指向 arr 数组。

如果数组有空位,map 方法的回调函数在这个位置不会执行,会跳过数组的空位。

var f = function (n) {return ‘a’};

[1, undefined, 2].map(f) // [“a”, “a”, “a”]
[1, null, 2].map(f) // [“a”, “a”, “a”]
[1, , 2].map(f) // [“a”, , “a”]
上面代码中,map 方法不会跳过 undefined 和 null,但是会跳过空位。

3.11forEach()
forEach 方法不返回值,只用来操作数据。这就是说,如果数组遍历的目的是为了得到返回值,那么使用 map 方法,否则使用 forEach 方法

function log(element, index, array) {
console.log(‘[‘ + index + ‘] = ‘ + element);
}

[2, 5, 9].forEach(log);
// [0] = 2
// [1] = 5
// [2] = 9

forEach 方法也可以接受第二个参数,绑定参数函数的 this 变量。

var out = [];

[1, 2, 3].forEach(function(elem) {
this.push(elem * elem);
}, out);

out // [1, 4, 9]
上面代码中,空数组 out 是 forEach 方法的第二个参数,结果,回调函数内部的 this 关键字就指向 out。

forEach 方法也会跳过数组的空位。

var log = function (n) {
console.log(n + 1);
};

[1, undefined, 2].forEach(log)
// 2
// NaN
// 3

[1, null, 2].forEach(log)
// 2
// 1
// 3

[1, , 2].forEach(log)
// 2
// 3

3.12filter()
[1, 2, 3, 4, 5].filter(function (elem) {
return (elem > 3);
})
// [4, 5]
上面代码将大于 3 的数组成员,作为一个新数组返回。

var arr = [0, 1, ‘a’, false];

arr.filter(Boolean)
// [1, “a”]
上面代码中,filter 方法返回数组 arr 里面所有布尔值为 true 的成员

[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
return index % 2 === 0;
});
// [1, 3, 5]

filter 方法还可以接受第二个参数,用来绑定参数函数内部的 this 变量。

var obj = {MAX: 3};
var myFilter = function (item) {
if (item > this.MAX) return true;
};

var arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj) // [8, 4, 9
3.13some(),every()
判断数组成员是否符合某种条件
some 方法是只要一个成员的返回值是 true,则整个 some 方法的返回值就是 true,否则返回 false
var arr = [1, 2, 3, 4, 5];
arr.some(function (elem, index, arr) {
return elem >= 3;
});
// true
上面代码中,如果数组 arr 有一个成员大于等于 3,some 方法就返回 true。

every 方法是所有成员的返回值都是 true,整个 every 方法才返回 true,否则返回 false。

var arr = [1, 2, 3, 4, 5];
arr.every(function (elem, index, arr) {
return elem >= 3;
});
// false
上面代码中,数组 arr 并非所有成员大于等于 3,所以返回 false。

注意,对于空数组,some 方法返回 false,every 方法返回 true,回调函数都不会执行。

function isEven(x) {return x % 2 === 0}

[].some(isEven) // false
[].every(isEven) // true
some 和 every 方法还可以接受第二个参数,用来绑定参数函数内部的 this 变量。
3.14reduce(),reduceRight()
reduce 方法和 reduceRight 方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce 是从左到右处理(从第一个成员到最后一个成员),reduceRight 则是从右到左(从最后一个成员到第一个成员),其他完全一样。
[1, 2, 3, 4, 5].reduce(function (a, b) {
console.log(a, b);
return a + b;
})
// 1 2
// 3 3
// 6 4
// 10 5
// 最后结果:15
上面代码中,reduce 方法求出数组所有成员的和。第一次执行,a 是数组的第一个成员 1,b 是数组的第二个成员 2。第二次执行,a 为上一轮的返回值 3,b 为第三个成员 3。第三次执行,a 为上一轮的返回值 6,b 为第四个成员 4。第四次执行,a 为上一轮返回值 10,b 为第五个成员 5。至此所有成员遍历完成,整个方法的返回值就是最后一轮的返回值 15。

reduce 方法和 reduceRight 方法的第一个参数都是一个函数。该函数接受以下四个参数。

累积变量,默认为数组的第一个成员
当前变量,默认为数组的第二个成员
当前位置(从 0 开始)
原数组
这四个参数之中,只有前两个是必须的,后两个则

如果要对累积变量指定初值,可以把它放在 reduce 方法和 reduceRight 方法的第二个参数。

[1, 2, 3, 4, 5].reduce(function (a, b) {
return a + b;
}, 10);
// 25
上面代码指定参数 a 的初值为 10,所以数组从 10 开始累加,最终结果为 25。注意,这时 b 是从数组的第一个成员开始遍历

上面的第二个参数相当于设定了默认值,处理空数组时尤其有用。

function add(prev, cur) {
return prev + cur;
}

[].reduce(add)
// TypeError: Reduce of empty array with no initial value
[].reduce(add, 1)
// 1
上面代码中,由于空数组取不到初始值,reduce 方法会报错。这时,加上第二个参数,就能保证总是会返回一个值

下面是一个 reduceRight 方法的例子。

function subtract(prev, cur) {
return prev – cur;
}

[3, 2, 1].reduce(subtract) // 0
[3, 2, 1].reduceRight(subtract) // -4
上面代码中,reduce 方法相当于 3 减去 2 再减去 1,reduceRight 方法相当于 1 减去 2 再减去 3。

由于这两个方法会遍历数组,所以实际上还可以用来做一些遍历相关的操作。比如,找出字符长度最长的数组成员。

function findLongest(entries) {
return entries.reduce(function (longest, entry) {

return entry.length > longest.length ? entry : longest;

}, ”);
}

findLongest([‘aaa’, ‘bb’, ‘c’]) // “aaa”
上面代码中,reduce 的参数函数会将字符长度较长的那个数组成员,作为累积值。这导致遍历所有成员之后,累积值就是字符长度最长的那个成员。

3.15indexOf(),lastIndexOf()
3.16 链式使用

正文完
 0