JavaScript中原生Array数组方法详解

更新日期: 2020-08-02阅读: 1.5k标签: 数组

JS中,数组可以通过 Array 构造函数或 [] 字面量的方式创建。数组是一个特殊的对象,继承自 Object 原型,但用 typeof 判断时,并没有一个特定的值,仍然返回 'object'。但使用 [] instanceof Array 返回 true。这说明,JS中存在一个类数组的对象,就像字符串对象或 arguments 对象。arguments 对象不是数组的实例,但仍然有 length 属性,值也可以被索引,因此也可以像数组一样被循环遍历。

这篇文章中,我将盘点下定义在 Array 原型上的一些常用的方法,并逐一介绍其用法。

  • 循环 .forEach
  • 断言 .some,.every
  • 连接与合并 .join,.concat
  • 栈与队列 .pop, .push, .shift, .unshift
  • 模型映射 .map
  • 过滤 .filter
  • 排序 .sort
  • 聚合 .reduce, .reduceRight
  • 截取 .slice
  • 删除插入 .splice
  • 查找值 .indexOf
  • 查找键 in 操作符
  • 颠倒 .reverse


1.forEach()

forEach 对数组的所有成员依次执行且只执行一次参数函数,参数函数包含以下3个参数:

  • value 当前值
  • index 当前位置,索引值
  • array 当前数组

进一步,可以传递一个可选参数用于指定函数里的 this 上下文。

['_', 't', 'a', 'n', 'i', 'f', ']'].forEach(function (value, index, array) {
    this.push(String.fromCharCode(value.charCodeAt() + index + 2))
}, out = [])

out.join('')
// <- 'awesome'

forEach的缺陷是既不能中断循环,也不能抛出异常。


2.some(), every()

这两个方法类似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件。
类似于 forEach,同样接受一个包含 value, index, and array的回调函数作为参数,而且也可以指定 上下文中的this。
some方法是只要一个成员的返回值是true,则整个some方法的返回值就是true,否则返回false。
every方法是所有成员的返回值都是true,整个every方法才返回true,否则返回false。

max = -Infinity
satisfied = [10, 12, 10, 8, 5, 23].some(function (value, index, array) {
    if (value > max) max = value
    return value < 10
})

console.log(max)
// <- 12

satisfied
// <- true


3.join() and concat()

这两个方法容易搞混,join是将数组内各个成员用分隔符连接成一个字符串,分隔符默认是 ,,concat用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。

var a = { foo: 'bar' }
var b = [1, 2, 3, a]
var c = b.concat()

console.log(b === c)
// <- false

b[3] === a && c[3] === a
// <- true


4.pop, .push, .shift, and .unshift

每个人都知道往数组末尾添加一个元素是用push方法,但你知道可以一次性添加多个元素吗,像这样 [].push('a', 'b', 'c', 'd', 'z').
pop是push方法的逆操作,去除数组最后一个元素同时返回这个元素,如果是空数组则返回 undefined,使用这两个方法很容易实现 LIFO(last in first out) 栈结构。

function Stack () {
    this._stack = []
}

Stack.prototype.next = function () {
    return this._stack.pop()
}

Stack.prototype.add = function () {
    return this._stack.push.apply(this._stack, arguments)
}

stack = new Stack()
stack.add(1,2,3)

stack.next()
// <- 3

相应的,我们可以通过 .unshift and .shift 实现一个 FIFO (first in first out)队列。

function Queue () {
    this._queue = []
}

Queue.prototype.next = function () {
    return this._queue.shift()
}

Queue.prototype.add = function () {
    return this._queue.unshift.apply(this._queue, arguments)
}

queue = new Queue()
queue.add(1,2,3)

queue.next()
// <- 1

使用 .shift (or .pop) 很容易用while循环清空一个数组,如下:

list = [1,2,3,4,5,6,7,8,9,10]

while (item = list.shift()) {
    console.log(item)
}

list
// <- []


5.map()

