《javascript高级程序设计》学习笔记 | 6.2.Array
Posted 小讴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《javascript高级程序设计》学习笔记 | 6.2.Array相关的知识,希望对你有一定的参考价值。
关注前端小讴,阅读更多原创技术文章
Array
- ECMAScript 的数组是一组有序的数据(和其他语言相同),每个槽位可以存储任意类型的数据(和其他语言不同)
- ECMAScript 的数组是动态大小的,随着数据添加而自动增长
相关代码 →
创建数组
使用 Array 构造函数
let colors = new Array() console.log(colors) // []
- 给构造函数传入一个参数:若参数是数值,则 length 属性会被自动创建并设置为这个值;若参数不是数值,则创建只包含该参数的数组
colors = new Array(10) console.log(colors) // [ <10 empty items> ] colors = new Array(true) console.log(colors) // [ true ]
- 给构造函数传入多个参数,会自动创建包含这些参数的数组
colors = new Array(\'red\', \'blue\') console.log(colors) // [ \'red\', \'blue\' ]
- 可以省略 new 操作符,结果不变
colors = Array(5) console.log(colors) // [ <5 empty items> ]
- 使用数组字面量表示法(同对象字面量表示法,使用数组字面量表示法创建数组时,不会调用 Array 构造函数)
colors = [\'red\', \'blue\', 3]
colors = []
ES6 新增
Array.from()
,将类数组结构转换为数组实例- 第一个参数是一个类数组对象,即任何可迭代结构或者包含 length 属性和可索引元素的结构
console.log(Array.from(\'Matt\')) // [ \'M\', \'a\', \'t\', \'t\' ],字符串被拆分为单字符数组 console.log(Array.from(new Map().set(1, 2).set(3, 4))) // [ [ 1, 2 ], [ 3, 4 ] ],集合和映射转换为数组 console.log(Array.from(new Set().add(1).add(2).add(3).add(4))) // [ 1, 2, 3, 4 ],集合和映射转换为数组 const a1 = [1, 2, 3, 4] const a2 = Array.from(a1) // 浅拷贝,a2与a1引用不同的基对象 console.log(a2) // [ 1, 2, 3, 4 ] console.log(a1 === a2) // false const a3 = a1 // a3与a1引用同一个基对象 console.log(a1 === a3) // true const iter = { *[Symbol.iterator]() { yield 1 yield 2 yield 3 yield 4 }, } console.log(Array.from(iter)) // [ 1, 2, 3, 4 ],可迭代对象转换为数组 function getColors() { console.log(Array.prototype.slice.call(arguments)) // [ \'red\', \'blue\' ],将argumens对象转换为数组 console.log(Array.from(arguments)) // [ \'red\', \'blue\' ],将argumens对象转换为数组 } getColors(\'red\', \'blue\') const arrayLikeObject = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4, } console.log(Array.from(arrayLikeObject)) // [ 1, 2, 3, 4 ],带有必要属性的自定义对象转换为数组
- 第二个可选参数是一个映射函数,可直接增强新数组的值
const a4 = Array.from( a1, (x) => x + 2 // 第二个可选参数:映射函数,增强数组 ) // 增强新数组a4的值 console.log(a4) // [ 3, 4, 5, 6 ]
- 第三个可选参数是一个对象,用于指定映射函数中 this 的值,此时映射函数不要用箭头函数
const a5 = Array.from( a1, function (x) { console.log(this) // { exponent: 2 },第三个参数中指定this的值,此时不可用箭头函数 return x ** this.exponent }, { exponent: 2 } // 第三个可选参数:指定映射函数中this的值 ) console.log(a5) // [ 1, 4, 9, 16 ] const a6 = Array.from(a1, (x) => x ** this.exponent, { exponent: 2 }) // 如使用箭头函数 console.log(a6) // [ NaN, NaN, NaN, NaN ] const a7 = Array.from(a1, (x) => this, { exponent: 2 }) // 因为用箭头函数,this的值是空对象 console.log(a7) // [ {}, {}, {}, {} ]
- ES6 新增
Array.of()
,将一组参数转换为数组
console.log(Array.of(1, 2, 3, 4)) // [ 1, 2, 3, 4 ],将参数转换为数组
console.log(Array.of(undefined, null)) // [ undefined, null ],将参数转换为数组
创建数组 | 语法 | 参数 |
---|---|---|
构造函数 | let arr = new Array(3) | 单个数值/单个非数值/多个 |
数组字面量 | let arr = [\'red\',\'blue\'] | |
Array.from() | Array.from(\'Matt\') | ① 类数组对象 ② 映射函数 ③ 指定映射函数 this 值的对象 |
Array.of() | Array.of(1, 2, 3, 4) | 一组参数 |
数组空位
- 使用数组字面量初始化数组时,可以使用一串逗号来创建空位
let options = [, , , , ,] // 创建包含5个元素的数组
console.log(options.length) // 5
console.log(options) // [ <5 empty items> ]
- 与之前的版本不同,ES6 新增的方法普遍将这些空位当成 undefined 元素
options = [1, , , , 5]
console.log(options) // [ 1, <3 empty items>, 5 ]
// es6的for-of语句
for (const option of options) {
console.log(option === undefined)
/*
false
true
true
true
false
*/
}
// es6的for-of语句+entries()方法
for (const [index, value] of options.entries()) {
console.log(value)
/*
1
undefined
undefined
undefined
5
*/
}
console.log([, , ,]) // [ <3 empty items> ]
// es6的Array.from()方法
console.log(Array.from([, , ,])) // [ undefined, undefined, undefined ]
// es6的Array.of()方法
console.log(Array.of(...[, , ,])) // [(undefined, undefined, undefined)]
- ES6 之前的方法会忽略这个空位,但具体行为也因方法而已
console.log(options.map(() => 6)) // [ 6, <3 empty items>, 6 ],map会跳过空位置
console.log(options.join(\'-\')) // \'1----5\',join视空位置为空字符串
- 由于行为不一致且存在性能隐患,实践中尽量避免使用数组空位,如确实需要,可以显示地用 undefined 代替
数组索引
使用中括号并提供相应值的数字索引,可取得或设置数组的值
- 索引小于数组包含的元素数,则返回存储在相应位置的元素
- 索引大于等于包含的元素书,则数组长度自动扩展到该索引值加 1(若中间还有元素,则自动用 undefined 填充)
colors = [\'red\', \'blue\', \'green\']
console.log(colors[0]) // \'red\',数组第1项
colors[2] = \'black\' // 设置数组第3项,重设数组原有的值
console.log(colors) // [ \'red\', \'blue\', \'black\' ]
colors[3] = \'brown\' // 设置数组第4项,扩展数组
console.log(colors) // [ \'red\', \'blue\', \'black\', \'brown\' ]
- 数组中元素的数量保存在
length
属性中,始终返回 0 或大于 0 的值
console.log(colors.length) // 4,数组的长度是4
通过修改数组的
length
属性,可以从数组末尾删除或添加元素- 将
length
值设置为小于数组元素数的值,则只保留数组前length
位元素,剩余的末尾元素将被删除 - 将
length
值设置为大于数组元素数的值,则新添加的元素都将以undefined
填充
- 将
colors.length = 3 // 将数组的长度设置为3,自动删除末尾\'brown\'
console.log(colors[3]) // undefined
colors.length = 5 // 将数组长度设置为5,新添加的元素以undefined填充
console.log(colors[5]) // undefined
- 使用
length
属性可以方便地向数组末尾添加元素
colors = [\'red\', \'blue\', \'green\']
colors[colors.length] = \'black\' // 向数组末尾添加\'black\'
colors[colors.length] = \'brown\' // 向数组末尾添加\'brown\'
console.log(colors) // [ \'red\', \'blue\', \'green\', \'black\', \'brown\' ]
检测数组
检测数组 | 适用情况 |
---|---|
instanceof | 只有一个全局作用域(只有一个网页/没有额外的 iframe) |
Array.isArray() | 任何时候(不用考虑在哪个全局上下文),首选 |
迭代器方法
ES6 在 Array 原型上暴露了 3 个检索数组内容的方法:
keys()
、values()
、entries()
keys()
返回数组索引的迭代器values()
返回数组元素的迭代器entries()
返回索引/值对的迭代器
colors = [\'red\', \'blue\', \'green\']
console.log(Array.from(colors.keys())) // [ 0, 1, 2 ]
console.log(Array.from(colors.values())) // [ \'red\', \'blue\', \'green\' ]
console.log(Array.from(colors.entries())) // [ [ 0, \'red\' ], [ 1, \'blue\' ], [ 2, \'green\' ] ]
- 使用 ES6 的解构,在循环中拆分键/值对
for (const [i, el] of colors.entries()) {
console.log(i)
console.log(el)
/*
0
red
1
blue
2
green
*/
}
迭代器方法 | 返回值 |
---|---|
keys() | 数组索引的迭代器 |
values() | 数组元素的迭代器 |
entries() | 索引/值对的迭代器 |
复制和填充方法
ES6 新增填充数组方法
fill()
,在指定范围内(包含开始索引,不包含结束索引),向已有数组中插入全部或部分相同的值,不改变原数组大小- 参数一:要插入的值,非必填,若不填自动转为 undefined
- 参数二:开始索引(包含),非必填,若不填则全部填充;若负数则想象成数组长度加上这个值
- 参数三:结束索引(不包含),非必填,若不填则一直填充到数组末尾;若负数则想象成数组长度加上这个值
let zeros = [0, 0, 0, 0, 0]
zeros.fill(5) // 用5填充整个数组,省略了开始索引和结束索引
console.log(zeros) // [ 5, 5, 5, 5, 5 ]
zeros.fill(0) // 重置
zeros.fill(6, 3) // 用6填充索引大于等于3的元素,省略了结束索引
console.log(zeros) // [ 0, 0, 0, 6, 6 ]
zeros.fill(0) // 重置
zeros.fill(7, 1, 3) // 用7填充索引值大于等于1且小于3的元素
console.log(zeros) // [ 0, 7, 7, 0, 0 ]
zeros.fill(0) // 重置
zeros.fill(8, -4, 3) // 相当于zeros.fill(8, 5-4, 3),用8填充索引值大于等于1且小于3的元素
console.log(zeros) // [ 0, 8, 8, 0, 0 ]
zeros.fill(0) // 重置
fill()
静默忽略:超出数组边界、零长度、索引范围方向相反,若索引部分可用则填充可用部分
zeros.fill(1, -10, -6) // 相当于zeros.fill(1, 5-10, 5-6),超出数组边界,忽略
console.log(zeros) // [ 0, 0, 0, 0, 0 ]
zeros.fill(0) // 重置
zeros.fill(1, 10, 15) // 超出数组边界,忽略
console.log(zeros) // [ 0, 0, 0, 0, 0 ]
zeros.fill(0) // 重置
zeros.fill(2, 4, 2) // 索引反向,忽略
console.log(zeros) // [ 0, 0, 0, 0, 0 ]
zeros.fill(0) // 重置
zeros.fill(4, 3, 10) // 索引部分可用,填充可用部分
console.log(zeros) // [ 0, 0, 0, 4, 4 ]
zeros.fill(0) // 重置
ES6 新增批量复制方法
copyWithin()
,在指定范围内(包含开始索引,不包含结束索引),浅复制数组中的部分内容,并将复制内容从指定索引开始替换,不改变原数组大小- 参数一:从该索引开始替换,必填
- 参数二:开始索引(包含),非必填,若不填则默认为 0;若负数则想象成数组长度加上这个值
- 参数三:结束索引(不包含),非必填,若不填则一直填充到数组末尾;若负数则想象成数组长度加上这个值
zeros = [1, 2, 3, 4, 5]
zeros.copyWithin(2) // 浅复制整个数组,从索引为2开始替换(直到数组边界),省略了开始索引和结束索引
console.log(zeros) // [ 1, 2, 1, 2, 3 ]
zeros = [1, 2, 3, 4, 5] // 重置
zeros.copyWithin(4, 3) // 浅复制索引大于等于3到数组结束的元素,从索引为4开始替换(直到数组边界),省略了结束索引
console.log(zeros) // [ 1, 2, 3, 4, 4 ]
zeros = [1, 2, 3, 4, 5] // 重置
zeros.copyWithin(3, 1, 3) // 浅复制索引大于等于1且小于3的元素,从索引为3开始替换(直到数组边界)
console.log(zeros) // [ 1, 2, 3, 2, 3 ]
zeros = [1, 2, 3, 4, 5] // 重置
zeros.copyWithin(2, -4, -1) // 相当于zeros.copyWithin(2, 5-4, 5-1),浅复制索引大于等于1且小于4的元素,从索引为2开始替换(直到数组边界)
console.log(zeros) // [ 1, 2, 2, 3, 4 ]
zeros = [1, 2, 3, 4, 5] // 重置
- 同
fill()
,copyWithin()
也会静默忽略:超出数组边界、零长度、索引范围方向相反,若索引部分可用则填充可用部分
zeros.copyWithin(2, -15, -12) // 相当于zeros.copyWithin(2, 5-15, 5-12),超出数组边界,忽略
console.log(zeros) // [ 1, 2, 3, 4, 5 ]
zeros = [1, 2, 3, 4, 5] // 重置
zeros.copyWithin(2, 12, 15) // 超出数组边界,忽略
console.log(zeros) // [ 1, 2, 3, 4, 5 ]
zeros = [1, 2, 3, 4, 5] // 重置
zeros.copyWithin(2, 3, 1) // 索引反向,忽略
console.log(zeros) // [ 1, 2, 3, 4, 5 ]
zeros = [1, 2, 3, 4, 5] // 重置
zeros.copyWithin(2, 3, 6) // 索引部分可用,填充可用部分
console.log(zeros) // [ 1, 2, 4, 5, 5 ]
zeros = [1, 2, 3, 4, 5] // 重置
复制和填充数组 | 含义 | 参数 |
---|---|---|
fill() | 指定范围内向数组插入相同的值 | ① 要插入的值 ② 开始索引(包含) ③ 结束索引(不包含) |
copyWithin() | 浅复制数组指定范围内容,从指定索引开始替换 | ① 从该索引开始替换 ② 开始索引(包含) ③ 结束索引(不包含) |
转换方法
所有对象都有
toLocaleString()
、toString()
和valueOf()
方法:valueOf()
返回数组本身toString()
对数组每个值调用其toString()
方法,返回由逗号分隔拼接而成的字符串toLocaleString()
对数组每个值调用其toLocaleString()
方法,返回由逗号分隔拼接而成的字符串
colors = [\'red\', \'blue\', \'green\']
console.log(colors) // [ \'red\', \'blue\', \'green\' ]
console.log(colors.valueOf()) // [ \'red\', \'blue\', \'green\' ]
console.log(colors.toString()) // red,blue,green
console.log(colors.toLocaleString()) // red,blue,green
// toLocaleString() vs toString()
let person1 = {
toLocaleString() {
return \'Nikalaos\'
},
toString() {
return \'Nicholas\'
},
}
let person2 = {
toLocaleString() {
return \'Grigorios\'
},
toString() {
return \'Greg\'
},
}
let people = [person1, person2]
console.log(people.toString()) // Nicholas,Greg
console.log(people.toLocaleString()) // Nikalaos,Grigorios
join()
对数组每个值调用其toString()
方法,接收一个参数作为设定数组返回拼接字符串的分隔符
console.log(colors.join()) // red,blue,green,默认用逗号拼接
console.log(colors.join(undefined)) // red,blue,green,默认用逗号拼接
console.log(colors.join(\'|\')) // red|blue|green
console.log([undefined, 1, 2].join()) // ,1,2
数组转换 | 返回 | 参数 |
---|---|---|
valueOf() | 数组本身 | |
toString() | 对每个值调用toString() ,返回逗号拼接的字符串 | |
toLocaleString() | 对每个值调用toLocaleString() ,返回逗号拼接的字符串 | |
join() | 对每个值调用toString() ,返回指定分隔符拼接的字符串 | 指定分隔符 |
设定数组返回拼接字符串的分隔符
栈方法
- 栈是后进先出的结构,数据项的插入(push)和删除(pop)只在栈顶发生,ECMAScript 数组提供了
push()
和pop()
方法,以实现类似栈的行为 push()
方法接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度
colors = new Array()
console.log(colors.push(\'red\', \'blue\')) //2,返回数组的长度
pop()
方法用于删除数组的最后一项,返回被删除的项
console.log(colors.pop()) // \'blue\',返回被删除的项
栈方法 | 操作 | 返回 | 参数 |
---|---|---|---|
push() | 数组末尾添加项 | 数组的最新长度 | 要添加的项 |
pop() | 删除数组最后一项 | 被删除的项 |
队列方法
- 队列是先进先出的结构,对应的方法是
shift()
和unshift()
shift()
方法用于删除数组的开头一项,返回被删除的项
colors = new Array()
colors.push(\'red\', \'blue\')
console.log(colors.shift()) // \'red\',返回被删除的项
unshift()
方法接收任意数量的参数,并将它们添加到数组开头,返回数组的最新长度
console.log(colors.unshift(\'green\', \'black\')) // 3,返回数组的长度
console.log(colors) // [ \'green\', \'black\', \'blue\' ]
栈方法 | 操作 | 返回 | 参数 |
---|---|---|---|
shift() | 删除数组开头一项 | 被删除的项 | |
unshift() | 数组开头添加项 | 数组的最新长度 | 要添加的项 |
排序方法
reverse()
方法将数组元素反向排列
let values = [1, 2, 3, 4, 5]
values.reverse()
console.log(values) // [ 5, 4, 3, 2, 1 ]
sort()
方法会在每一项上调用String()
转型函数,然后比较字符串按序重新排列数组元素(默认升序)
values = [0, 1, 5, 10, 15]
values.sort()
console.log(values) // [ 0, 1, 10, 15, 5 ],比较字符串大小而不是数字大小
sort()
方法可以接收一个比较函数,用于判断数组中数值的排列顺序,比较函数接收 2 个参数(以升序为例):- 如果第 1 个参数应该排在第二个参数前面,则返回负值
- 如果 2 个参数相等,则返回 0
- 如果第 1 个参数应该排在第二个参数后面,则返回正值
function compareAsc(val1, val2) { if (val1 < val2) { return -1 } else if (val1 > val2) { return 1 } else { return 0 } } values = [0, 1, 5, 10, 15] values.sort(compareAsc) // 接收参数:正序比较函数 console.log(values) // [ 0, 1, 5, 10, 15 ]
- 如果想产生降序效果,只需把比较函数的返回值交换
function compareDesc(val1, val2) { if (val1 < val2) { return 1 // 降序 } else if (val1 > val2) { return -1 // 降序 } else { return 0 } } values.sort(compareDesc) // 接收参数:降序比较函数 console.log(values) // [ 15, 10, 5, 1, 0 ]
- 比较函数可以简写为箭头函数
values.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)) // 升序 console.log(values) // [ 0, 1, 5, 10, 15 ]
- 如果数组的元素是数值或 valueOf()方法返回数值的对象(如 Date 对象),比较函数可进一步简化为减法操作,用第 1 个参数减去第 2 个参数(或相反)
values.sort((a, b) => a - b) // 升序 console.log(values) // [ 0, 1, 5, 10, 15 ] values.sort((a, b) => b - a) // 降序 console.log(values) // [ 15, 10, 5, 1, 0 ]
排序方法 | 操作 | 返回 | 参数 |
---|---|---|---|
reverse() | 数组元素反向排列 | 调用数组的引用 | |
sort() | 数组元素按序排列 | 调用数组的引用 | 比较函数,用于判断排列顺序 |
操作方法
concat()
创建当前数组的副本,然后把它的参数添加到数组末尾,返回新构建的数组,不改变原数组- 若参数是一个或多个数组,则把这些数组的每一项都添加到结果数组末尾
- 若参数不是数组,则直接把它们添加到结果数组末尾
colors = [\'red\', \'green\', \'blue\']
let colors2 = colors.concat(\'yellow\', [\'black\', \'brown\'])
console.log(colors) // [ \'red\', \'green\', \'blue\' ],不改变原数组
console.log(colors2) // [ \'red\', \'green\', \'blue\', \'yellow\', \'black\', \'brown\' ]
let colors3 = colors.concat(\'yellow\', [\'black\', \'brown\', [\'orange\']]) // [ \'red\', \'green\', \'blue\', \'yellow\', \'black\', \'brown\', [ \'orange\' ] ]
console.log(colors3)
- 在参数数组上指定特殊的符号
Symbol.isConcatSpreadable
,设置为 false 可阻止打平数组(数组默认打平),设置为 true 可打平类数组对象(类数组对象默认不打平)
let newColors = [\'black\', \'brown\'] // 数组
let moreNewColors = {
// 类数组对象
0: \'pink\',
1: \'cyan\',
length: 2,
}
console.log(colors.concat(newColors)) // [ \'red\', \'green\', \'blue\', \'black\', \'brown\' ],数组默认打平
console.log(colors.concat(moreNewColors)) // [ \'red\', \'green\', \'blue\', { \'0\': \'pink\', \'1\': \'cyan\' } ],类数组对象默认不打平
newColors[Symbol.isConcatSpreadable] = false // 阻止打平数组
moreNewColors[Symbol.isConcatSpreadable] = true // 强制打平类数组对象
console.log(colors.concat(newColors)) // [ \'red\', \'green\', \'blue\',[ \'black\', \'brown\', [Symbol(Symbol.isConcatSpreadable)]: false] ]
console.log(colors.concat(moreNewColors)) // [ \'red\', \'green\', \'blue\', \'pink\', \'cyan\' ]
slice()
创建一个包含原有数组中若干元素的新数组,不改变原数组,接收 1 个或 2 个参数(开始索引&结束索引)- 1 个参数,返回该索引到数组末尾的所有元素
- 2 个参数,返回从开始索引到结束索引的所有元素,不包含结束索引
- 同
fill()
和copyWithin()
,索引负值则以数组长度加上负值即可
colors = [\'red\', \'green\', \'blue\', \'black\', \'brown\']
console.log(colors.slice(1)) // [ \'green\', \'blue\', \'black\', \'brown\' ],索引大于等于1到末尾的元素
console.log(colors.slice(1, 4)) // [ \'green\', \'blue\', \'black\' ],索引大于等于1小于4的元素
splice()
可在数组中插入元素、删除元素或同时进行插入和删除两种操作,返回被删除元素组成的数组,改变原数组- 删除元素,传入 2 个参数:要操作元素的开始位置、要删除元素数量
- 插入(并删除)元素,传入大于等于 3 个参数:要操作元素的开始位置、要删除元素数量(0 则不删除)、要插入的元素 1、要插入的元素 2...
colors = [\'red\', \'green\', \'blue\']
let removed = colors.splice(0, 1) // 从索引0开始,删除1项
console.log(removed) // [ \'red\' ],返回被删除元素组成的数组
console.log(colors) // [ \'green\', \'blue\' ],改变原数组
removed = colors.splice(1, 0, \'yellow\', \'orange\') // 从索引1开始,删除0项,插入\'yellow\'、\'orange\'
console.log(removed) // [],没有被删除的元素
console.log(colors) // [ \'green\', \'yellow\', \'orange\', \'blue\' ]
removed = colors.splice(1, 1, \'black\', \'purple\') // 从索引1开始,删除1项,插入\'black\'、\'purple\'
console.log(removed) // [ \'yellow\' ]
console.log(colors) // [ \'green\', \'black\', \'purple\', \'orange\', \'blue\' ]
操作方法 | 操作 | 返回 | 参数 | 改变原数组 |
---|---|---|---|---|
concat() | 数组末尾追加元素 | 新数组 | 要添加的元素/数组 | 否 |
slice() | 创建包含原数组若干元素的新数组 | 新数组 | ① 开始索引 ② 结束索引(不包含) | 否 |
splice() | 数组(同时)插入元素、删除元素 | 被删除元素组成的数组 | ① 开始索引 ② 要删除个数 ③ 插入元素 1 ④ 插入元素 2 | 是 |
搜索和位置方法
- ECMASctipr 提供 2 类搜索数组的方法:严格相等搜索和断言函数搜索
严格相等
3 个方法:
indexOf()
、lastIndexOf()
、includes()
- 均接收 2 个参数:要查找的元素(必填)、起始搜索位置(非必填)
indexOf()
和includes()
从前向后搜索,lastIndexOf()
从后向前搜索indexOf()
、lastIndexOf()
返回要查找元素首次出现的位置(无匹配返回-1),includes()
返回布尔值- 查找时,均使用
===
全等比较 includes()
是 ES7 新增的方法
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1]
console.log(numbers.indexOf(4)) // 3,从前向后,数组首次出现4的索引
console.log(numbers.lastIndexOf(4)) // 5,从后向前,数组首次出现4的索引
console.log(numbers.includes(4)) // true,从前向后,数组中是否包含4
console.log(numbers.indexOf(4, 4)) // 5,从前向后,从数组索引4开始首次出现4的索引
console.log(numbers.lastIndexOf(4, 4)) // 3,从后向前,从数组索引4开始首次出现4的索引
console.log(numbers.includes(4, 7)) // false,从前向后,从数组索引7开始是否包含4
let man = { name: \'Nicholas\' }
let human = [{ name: \'Nicholas\' }] // 不全等,human数组中的对象和对象man来自不同的引用
let human2 = [man] // 全等,将对象man放入human2数组
console.log(human.indexOf(man)) // -1
console.log(human2.indexOf(man)) // 0
console.log(human.includes(man)) // false
console.log(human2.includes(man)) // true
严格相等 | 参数 | 查找顺序 | 返回 |
---|---|---|---|
indexOf() | ① 要查找元素(必) ② 起始搜索位置(非) | 前 → 后 | 要查找元素首次出现的位置,无匹配返回-1 |
lastIndexOf() | ① 要查找元素(必) ② 起始搜索位置(非) | 后 → 前 | 要查找元素首次出现的位置,无匹配返回-1 |
includes() | ① 要查找元素(必) ② 起始搜索位置(非) | 前 → 后 | 布尔值 |
断言函数
2 个方法:
find()
和findIndex()
- 均接收 2 个参数:断言函数、指定断言函数内部 this 的值(可选)
- 断言函数又接收 3 个参数:元素、索引、数组本身
find()
返回第一个匹配的元素,无匹配返回 undefinedfindIndex()
返回第一个匹配元素的索引,无匹配返回-1
people = [
{ name: \'Matt\', age: 27 },
{ name: \'Nicholas\', age: 29 },
]
console.log(people.find((e, i, arr) => e.age > 28)) // { name: \'Nicholas\', age: 29 },返回元素
console.log(people.findIndex((e, i, arr) => e.age > 28)) // 1,返回索引
console.log(people.find((e, i, arr) => e.age > 30)) // undefined,无匹配
console.log(people.findIndex((e, i, arr) => e.age > 30)) // -1,无匹配
- 一旦找到匹配项,两个方法均不再继续搜索
numbers = [3, 6, 9]
numbers.find((e, i, arr) => {
console.log(e)
console.log(i)
console.log(arr)
return e % 2 === 0 // 匹配条件:元素能被2整除
/*
开始搜索:
3,不符合匹配条件
0,此时的索引
[ 3, 6, 9 ],此时的数组
继续搜索:
6,符合匹配条件
1,此时的索引
[ 3, 6, 9 ],次数的数组
不再继续搜索
*/
})
断言函数 | 参数 | 返回 |
---|---|---|
find() | ① 断言函数(必) ② 指定断言函数内部 this 的值(非) | 第一个匹配的元素,无匹配返回 undefined |
findIndex() | ① 断言函数(必) ② 指定断言函数内部 this 的值(非) | 第一个匹配元素的索引,无匹配返回-1 |
迭代方法
- 5 个方法
every()
、some()
、filter()
、map()
、forEach()
- 每个方法接收 2 个参数:以每一项为参数运行的函数、作为函数运行上下文的作用域对象(非必填,影响函数中 this 的值)
传给每个方法的函数接收 3 个参数:元素、索引、数组本身
every()
:对数组每一项运行传入的函数,若每项都返回 true,则该方法返回 truesome()
:对数组每一项运行传入的函数,若有一项返回 true,则该方法返回 truefilter()
:对数组每一项运行传入的函数,由返回 true 的项组成数组,返回给该方法map()
:对数组每一项运行传入的函数,由每项调用的结果组成数组,返回给该方法forEach()
:对数组每一项运行传入的函数,相当于使用 for 循环遍历数组,该方法没有返回值- 除了
forEach()
,其他 4 种方法的参数运行函数都必须有 return(或取消大括号的箭头函数)
numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1]
// some()
let everyResult = numbers.every((item, index, array) => item > 2) // 是否每项都大于2
console.log(everyResult) // false
let someResult = numbers.some((item, index, array) => item > 2) // 是否有1项大于2
console.log(someResult) // true
// filter()
let filterResult = numbers.filter((item, index, array) => item > 2) // 筛选出大于2的元素
console.log(filterResult) // [ 3, 4, 5, 4, 3 ]
// map()
let mapResult = numbers.map((item, index, array) => item * 2) // 返回每项调用函数的结果
console.log(mapResult) // [ 2, 4, 6, 8, 10, 8, 6, 4, 2 ]
// forEach()
let forEachResult = numbers.forEach((item, index, array) => {
item = item * 2
})
console.log(forEachResult) // undefined,forEach没有返回值
numbers.forEach((item, index, array) => {
// 在函数内执行操作,相当于使用for循环遍历
console.log(item * 2)
/*
2
4
6
8
10
8
6
4
2
*/
})
迭代方法 | 参数 | 返回 |
---|---|---|
every() | ① 运行函数(必),必须有返回值 ② 函数的作用域对象(非) | 每项运行参数函数,每项都返回 true 方法才返回 true |
some() | ① 运行函数(必),必须有返回值 ② 函数的作用域对象(非) | 每项运行参数函数,有一项返回 true 方法就返回 true |
filter() | ① 运行函数(必),必须有返回值 ② 函数的作用域对象(非) | 每项运行参数函数,返回 由返回 true 的项组成的数组 |
map() | ① 运行函数(必),必须有返回值 ② 函数的作用域对象(非) | 每项运行参数函数,返回 由每项调用的结果组成的数组 |
forEach() | ① 运行函数(必),没有返回值 ② 函数的作用域对象(非) | 无返回值 |
归并方法
- 2 个方法
reduce()
和reduceRight()
,均迭代数组的所有项,在此基础上构建一个最终返回值 - 每个方法接收 2 个参数:对每一项都会运行的归并函数、归并起点的初始值(非必填)
- 每个归并函数接收 4 个参数:上一个归并值、当前项、当前索引、数组本身
- 若省略归并起点值,则首次迭代将从数组第 2 项开始,传给归并函数的第 1 个参数是数组第 1 项,第 2 个参数是数组第 2 项
reduce()
从前向后遍历,reduceRight()
反之
values = [1, 2, 3, 4, 5]
// reduce()
let sum1 = values.reduce((pre, cur, index, arr) => {
console.log(pre, cur, index)
/*
1 2 1
3 3 2
6 4 3
10 5 4
*/
return pre + cur
}) // 省略归并起点值,归并函数第1个参数为数组第2项,第2个参数为数组第2项
console.log(sum1) // 15
let sum2 = values.reduce((pre, cur, index, arr) => {
console.log(pre, cur, index)
/*
10 1 0
11 2 1
13 3 2
16 4 3
20 5 4
*/
return pre + cur
}, 10) // 归并起点值为10,归并函数第1个参数为10,第2个参数为数组第1项
console.log(sum2) // 25
// reduceRight
let sum3 = values.reduceRight((pre, cur, index, arr) => {
console.log(pre, cur, index)
/*
5 4 3
9 3 2
12 2 1
14 1 0
*/
return pre + cur
})
console.log(sum3) // 15
let sum4 = values.reduceRight((pre, cur, index, arr) => {
console.log(pre, cur, index)
/*
10 5 4
15 4 3
19 3 2
22 2 1
24 1 0
*/
return pre + cur
}, 10) // 归并起点值为10,归并函数第1个参数为10,第2个参数为数组最后1项
console.log(sum4) // 25
迭代方法 | 参数 | 遍历方向 | 返回 |
---|---|---|---|
reduce() | ① 归并函数(必) ② 归并起点值(非) | 前 → 后 | 遍历后最终返回值 |
reduceRight() | ① 运行函数(必) ② 归并起点值(非) | 后 → 前 | 遍历后最终返回值 |
总结 & 问点
- 有哪些基本方法可以创建数组?如何将类数组或一组参数转换为数组实例?
- 为什么不建议使用数组空位?如果确实需要呢?
- 数组的 length 属性是可变的么?如何快速的向数组末尾添加元素?
- 如何判断一个对象是不是数组?
- 用什么方法获取数组索引组成的数组?元素和键值对呢?
- 用什么方法批量填充数组的部分内容?用什么方法获取数组每个值拼接的字符串?若指定分隔符呢?
- 数组的“栈方法”和“队列方法”分别是怎样的用法和返回值?
- 如何按照升序/降序排列数组元素?如果数组元素是数值,如何简化写法?
- 如何将数组和类数组对象打平后添加到另一个数组的末尾?不打平添加呢?
- 请详述 slice()和 splice()的含义、用法、返回值及是否改变原数组
- 有哪些方法可以搜索数组?请分别详述其用法并举例
- 有哪些数组迭代方法?请分别详述其用法并举例
- 有哪些数组归并方法?请分别详述其用法并举例
以上是关于《javascript高级程序设计》学习笔记 | 6.2.Array的主要内容,如果未能解决你的问题,请参考以下文章
javascript 高级程序设计 学习笔记01章 javascript的认知
《JavaScript高级程序设计(第四版)》学习笔记第3章