《JavaScript: The Definitive Guide》【读犀牛书】- 第 7 章 数组

111 阅读4分钟

【读犀牛书】是《JavaScript: The Definitive Guide》这本书个人学习笔记的汇总,目的是夯实前端 JS 基础,欢迎讨论!

前情提要

阅读本章节你会了解到以下内容:

  1. 数组介绍
  2. 创建数组的几种方式
  3. 数组如何读写
  4. 数组遍历、栈和队列的实现、增删改、搜索、排序等相关方法
  5. 数组和字符串间转换
  6. 知识扩展

1. 数组介绍

  • 数组是有序集合,其中值被称为元素,位置被称为索引。
  • 数组中元素无任何限制,可以是任意数据类型,索引从 0 开始。
  • 数组中有个 length 属性,表示数组中元素的个数,且数组的长度总是比末尾元素的索引大 1。
  • 数组的属性和方法都继承自 Array.prototype 原型。

2.创建数组的几种方式

(1)数组字面量

const empty = []
const nums = [1, 2, 3, 4]

(2)扩展运算符

const nums = [1, 2]
const arr = [1, 2, ...nums, 3, 4]    // [1, 2, 1, 2, 3, 4]

(3)Array()构造函数

const nums = new Array()    // []
const nums = new Array(2)    // [empty x 2]
const nums = new Array('hello', 'world')    // ['hello', 'world']

(4)Array.of() 和 Array.from()

const nums = Array.of(10)    // [10]
const nums = Array.of(1,2,4)    // [1, 2, 4]

const nums = Array.from('foo')    // ['f', 'o', 'o']
const nums = Array.from([1,2,3], x => x + x)    // [2, 4, 6]

3. 数组的读写

可以使用 [] 方括号对数组进行读写,一般规则是:

  • 读操作,若访问索引存在,直接读取元素;若不存在,返回 undefined;
  • 写操作,若访问索引存在,直接更新元素;若不存在,写入该元素,数组的 length 属性也会更新;

数组是一种特殊的对象,按照对象概念理解,数组的索引本质上就是属性名。不过如果索引恰好是介于 0 ~ 2^32 - 2 间的整数时,属性名就称为索引,对于数组来说行为特殊,可以对其进行读写操作。同时,数组和对象一样,当访问不到某个索引值时,或索引值为负数时,不会报错,仅返回 undefined,表示未访问到。

4. 数组遍历、栈和队列的实现、增删改、搜索、排序等相关方法

遍历:数组遍历目的一般是访问每个元素,对其调用指定的函数或逻辑

(1)for 循环

// 从前往后遍历
for(let i = 0; i < nums.length; i++) { ... }

// 从后往前遍历
for(let i = nums.length; i >= 0; i--) { ... }

(2)for...of 循环

let nums = [1, 2, 3, 4]
for(let n of nums) {
    console.log(n)    // 1 2 3 4
}

(3) forEach()

let strs = [...'hello']
let ret = ''
strs.forEach(s => {
    ret += s.toUpperCase()
})
console.log(ret)    // 'HELLO'

(4)map()

let nums = [1, 2, 4]
let newNums = nums.map(x => x*x)    // [1, 4, 16]

(5) filter()

let nums = [1, 2, undefined, 3, null, 4]
let newNums = nums.filter(x => x !== undefined && x !== null)    // [1, 2, 3, 4]

(6) find() 和 findIndex()

let nums = [1, 2, 3, 4]
nums.find(x => x > 2)    // 3
nums.find(x => x%7 === 0)    // undefined

nums.findIndex(x => x === 2) // 1
nums.findIndex(x => x < 0)    // -1

5. 数组和字符串间转换

(1)join()

将数组或类数组的所有元素,根据分隔符连接成一个字符串,分隔符默认为逗号,返回拼接好的字符串。若数组仅有一个元素,则返回该元素。(数组 -> 字符串,返回字符串)

let nums = ['h','e','l','l','o']
nums.join()    // 'a,b,c,d'
nums.join('')    // 'abcd'
nums.join('-')    // 'a-b-c-d'

(2) split()

根据指定的分隔符,将字符串分隔成一个数组,并返回该数组。(字符串 -> 数组,返回数组)

let str = 'hello world'
str.split()    // ['hello world']
str.split('')    // ['h', 'e', 'l', 'l', 'o', '', 'w', 'o', 'r', 'l', 'd']
str.split(' ')    //['hello', 'world']

6. 知识扩展

(1)数组浅拷贝,可以使用扩展运算符、Array.from()

  • 扩展运算符
let nums = [1,2,3,4]
let arr = [...nums]
arr[0] = 2
  • Array.from()
let nums = [1,2,3,4]
let arr = Array.from(nums)

(2) 数组去重,可以利用 Set 集合无重复元素的特性

let nums = [1,1,2,4,2,1,4]
let arr = [...new Set(nums)]
let arr = Array.from(new Set(nums))

(3) 稀疏数组,是指没有从 0 开始的索引的数组,或是存在值为 undefined 的元素,即不是每个元素都有值

let nums = new Array(4)

let nums = []
nums[10] = 2

let nums = [1, , 2]

(4) 数组遍历时使用 for...of 若想同时获取元素的值和索引,可以利用 entries() 方法和解构赋值

let str = [...'hello']
for(let [index, value] of str.entries()) {
    console.log(`${index}, ${value}`)
}

(5) 数组排序,期望找到最大、最小值,可以利用 reduce() 替代 sort(),时间复杂度更低

// sort()
let nums = [1,4,2,7,11,9,12,16,20,206,117]
nums.sort((a, b) => a - b)
let min = nums[0]    // 1
let max = nums[nums.length - 1]    // 206

// reduce()
let min = nums.reduce((a, b) => a <= b ? a : b)    // 1
let max = nums.reduce((a, b) => a >= b ? a : b)    // 206

(6) 判断数组中是否存在某个元素,一般使用 includes() 方法,但数组量级庞大时,建议使用 Set 集合判断


const nums = [1,2,3,4,5,6,7]
nums.includes(7)    // true

const numSet = new Set(nums)
numSet.has(7)    // true

(7) 对数组操作时,算法考虑时间空间复杂度尽量低,因此可以使用某些方法,尽量原地修改数组,如 push()、splice() 等

(8)字符串利用数组原生方法

Array.prototype.join.call('javascript', '-')    // 'j-a-v-a-s-c-r-i-p-t'

👏 其他章节不定期更新,敬请期待!