《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()返回第一个匹配的元素,无匹配返回 undefined
    • findIndex()返回第一个匹配元素的索引,无匹配返回-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,则该方法返回 true
    • some():对数组每一项运行传入的函数,若有一项返回 true,则该方法返回 true
    • filter():对数组每一项运行传入的函数,由返回 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 高级程序设计学习笔记

javascript 高级程序设计 学习笔记01章 javascript的认知

1 《JavaScript高级程序设计》学习笔记

《JavaScript高级程序设计(第四版)》学习笔记第3章

《JavaScript高级程序设计(第四版)》学习笔记第3章

JavaScript高级程序设计(第三版)学习笔记222425章