anjia / blog

博客,积累与沉淀
106 stars 4 forks source link

数据类型 | Array #96

Open anjia opened 2 years ago

anjia commented 2 years ago

目录

anjia commented 2 years ago

一. Array 操作篇

本文将介绍 JavaScript 里 Array 的相关操作,内容包括:

  1. 构造器:Array()
  2. 静态方法
    • Array.from(), Array.of()
    • Array.isArray()
  3. 实例属性 Array.prototype.length
  4. 实例方法

1. 构造器

constructor, 构造器/构造函数

Array() 构造器用于创建 Array 对象。

let nums1 = [1, 2, 3, 4];  // 数组字面量
let nums2 = new Array(1, 2, 3, 4); // 用数组元素初始化
let nums3 = new Array(4);          // 用数组长度初始化, [0, 2^32 - 1]

console.log(nums1.length, nums1[0], nums1[3]); // 4 1 4
console.log(nums2.length, nums2[0], nums2[3]); // 4 1 4
console.log(nums3.length, nums3[0], nums3[3]); // 4 undefined undefined

// 字符串类型
let fruits1 = ['apple', 'banana', 'strawberry'];
let fruits2 = new Array('apple', 'banana', 'strawberry');
console.log(fruits1.length, fruits2.length); // 3 3

2. 静态方法

Array.from()

Array.from() 方法从类数组对象或可迭代对象创建一个新的 Array 实例。它有三个参数:

Array.from(obj, mapFn, thisArg)Array.from(obj).map(mapFn, thisArg) 的结果是一样的,只是前者不创建中间数组,且映射函数只接收两个参数 (element, index)

“不创建中间数组”对于某类数组尤其重要,比如类型数组,因为中间数组的值必然会被截断以适应合适的类型。

//========= Array-like Objects
Array.from({ length: 5 }, (item, index) => index); // [0, 1, 2, 3, 4]
(function () { return Array.from(arguments) })(11, 22, 33); // [11, 22, 33]
// nodelist
const images = document.getElementsByTagName('img');
const sources = Array.from(images, image => image.src);
const insecureSources = sources.filter(link => link.startsWith('http://'));

//========= Iterable Objects
// Array
Array.from([1, 2, 3]); // [1, 2, 3]
Array.from([1, 2, 3], x => x + x);  // [2, 4, 6]
// String
Array.from('hello');   // ['h', 'e', 'l', 'l', 'o']
// Set
const fruits = new Set(['apple', 'banana', 'strawberry', 'apple']);
fruits;             // {'apple', 'banana', 'strawberry'}
Array.from(fruits); // ['apple', 'banana', 'strawberry']
// Map
const person = new Map([['name', 'Jane'], ['age', 18], ['sex', 'female']]);
Array.from(person); // [['name', 'Jane'], ['age', 18], ['sex', 'female']]
Array.from(person.keys()); // ['name', 'age', 'sex']
Array.from(person.values()); // ['Jane', 18, 'female']

Array.of()

Array.of() 方法从可变数量的参数列表创建一个新的 Array 实例,不限参数的数量和类型。

Array.of()Array() 构造器之间的区别在于对一个整数参数的处理,比如 Array.of(3) 会创建一个只有一个元素 3 的数组,而 Array(3) 会创建一个 length 属性是 3 的空数组(这意味着一个包含 3 个空槽(slots)的数组,而不是具有实际 undefined 值的槽)。

// 不同点:单个整数时
Array.of(3); // [3]
new Array(3); // [empty × 3], array of 3 empty slots

// 多个时表现一致
new Array(1, 2, 3); // [1, 2, 3]
Array.of(1, 2, 3); // [1, 2, 3]

3. 实例属性

Array 对象的 length 属性设置或返回该数组中元素的数量,它是一个无符号的 32 位整数。

new Array(2 ** 32); // Uncaught RangeError: Invalid array length
new Array(2 ** 32 - 1); // OK

我们可以随时设置 length 属性以对数组进行扩容或缩容。

const nums = [1, 2, 3];
console.log(nums); // [1, 2, 3]

// 扩容
nums.length = 10;
console.log(nums); // [1, 2, 3, empty × 7],  empty slots

// 缩容
nums.length = 1;
console.log(nums); // [1]

Array.prototype.length 的属性描述符是:

属性描述符
value
Writable true ✔️ ️
Enumerable false
Configurable false

4. 实例方法

数组的实例方法 Array.prototype.xxx() 比较多,大约 34 个。这里对它们进行下分类,以便更好地理解和记忆。

可变函数

mutation operations, 变异/可变操作, 即会改变原数组的

方法 说明
fill() 值填充
push()
pop()
push_back 在尾部添加一个/多个元素,返回新 length
pop_back 删除最后一个元素,返回该元素
unshift()
shift()
push_front 在头部添加一个/多个元素,返回新 length
pop_front 删除第一个元素,返回该元素
sort()
reverse()
原地排序
原地反转数组元素
splice() 增/删/改

完整参数(包括可选参数):

eg1. splice()

const nums = [1, 2, 3, 4];
// 删除
nums.splice(2, 1);
console.log(nums); // [1, 2, 4]
// 替换
nums.splice(2, 1, 44);
console.log(nums); // [1, 2, 44]
// 新添加
nums.splice(2, 0, 66, 666, 6666, 66666);
console.log(nums); //  [1, 2, 66, 666, 6666, 66666, 44]
// 操作多个
nums.splice(3);
console.log(nums); // [1, 2, 66]

eg2. sort()

// 默认按字符串排序
let names = ['Jobs', 'Bob', 'Ann', 'Charl', 'David'];
names.sort(); // ['Ann', 'Bob', 'Charl', 'David', 'Jobs']
// 数字也会按字符串排(不符合预期)
let nums = [22, 0, -20, 7, -11, -9, 0, 1];
nums.sort(); // [-11, -20, -9, 0, 0, 1, 22, 7]
// 按数字排
nums.sort((a, b) => a > b ? 1 : -1); // -20, -11, -9, 0, 0, 1, 7, 22

索引/查找

方法 说明
at() 传下标索引,支持负数
includes() 传元素,返回 boolean
indexOf()
lastIndexOf()
传元素,返回第一个(最小)下标索引
传元素,返回倒数第一个(最大)下标索引
find()
findIndex()
传函数,返回满足条件的第一个元素
传函数,返回满足条件的第一个下标索引

完整参数(包括可选的):

  1. 传元素:检查每个元素是否和值相等
    • includes(searchElement, fromIndex)
    • indexOf(searchElement, fromIndex)
    • lastIndexOf(searchElement, fromIndex)
  2. 传函数:使用测试函数判断
    • 箭头函数 find((element, index, array) => { ... })
    • 回调函数 find(callbackFn, thisArg)
    • 内联函数 find(function(element, index, array) { ... }, thisArg)
let nums = [1, 2, 4, 8, 16, 32];
nums.at(-1); // 32
nums[nums.length - 1]; // 32

nums.find(x => x > 5); // 8
nums.findIndex(x => x > 5); // 3

nums.find((x, i, arr) => { console.log(x, i, arr); return x > 5; }); // 8
// 1 0 [1, 2, 4, 8, 16, 32]
// 2 1 [1, 2, 4, 8, 16, 32]
// 4 2 [1, 2, 4, 8, 16, 32]
// 8 3 [1, 2, 4, 8, 16, 32]

判定

方法 说明
some() 传测试函数,若至少有一个元素满足,则返回 true
every() 传测试函数,若每个元素都满足,则返回 true
let nums = [1, 2, 4, 8, 16, 32];
nums.some(x => x > 5); // true
nums.every(x => x % 2 === 0); // false

新数组

方法 说明
entries() key/value pairs 二维数组
keys() values 一维数组
values() keys 一维数组

新的数组迭代器

方法 说明
map() 传函数,对数组的每个元素用回调,用返回值组成一个新数组
filter() 传函数,用过滤函数返回 true 的元素们组成一个新数组
slice() 传下标,截取数组(返回浅拷贝)
参数 (start, end) 对应下标范围 [start, end)
concat()
合并两个/多个数组
参数 (value0, value1, ... , valueN)
flat()
flatMap()
let nums = [1, 2, 4, 8, 16, 32];
nums.map(x => x > 5);  // [false, false, false, false, false, true, true]
nums.map(x => x + x);  // [2, 4, 6, 8, 10, 12, 14]
nums.filter(x => x > 5); // [8, 16, 32]

其它

分类 方法/属性 说明
迭代 forEach() 传函数,为每个数组元素执行一次提供的函数
字符串 join() 将数组变成字符串,默认用字符","
toString()
toLocaleString()
字符串
localized 字符串
其它 groupBy()
groupByToMap()
传函数,根据返回值将元素分组到一个对象里
传函数,根据返回值将元素分组到 Map 里
reduce()
reduceRight()
传 reducer 函数,从左到右
传 reducer 函数,从右到左
copyWithin() 复制一系列数组元素

总结

本文简要介绍了 JavaScript 里 Array 的基本操作,旨在对其有个整体了解和感性认识。

操作 说明
构造器 Array() 创建 Array 对象
静态方法 Array.from()
Array.of()
创建一个新的 Array 实例
Array.isArray()
实例属性 Array.prototype.length 可变长数组
实例方法 fill()
push(), pop() 可模拟栈
unshift(), shift() 可模拟队列
sort(), reverse() 原地
splice() 增删改
可变操作
at()
includes()
indexOf(), lastIndexOf()
find(), findIndex()
索引/查找
some()
every()
判定
entries()
keys()
values()
返回新数组
map(), filter()
slice(), concat()
flat(), flatMap()
返回新的数组迭代器
forEach() 迭代
join()
toString()
toLocaleString()
字符串
groupBy(), groupByToMap()
reduce(), reduceRight()
copyWithin()
其它

各个方法的更多详情,可查阅其接口文档。

主要参考