来自 公司简介 2019-11-28 09:00 的文章
当前位置: 澳门太阳娱乐手机登录 > 公司简介 > 正文

大雅的数组降维,风趣的JavaScript原生数组函数

尊贵的数组降维——Javascript中apply方法的妙用

2016/02/18 · JavaScript · apply, 数组

初藳出处: ralph_zhu   

将多维数组(尤其是二维数组卡塔 尔(阿拉伯语:قطر‎转变为风度翩翩维数组是事情开销中的常用逻辑,除了使用节约能源的轮回转换以外,大家还足以应用Javascript的语言特征完成特别简单高雅的调换。本文将从节俭的巡回转变初步,逐个介绍二种常用的转变方法,并借此轻便回看Array.prototype.concat方法和Function.prototype.apply方法。
以下代码将以把二维数组降维到风流洒脱维数组为例。

  1. 节约的退换

JavaScript

function reduceDimension(arr) { var reduced = []; for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr[i].length; j++) { reduced.push(arr[i][j]); } } return reduced; }

1
2
3
4
5
6
7
8
9
function reduceDimension(arr) {
    var reduced = [];
    for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j < arr[i].length; j++) {
            reduced.push(arr[i][j]);
        }
    }
    return reduced;
}

此措施思路简单,利用再次循环遍历二维数组中的种种成分并置于新数组中。

 

  1. 利用concat转换
    先来回想一下MDN上对此该方式的介绍:
    “concat creates a new array consisting of the elements in the object on which it is called, followed in order by, for each argument, the elements of that argument (if the argument is an array) or the argument itself (if the argument is not an array).”

即只要concat方法的参数是一个因素,该因素会被直接插入到新数组中;假设参数是贰个数组,该数组的顺序要素将被插入到新数组中;将该个性应用到代码中:

JavaScript

function reduceDimension(arr) { var reduced = []; for (var i = 0; i < arr.length; i++){ reduced = reduced.concat(arr[i]); } return reduced; }

1
2
3
4
5
6
7
function reduceDimension(arr) {
    var reduced = [];
    for (var i = 0; i < arr.length; i++){
        reduced = reduced.concat(arr[i]);
    }
    return reduced;
}

arr的每叁个成分都以一个数组,作为concat方法的参数,数组中的每叁个子成分又都会被单独插入进新数组。
行使concat方法,我们将再一次循环简化为了单重循环。

 

  1. 利用apply和concat转换
    固守规矩,先来回顾一下MDN上对此apply方法的介绍:
    “The apply() method calls a function with a given this value and arguments provided as an array.”

