乐趣区

JavaScript的数组操作

JavaScript 的数组操作

JavaScript 数组也是对象,它使用单一的变量存储一系列的值。

数组和对象的区别

在 JavaScript 中,数组必须使用数字索引,对象可以使用命名索引。
数组是特殊类型的对象,具有特有的一些属性和方法。

如何区分数组和对象

方案 1
ECMAScript5 定义新方法 Array.isArray()

var arr = [];
var obj = {};
console.log(Array.isArray(arr));
// true
console.log(Array.isArray(obj));
// false

此方案不支持老的浏览器。

方案 2

var arr = [];
console.log(Object.prototype.toString.call(arr));
// [object Array]
var obj = {};
console.log(Object.prototype.toString.call(obj));
// [object Object]

创建

使用字面量创建

var arr = [];

使用构造函数创建

var arr = new Array();
console.log(arr);
// []
arr = new Array(2);
console.log(arr);
// [empty × 2],当构造函数只传一个参数时如 2,生成一个长度为 2,都为空位的数组
arr = new Array(1, 2);
console.log(arr);
// [1, 2]

出于简洁、可读性和执行速度的考虑,建议使用第一种方法。

取值

var arr = [1, 2];
console.log(arr[1]);// 2

修改值

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

超过数组长度赋值、取值

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

删除元素

数组属于对象, 所以可以使用 delete 运算符执行删除操作

var arr = [0];
console.log(arr);
// [0]
delete arr[0];
console.log(arr);
// [empty]

元素长度 length

var arr = [1, 2];
console.log(arr.length);
// 2

for 循环遍历

var arr = [1, 2];
for (var i = 0, len = arr.length; i < len; i ++) {console.log(arr[i]);
}
// 1
// 2

for…in 循环遍历

var arr = [1, 2];
for (index in arr) {console.log(arr[index]);
}
// 1
// 2

concat()- 合并两个或多个数组

var arr1 = [1];
var arr2 = [2];
console.log(arr1.concat(arr2));
// [1, 2]
var arr = [1];
console.log(arr.concat(2, 3));
// [1, 2, 3]

不会改变原数组

join()- 将数组元素拼接成一个字符串

var arr = [1, 2];
console.log(arr.join('-'));
// 1-2

不会改变原数组

sort()- 排序

var arr = [1, 2];
console.log(arr.sort());
// [1, 2]
console.log(arr.sort((item1, item2) => {return item1 - item2;}));
// [1, 2]
console.log(arr.sort((item1, item2) => {return item2 - item1;}));
// [2, 1]
console.log(arr);
// [2, 1]

返回对数组的引用,在原数组上进行排序,不生成副本。
说明

  1. 函数中比较如果小于零,则排序结果 item1 在前,item2 在后。即 return item1 - item2 为升序,反之 return item2 - item1 为降序。所以 return 0.5 - Math.random() 可以实现随机排序。
  2. sort 也可以对文字排序,和数字排序一样,遵从 ASCII 编码的排序规则

查找最值

方案一
查找最小值(最大值同理)

var arr = [1, 2];
console.log(arr.sort(function (a, b) {return a - b;})[0]);

需要对数组进行排序,效率较低
方案二

var arr = [1, 2];
function getArrMax(arr) {return Math.max.apply(null, arr);
}
function getArrMin(arr) {return Math.min.apply(null, arr);
}
console.log(getArrMax(arr));
// 2
console.log(getArrMin(arr));
// 1

pop()- 删除并返回数组的最后一个元素

var arr = [1, 2];
console.log(arr.pop());
// 2
console.log(arr);
// [1]

会改变原数组

push()- 向数组的末尾添加一个或多个元素,并返回新的长度

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

会改变原数组
push() 方法和 pop()方法使用数组提供的先进后出栈的功能。

reverse()- 颠倒数组中元素的顺序

var arr = [1, 2];
console.log(arr.reverse());
// [2, 1]

会改变原数组

shift()- 删除数组第一个元素,并返回第一个元素的值

var arr = [1, 2];
console.log(arr.shift());
// 1
console.log(arr);
// [2]

会改变原数组

unshift()- 向数组的开头添加一个或更多元素,并返回新的长度

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

改变原有的数组

slice()- 返回选定的元素

arrayObject.slice(start,end)

start、end 都可以使用负值从数组的尾部选取元素,

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

不会改变原数组,如果需要删除数组中的一段元素,应该使用方法 Array.splice()

splice()- 从数组中添加 / 删除元素,返回被删除元素

arrayObject.splice(index,howmany,item1,.....,itemX)

howmany 如果设置为 0,则不会删除项目。

var arr = [1, 2, 3, 4, 5];
console.log(arr.splice(2, 1, 6));
// [3]
console.log(arr);
// [1, 2, 6, 4, 5]

改变原始数组。

toString()- 将数组转换为字符串

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

返回值与没有参数的 join()方法返回的字符串相同,元素之间用逗号分隔

toLocaleString()- 把数组转换为本地字符串

首先调用每个数组元素的 toLocaleString()方法,然后使用地区特定的分隔符把生成的字符串连接起来,形成一个字符串。

var arr = ['a', 'b', 'c'];
console.log(arr.toLocaleString());
// a,b,c

valueOf()- 返回 Array 对象的原始值

var arr = [1, 2];
console.log(arr.valueOf());
// [1, 2]

通常由 JavaScript 在后台自动调用,并不显式地出现在代码中。

forEach()- 为每个元素调用一次函数

var arr = [1, 2];
arr.forEach(function (item, index, arr) {console.log(item);
  console.log(index);
  console.log(arr);
});
// 1
// 0
// [1, 2]
// 2
// 1
// [1, 2]

不改变原数组

map()- 对每个元素执行函数来创建新数组

var arr = [1, 2];
console.log(arr.map(function (item, index, array) {return item * 2;}));
// [2, 4]
console.log(arr);
// [1, 2]

不改变原数组

filter()- 通过测试的元素创建新数组

var arr = [1, 2];
console.log(arr.filter(function (item, index, array) {return item > 1;}));
// [2]
console.log(arr);
// [1, 2]

不改变原数组

reduce()- 每个元素运行函数,以生成(减少它)单个值。从左到右工作

var arr = [1, 2, 3];
var sum = arr.reduce(function (total, value, index, array) {return total + value;});
console.log(sum);
// 6
console.log(arr);
// [1, 2, 3]

可以接受一个初始值

var arr = [1, 2, 3];
var sum = arr.reduce(function (total, value, index, array) {return total + value;}, 4);
console.log(sum);
// 10
console.log(arr);
// [1, 2, 3]

reduceRight()- 每个元素运行函数,以生成(减少它)单个值。从右到左工作

var arr = [1, 2, 3];
var sum = arr.reduceRight(function (total, value, index, array) {return total + value;}, 4);
console.log(sum);
// 10
console.log(arr);
// [1, 2, 3]

every()- 检查所有数组值是否通过测试

var arr = [1, 2, 3];
console.log(arr.every(function (value, index, array) {return value < 3;}));
// false

some()- 检查某些数组值是否通过测试

var arr = [1, 2, 3];
console.log(arr.some(function (value, index, array) {return value < 3;}));
// true

indexOf()- 搜索元素值并返回其位置

array.indexOf(item, start)

item 必需。要检索的项目。
start 可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到结尾。

未找到项目返回 -1。
项目多次出现,返回第一次出现的位置。

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

lastIndexOf()- 搜索元素值并返回其位置,从结尾开始搜索

array.lastIndexOf(item, start)

item 必需。要检索的项目。
start 可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到开头。

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

find()- 返回通过测试函数的第一个元素的值

var arr = [1, 2, 3];
console.log(arr.find(function (value, index, array) {return value > 1;}));
// 2

findIndex()- 返回通过测试函数的第一个元素的索引

var arr = [1, 2, 3];
console.log(arr.findIndex(function (value, index, array) {return value > 1;}));
// 1

es6 中的数组操作

Array.from()- 将类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)转为真正的数组

所谓类似数组的对象,本质特征只有一点,即必须有 length 属性。

var arrLike = {
  "0": 1,
  "1": 2,
  length: 2,
};
// ES5 的写法
console.log([].slice.call(arrLike));
// [1, 2]
// ES6 的写法
console.log(Array.from(arrLike));
// [1, 2]

只要部署了 Iterator 接口的数据结构,Array.from 都能将其转为数组,如 Set 和 Map。

var set = new Set([1, 2])
console.log(Array.from(set));
// [1, 2]

Array.from 还可以接受第二个参数,作用类似于数组的 map 方法。

var arrLike = {
  "0": 1,
  "1": 2,
  length: 2,
};
console.log(Array.from(arrLike, value => value *2));
// [2, 4]

如果 map 函数里面用到了 this 关键字,还可以传入 Array.from 的第三个参数,用来绑定 this。

var arrLike = {
  "0": 1,
  "1": 2,
  length: 2,
};
var context = {key: 1,}
console.log(Array.from(arrLike, function () {return this.key *2}, context));
// [2, 2]

Array.of()- 将一组值转换为数组

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

参数个数不同,不会有像 new Array()一样行为有差异。

Array.of()的模拟实现

function ArrayOf(){return [].slice.call(arguments);
}

Array.prototype.copyWithin()- 在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。

Array.prototype.copyWithin(target, start = 0, end = this.length)
  1. target(必需):从该位置开始替换数据。如果为负值,表示倒数。
  2. start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
  3. end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
var arr = [1, 2, 3, 4, 5];
console.log(arr.copyWithin(0, 3));
// [4, 5, 3, 4, 5]
console.log(arr);
// [4, 5, 3, 4, 5]

Array.prototype.fill()- 使用给定值,填充一个数组

arr.fill(value, start, end);
console.log([1, 2, 3].fill(4, 1, 2));
// [1, 4, 3]

Array.prototype 的 entries()、keys()和 values()

keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

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

for (let value of [1, 2].values()) {console.log(value);
}
// 1
// 2

for (let [index, value] of [1, 2].entries()) {console.log(index, value);
}
// 0 1
// 1 2

Array.prototype.includes()- 表示数组是否包含给定的值,与字符串的 includes 方法类似。

Array.prototype.includes(value, start);

该方法的第二个参数表示搜索的起始位置。

console.log([1, 2, 3].includes(3, 3));
// false
console.log([1, 2, 3].includes(3, -1));
// true

includes 不会导致对 NaN 的误判

Array.prototype.flat()- 将嵌套的数组“拉平”

console.log([1, 2, [3, 4]].flat());
// [1, 2, 3, 4]
console.log([1, 2, [3, [4, 5]]].flat(1));
// [1, 2, 3, Array(2)]
console.log([1, 2, [3, [4, 5]]].flat(2));
// [1, 2, 3, 4, 5]

flat()的参数代表“拉平”几层的嵌套数组,使用 Infinity 关键字,不管多少层嵌套,都可以转成一维数组。

Array.prototype.flatMap()- 对原数组的每个成员执行一个函数,对返回值组成的数组执行 flat()方法

arr.flatMap(function callback(currentValue, index, array) {// ...}, thisArg)
console.log([2, 3, 4].flatMap((x) => [x, x * 2]));
// [2, 4, 3, 6, 4, 8]

只能展开一层数组。

console.log([1, 2, 3, 4].flatMap(x => [[x * 2]]));
// [[2], [4], [6], [8]]

参考

  1. es6 标准入门
  2. w3school 数组相关内容

退出移动版