map方法将数组的所有成员依次传入回调函数,然后把每一次的执行结果组成一个新数组返回。
方法签名类似于 forEach,.map(fn(value, index, array), thisArgument).

values = [void 0, null, false, '']
values[7] = void 0
result = values.map(function(value, index, array){
    console.log(value)
    return value
})
// <- [undefined, null, false, '', undefined × 3, undefined]

undefined × 3 表明了回调函数不会在已删除或未赋值的成员执行,而是自己返回包含在返回数组中。Map在映射或转换数组时非常有用,比如下面这个例子:

// casting
[1, '2', '30', '9'].map(function (value) {
    return parseInt(value, 10)
})
// 1, 2, 30, 9

[97, 119, 101, 115, 111, 109, 101].map(String.fromCharCode).join('')
// <- 'awesome'

// a commonly used pattern is mapping to new objects
items.map(function (item) {
    return {
        id: item.id,
        name: computeName(item)
    }
})


6.filter()

filter方法用于过滤数组成员,满足条件的成员组成一个新数组返回。

使用类似于,.filter(fn(value, index, array), thisArgument).

[void 0, null, false, '', 1].filter(function (value) {
    return value
})
// <- [1]

[void 0, null, false, '', 1].filter(function (value) {
    return !value
})
// <- [void 0, null, false, '']


7.sort(compareFunction)

sort方法对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。
像大多数的排序函数一样,Array.prototype.sort(fn(a,b)) 接受一个回调函数用于比较 a,b 的大小,而且为下面三种情况之一:

  • return value < 0 if a comes before b
  • return value === 0 if both a and b are considered equivalent
  • return value > 0 if a comes after b
[9,80,3,10,5,6].sort()
// <- [10, 3, 5, 6, 80, 9]

[9,80,3,10,5,6].sort(function (a, b) {
    return a - b
})
// <- [3, 5, 6, 9, 10, 80]


8.reduce(), reduceRight()

Reduce函数一开始很难理解,这些函数会循环数组,从左向右 (.reduce) 或从右向左 (.reduceRight),每次回调函数执行时会接受之前的部分结果,最终返回值是单个聚合的值。

两个方法具有相同的语法

reduce(callback(previousValue, currentValue, index, array), initialValue)

previousValue 是上次回调函数执行的返回值,或者第一次执行时的初始值;currentValue 是当前值;index 是当前值位置;array 是执行reduce方法数组的引用;initialValue 是初始值;

.reduce方法的一个典型应用场景是数组成员求和:

Array.prototype.sum = function () {
    return this.reduce(function (partial, value) {
        return partial + value
    }, 0)
};

[3,4,5,6,10].sum()
// <- 28


9.slice()

slice()方法用于提取目标数组的一部分,返回一个新数组,原数组不变。

arr.slice(start, end)

它的第一个参数为起始位置(从0开始,会包括在返回的新数组之中),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。

与concat()类似,slice()如果没有任何参数则返回原数组的浅拷贝。Array.prototype.slice可以用来将类数组的对象转换成真正的数组。

Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })
// <- ['a', 'b']

concat做不到,它会返回一个包含传入对象的数组。

Array.prototype.concat.call({ 0: 'a', 1: 'b', length: 2 })
// <- [{ 0: 'a', 1: 'b', length: 2 }]


10.splice()

.splice 是我最喜欢的array原生数组方法,它允许你在一次性在同一个位置删除、插入元素,注意:这个函数会改变原数组。

var source = [1,2,3,8,8,8,8,8,9,10,11,12,13]
var spliced = source.splice(3, 4, 4, 5, 6, 7)

console.log(source)
// <- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ,13]

spliced
// <- [8, 8, 8, 8]

你可能注意到了,它会返回被删除的元素,这个常用于循环被删除的元素,你之前可能忘记了。

var source = [1,2,3,8,8,8,8,8,9,10,11,12,13]
var spliced = source.splice(9)

spliced.forEach(function (value) {
    console.log('removed', value)
})
// <- removed 10
// <- removed 11
// <- removed 12
// <- removed 13

console.log(source)
// <- [1, 2, 3, 8, 8, 8, 8, 8, 9]


11.indexOf()、lastIndexOf()

indexOf方法返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1。
var a = { foo: 'bar' }
var b = [a, 2]

console.log(b.indexOf(1))
// <- -1

console.log(b.indexOf({ foo: 'bar' }))
// <- -1

console.log(b.indexOf(a))
// <- 0

console.log(b.indexOf(a, 1))
// <- -1

b.indexOf(2, 1)
// <- 1

lastIndexOf方法返回给定元素在数组中最后一次出现的位置,如果没有出现则返回-1。

注意,这两个方法不能用来搜索NaN的位置,即它们无法确定数组成员是否包含NaN。

这是因为这两个方法内部,使用严格相等运算符(===)进行比较,而NaN是唯一一个不等于自身的值。


12.in 操作符

in 用于查找 key 在一个数组中是否存在,indexOf则是查找值。当然速度快于 indexOf.

var a = [1, 2, 5]

1 in a
// <- true, but because of the 2!

5 in a
// <- false
var a = [3, 7, 6]

1 in a === !!a[1]
// <- true

in 操作符跟把相应位置的值转化为布尔值类似。!! 表达式常用于将一个值取反然后再取反,这是一种高效的将真值转为布尔值的方式。


13.reverse()

reverse方法用于颠倒排列数组元素,返回改变后的数组。注意,该方法将改变原数组。
var a = ['a', 'b', 'c'];

a.reverse() // ["c", "b", "a"]

a // ["c", "b", "a"]

链接: https://www.fly63.com/article/detial/9692

探索JavaScript数组奥秘

avaScript数组同后端语言一样,具有它自己的数据结构,归根结底,这种数据结构,本质就是一种集合。在后端语言中(如java,.net等),数组是这样定义的:数组是用来存储相同数据类型的集合

js使用数组+循环+条件实现数字转换为汉字的简单方法。

单个数字转汉字的解决方法:利用数组存储0-9的汉字、 ary.length和str.length不用多说,这是指ary数组和str字符串的长度。这里我们需要注意的是str.charAt(j)和ary[i],分别指在str这个字符串中索引为j的元素,在ary中索引为i的元素。

[译]async-await 数组循环的几个坑

在 Javascript 循环中使用 async/ await 循环遍历数组似乎很简单,但是在将两者结合使用时需要注意一些非直观的行为。让我们看看三个不同的例子,看看你应该注意什么,以及哪个循环最适合特定用例。

数组、字符串去重

今天说的数组和字符串去重呢,主要用到es6新的数据结构 Set,它类似于数组,但是成员的值都是唯一的,没有重复的值,所以活用Set来进行数组和字符串的去重。

JavaScript 数组方法

数组方法:1、Array.join([param]) 方法:将数组中所有的元素都转换为字符串并连接起来,通过字符 param 连接,默认使用逗号,返回最后生成的字符串2、Array.reverse() 方法:将数组中的元素颠倒顺序(在原数组中重新排列它们),返回逆序数组

如何删除JavaScript 数组中的虚值

falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中。

JavaScript中十种一步拷贝数组的方法

JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下。扩展运算符(浅拷贝)自从ES6出现以来,这已经成为最流行的方法。

JS数组的几个经典api

本文主要来讲数组api的一些操作,如简单实现扁平化n维数组、数组去重、求数组最大值、数组求和、排序、对象和数组的转化等。扁平化嵌套数组/展平和阵列孔——flat()

关于Vue不能监听(watch)数组变化

vue无法监听数组变化的情况,但是数组在下面两种情况下无法监听:利用索引直接设置数组项时,例如arr[indexofitem]=newValue;修改数组的长度时,例如arr.length=newLength

JS计算两个数组的交集、差集、并集、补集(多种实现方式)

使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本,使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本。也不用引入其他第三方库。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!