即apply方法会调用叁个函数,apply方法的第三个参数会作为被调用函数的this值,apply方法的第二个参数(三个数组,或类数组的目的卡塔 尔(英语:State of Qatar)会作为被调用对象的arguments值,也便是说该数组的相继要素将会挨个成为被调用函数的逐少年老成参数;将该本性应用到代码中:

function reduceDimension(arr) { return Array.prototype.concat.apply([], arr); }

1
2
3
function reduceDimension(arr) {
    return Array.prototype.concat.apply([], arr);
}

arr作为apply方法的第一个参数,自个儿是二个数组,数组中的每多少个成分(依然数组,即二维数组的第二维卡塔尔会被看作参数依次传入到concat中,效果同样[].concat([1,2], [3,4], [5,6])。
使用apply方法,大家将单重循环优化为了风度翩翩行代码,很简单有型有木有啊~

读者也可参看本文思路,自身行使递归落成N维数组降维的逻辑。

3 赞 8 收藏 评论

图片 1

在JavaScript中,能够透过三种艺术开创数组,布局函数和数组直接量, 在那之中前面一个为首要推荐办法。数组对象继承自Object.prototype,对数组实践typeof操作符再次回到‘object’而不是‘array’。然则实施[] instanceof Array重临true。其余,还会有类数组对象是难题更目眩神摇,如字符串对象,arguments对象。arguments对象不是Array的实例,但却有个length属性,况兼值能经过索引获取,所以能像数组同样通过轮回操作。

 

在本文中,小编将复习一些数组原型的诀窍,并研讨这个形式的用法。

 

循环.forEach

断言.some和.every

.join和.concat的区别

栈和队列.pop,.push,.shift和.unshift

模型映射.map

查询.filter

排序.sort

计算.reduce和.reduceRight

复制.slice

万能的.splice

查找.indexOf

in操作符

走进.reverse

 

 

要是你想测量试验上边的事例,您可以复制并粘贴到您的浏览器的调节台北。

 

循环.forEach

 

这是JavaScript原生数组方法中最轻易易行的艺术。不用可疑,IE7和IE8不援助此办法。

 

forEach方法要求叁个回调函数,数组内的种种成分都会调用三次此措施,此措施供给八个参数如下:

 

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'

.join函数我就要下文聊起,上边例子中,它将数组中的不一致因素拼接在一同,相似于如下的功力:out[0]

  • '' + out[1] + '' + out[2] + '' + out[n]。

 

小编们不可能用break中断forEach循环,抛出十一分是不明智的点子。幸运的是,大家有其余的点子中断操作。

 

断言.some和.every

 

后生可畏经你已经用过.NET的枚举,那么些主意的名字和.Any(x => x.IsAwesome) 和 .All(x => x.IsAwesome)非常相符。

 

这几个办法和.forEach雷同,必要一个分包value,index,和array几个参数的回调函数,何况也会有三个可选的第叁个上下文参数。MDN对.some的叙说如下:

 

some将会给数组里的每四个要素施行三回回调函数,直到有叁个回调函数重回true地方。固然找到对象成分,some立时回去true,不然some再次回到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

复制代码

小心,当回调函数的value < 10 条件满意时,中断函数循环。.every的行事表现看似,但回调函数要赶回false并不是true。

 

.join和.concat的区别

 

.join方法日常和.concat混淆。.join(分隔符)方法创造一个字符串,会将数组里面每一个成分用分隔符连接。若无提供分隔符,暗许的相间符为“,”。.concat方法创设八个新数组,其是对原数组的浅拷贝(注意是浅拷贝哦卡塔尔国。

 

.concat 的标记用法:array.concat(val, val2, val3, valn)

.concat 重临二个新书组

array.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

复制代码

栈和队列.pop,.push,.shift和.unshift

 

各种人都晓得向数组添法郎素用.push。但您掌握一次能够增多七个因素呢?如下[].push('a', 'b', 'c', 'd', 'z')。

 

.pop方法和.push成对使用,它回到数组的尾声成分并将元素从数组移除。即使数组为空,重临void 0(undefined卡塔尔国。使用.push和.pop大家能轻松模拟出LIFO(后进先出或先进后出卡塔 尔(英语:State of Qatar)栈。

 

复制代码

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 和 .shift模拟FIFO(先进先出卡塔 尔(阿拉伯语:قطر‎队列。

 

复制代码

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或.pop能相当的轻易遍历数组成分,并做一些操作。

 

复制代码

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

 

while (item = list.shift()) {

    console.log(item)

}

 

list

// <- []

复制代码

模型映射.map

 

map 方法会给原数组中的各个成分(必得有值)都调用一遍 callback 函数.callback 每一次实施后的重返值组合起来变成二个新数组. callback函数只会在有值的目录上被调用; 那多个向来没被赋过值也许使用delete删除的目录则不会被调用。——MDN

 

Array.prototype.map方法和方面大家提到的.forEach,.some和.every有同等的参数:.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不会在没被赋过值只怕使用delete删除的目录上调用,但他们如故被含有在结果数组中。map在遍历或改换数组方面非常有用,如下所示:

 

复制代码

// 遍历

[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'

 

// 三个映射新对象的通用格局

items.map(function (item) {

    return {

        id: item.id,

        name: computeName(item)

    }

})

复制代码

查询.filter

 

filter对种种数组成分推行三遍回调函数,并回到三个由回调函数重返true的因素 组成的新数组。回调函数只会对曾经内定值的数组项调用。

 

用法例子:.filter(fn(value, index, array), thisArgument)。把它想象成.Where(x => x.IsAwesome) LINQ expression(要是您领会C#卡塔尔国,大概SQL语句里面包车型客车WHERE。考虑到.filter仅再次回到callback函数再次回到真值的值,下边是局地旧事例。未有传递给回调函数测验的要素被归纳的跳过,不会含有进重返的新书组里。

 

复制代码

[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, '']

复制代码

排序.sort(相比较函数)

 

假诺未提供相比较函数,成分会调换为字符串,并按字典许排列。举个例子,在字典序里,“80”排在“9”此前,但事实上大家目的在于的是80在9现在(数字排序卡塔尔。

 

像超越四分之二排序函数雷同,Array.prototype.sort(fn(a,b))要求三个含有多少个测验参数的回调函数,並且要发生一下两种重临值之生龙活虎:

 

要是a在b前,则再次来到值小于零

假诺a和b是等价的,则重临值等于零

举个例子a在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]

复制代码

计算.reduce和.reduceRight

 

率先reduce函数不是很好精通,.reduce从左到右而.reduceRight从右到左循环遍历数组,每便调用接受近来截至的一些结出和近年来遍历的值。

 

三种格局皆好似下标准用法:.reduce(callback(previousValue, currentValue, index, array), initialValue)。

 

previousValue是最终被调用的回调函数的再次回到值,initialValue是初阶时previousValue被伊始化的值。currentValue 是现阶段被遍历的要素值,index是最近成分在数组中的索引值。array是对调用.reduce数组的简短援引。

 

多个名列三甲的用例,使用.reduce的求和函数。

 

复制代码

Array.prototype.sum = function () {

    return this.reduce(function (partial, value) {

        return partial + value

    }, 0)

};

 

[3,4,5,6,10].sum()

// <- 28

复制代码

地点提到假设想把数组连成三个字符串,能够使用.join。当数组的值是指标的情形下,除非对象有能回去其合理值的valueof或toString方法,不然.join的显现和您愿意的不朝气蓬勃致。但是,大家能够使用.reduce作为指标的字符串生成器。

 

复制代码

function concat (input) {

    return input.reduce(function (partial, value) {

        if (partial) {

            partial += ', '

        }

        return partial + value

    }, '')

}

 

concat([

    { name: 'George' },

    { name: 'Sam' },

    { name: 'Pear' }

])

// <- 'George, Sam, Pear'

复制代码

复制.slice

 

和.concat相似,调用.slice缺省参数时,重临原数组的浅拷贝。slice函数须求多个参数,多个是开始地方和三个终了位置。

 

Array.prototype.slice能被用来将类数组对象转变为真正的数组。

 

Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })

// <- ['a', 'b']

而外,另叁个广泛用处是从参数列表中移除最先的多少个因素,并将类数组对象调换为确实的数组。

 

复制代码

function format (text, bold) {

    if (bold) {

        text = '<b>' + text + '</b>'

    }

    var values = Array.prototype.slice.call(arguments, 2)

 

    values.forEach(function (value) {

        text = text.replace('%s', value)

    })

 

    return text

}

 

format('some%sthing%s %s', true, 'some', 'other', 'things')

// <- <b>somesomethingother things</b>

复制代码

万能的.splice

 

.splice是自己最心爱的原生数组函数之风华正茂。它同意你剔除成分,插入新因素,或在同样地方同一时间举行上述操作,而只行使一个函数调用。注意和.concat和.slice不一致的是.splice函数改良原数组。

 

复制代码

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]

复制代码

查找.indexOf

 

通过.indexOf,大家得以搜索数组成分的职位。若无相称成分则赶回-1。笔者意识作者用的居多的四个情势是延续相比,举例a === 'a' || a === 'b' || a === 'c',可能固然独有四个结果的比较。在这里种情状下,你也能够使用.indexOf,像这么:['a', 'b', 'c'].indexOf(a) !== -1。

 

瞩目这对指向性同叁个引用的靶子同样适用。第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能派上用处。

 

in操作符

 

在面试中新手轻便犯的失实是混淆.indexOf和in操作符,如下:

 

复制代码

var a = [1, 2, 5]

 

1 in a

// <- true, 但因为 2!

 

5 in a

// <- false

复制代码

主题材料的首借使in操作符检索对象的键而非值。当然,那在性质上比.indexOf快得多。

 

var a = [3, 7, 6]

 

1 in a === !!a[1]

// <- true

in操作符形似于将键值转变为布尔值。!!表达式平日被开拓者用来重新取非三个值(转变为布尔值)。实际上约等于强制转变为布尔值,任何为确实值被转为true,任何为假的值被转变为false。

 

走进.reverse

 

这格局将数组中的成分翻转并替换原本的因素。

 

var a = [1, 1, 7, 8]

 

a.reverse()

// [8, 7, 1, 1]

和复制不一致的是,数组本人被改变。在其后的稿子中自己将张开对这一个概念的知道,去寻访哪些创立叁个库,如Underscore或Lo-Dash。

此中后面一个为首推办法。数组对象世袭自Object.prototype,对数组实践type...

本文由澳门太阳娱乐手机登录发布于公司简介,转载请注明出处:大雅的数组降维,风趣的JavaScript原生数组函数

关键词: