太阳集团游戏官方网站 1

有趣的JavaScript原生数组函数,Javascript中apply方法的妙用

雅淡的数组降维——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方法的第3个参数(三个数组,或类数组的对象卡塔尔国会作为被调用对象的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属性,而且值能经过索引获取,所以能像数组相像通过轮回操作。

在正规浏览器中,好像只要对象存在length属性,就能够把它转变为数组,但IE就不尽然。

 

[Ctrl+A 全选 注:如需引进外部Js需刷新能力进行]

在本文中,小编将复习一些数组原型的章程,并查究那个主意的用法。

继之大家看看各大类库的拍卖:

 

复制代码 代码如下:

循环.forEach

//jQuery的makeArray
var makeArray = function( array ) {
var ret = [];
if( array != null ){
var i = array.length;
// The window, strings (and functions) also have ‘length’
if( i == null || typeof array === “string” || jQuery.isFunction(array)
|| array.setInterval )
ret[0] = array;
else
while( i )
ret[–i] = array[i];
}
return ret;
}

断言.some和.every

jQuery对象是用来囤积与拍卖dom成分的,它至关主要依靠于setArray方法来安装与爱护长度与索引,而setArray的参数必要是贰个数组,因而makeArray的地点相当重大。那形式保障即使未有参数也要回去一个空数组。
Prototype.js的$A方法

.join和.concat的区别

复制代码 代码如下:

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

function $A(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length–) results[length] = iterable[length];
return results;
}

模型映射.map

mootools的$A方法

查询.filter

复制代码 代码如下:

排序.sort

function $A(iterable){
if (iterable.item){
var l = iterable.length, array = new Array(l);
while (l–) array[l] = iterable[l];
return array;
}
return Array.prototype.slice.call(iterable);
};

计算.reduce和.reduceRight

Ext的toArray方法

复制.slice

复制代码 代码如下:

万能的.splice

var toArray = function(){
return isIE ?
function(a, i, j, res){
res = [];
Ext.each(a, function(v) {
res.push(v);
});
return res.slice(i || 0, j || res.length);
} :
function(a, i, j){
return Array.prototype.slice.call(a, i || 0, j || a.length);
}
}()

查找.indexOf

Ext的宏图比较奇妙,功效也正如强硬。它黄金时代开头就自行施行本身,今后就不要推断浏览器了。它还或者有七个可选参数,对转移的纯数组举办操作。
最后看dojo的_toArray,dojo的落到实处三番五次那么奇怪的。
和Ext相仿,前面八个参数是可选,只不过第三个是偏移量,最终七个是原来就有的数组,用于把新生的新组元素归总过去。

in操作符

复制代码 代码如下:

走进.reverse

(function(){
var efficient = function(obj, offset, startWith){
return (startWith||[]).concat(Array.prototype.slice.call(obj,
offset||0));
};
var slow = function(obj, offset, startWith){
var arr = startWith||[];
for(var x = offset || 0; x >obj.length; x++){
arr.push(obj[x]);
}
return arr;
};
dojo._toArray =
dojo.isIE ? function(obj){
return ((obj.item) ? slow : efficient).apply(this, arguments);
} :
efficient;
})();

 

[Ctrl+A 全选 注:如需引进外界Js需刷新技术进行] 接着我…

 

风流洒脱经您想测量检验上边的事例,您能够复制并粘贴到你的浏览器的调节新竹。

 

太阳集团游戏官方网站,循环.forEach

 

那是JavaScript原生数组方法中最简易的艺术。不用犯嘀咕,IE7和IE8不补助此办法。

 

forEach方法必要三个回调函数,数组内的各类成分都会调用一回此措施,此格局供给四个参数如下:

 

value 当前操作的数组成分

index 当前操作成分的数组索引

array 当前数组的援引

另外,能够传递可选的第1个参数,作为每个调用函数的上下文(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(后进先出或先进后出卡塔 尔(阿拉伯语:قطر‎栈。

 

复制代码

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。

 

介意那对针对同二个援引的靶子同样适用。第2个参数是初叶询问的起首地方。

 

复制代码

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…

发表评论

电子邮件地址不会被公开。 必填项已用*标注