JavaScript原生陣列函式例項彙總
在JavaScript中,建立陣列可以使用Array建構函式,或者使用陣列直接量[],後者是首選方法。Array物件繼承自Object.prototype,對陣列執行typeof操作符返回object而不是array。然而,[] instanceof Array也返回true。也就是說,類陣列物件的實現更復雜,例如strings物件、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]。
不能中斷.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,array) { if (value > max) max = value return value < 10 }) console.log(max) // <- 12 satisfied // <- true
注意,當回撥函式的value < 10時,中斷函式迴圈。.every的執行原理和.some類似,但回撥函式是返回false而不是true。
區分.join和.concat
.join和.concat 經常混淆。.join(separator)以separator作為分隔符拼接陣列元素,並返回字串形式,如果沒有提供separator,將使用預設的,。.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,.shift和 .unshift
每個人都知道.push可以再陣列末尾新增元素,但是你知道可以使用[].push(‘a',‘b',‘c',‘d',‘z')一次性新增多個元素嗎?
.pop 方法是.push 的反操作,它返回被刪除的陣列末尾元素。如果陣列為空,將返回void 0 (undefined),使用.pop和.push可以建立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,3) stack.next() // <- 3 相反,可以使用.shift和 .unshift建立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,3) queue.next() // <- 1 Using .shift (or .pop) is an easy way to loop through a set of array elements,while draining the array in the process. list = [1,4,6,7,9,10] while (item = list.shift()) { console.log(item) } list // <- []
模型對映:.map
.map為陣列中的每個元素提供了一個回撥方法,並返回有呼叫結果構成的新陣列。回撥函式只對已經指定值的陣列索引執行;它不會對已刪除的或未指定值的元素呼叫。
Array.prototype.map 和上面提到的.forEach、.some和 .every有相同的引數格式:.map(fn(value,array),thisArgument)
values = [void 0,null,false,''] values[7] = void 0 result = values.map(function(value,array){ console.log(value) return value }) // <- [undefined,'',undefined × 3,undefined]
undefined × 3很好地解釋了.map不會對已刪除的或未指定值的元素呼叫,但仍然會被包含在結果陣列中。.map在建立或改變陣列時非常有用,看下面的示例:
// casting [1,'2','30','9'].map(function (value) { return parseInt(value,10) }) // 1,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) } })
查詢:.filter
filter對每個陣列元素執行一次回撥函式,並返回一個由回撥函式返回true的元素組成的新陣列。回撥函式只會對已經指定值的陣列項呼叫。
通常用法:.filter(fn(value,thisArgument),跟C#中的LINQ表示式和SQL中的where語句類似,.filter只返回在回撥函式中返回true值的元素。
[void 0,1].filter(function (value) { return value }) // <- [1] [void 0,1].filter(function (value) { return !value }) // <- [void 0,'']
排序:.sort(compareFunction)
如果沒有提供compareFunction,元素會被轉換成字串並按照字典排序。例如,”80″排在”9″之前,而不是在其後。
跟大多數排序函式類似,Array.prototype.sort(fn(a,b))需要一個包含兩個測試引數的回撥函式,其返回值如下:
- a在b之前則返回值小於0
- a和b相等則返回值是0
- a在b之後則返回值小於0
[9,80,6].sort()
// <- [10,9]
[9,6].sort(function (a,b) {
return a - b
})
// <- [3,80]
計算:.reduce和.reduceRight
這兩個函式比較難理解,.reduce會從左往右遍歷陣列,而.reduceRight則從右往左遍歷陣列,二者典型用法:.reduce(callback(previousValue,currentValue,initialValue)。
previousValue 是最後一次呼叫回撥函式的返回值,initialValue則是其初始值,currentValue是當前元素值,index是當前元素索引,array是呼叫.reduce的陣列。
一個典型的用例,使用.reduce的求和函式。
Array.prototype.sum = function () {
return this.reduce(function (partial,value) {
return partial + value
},0)
};
[3,10].sum()
// <- 28
如果想把陣列拼接成一個字串,可以用.join實現。然而,若陣列值是物件,.join就不會按照我們的期望返回值了,除非物件有合理的valueOf或toString方法,在這種情況下,可以用.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']
這對.concat不適用,因為它會用陣列包裹類陣列物件。
Array.prototype.concat.call({ 0: 'a',length: 2 })
// <- [{ 0: 'a',length: 2 }]
此外,.slice的另一個通常用法是從一個引數列表中刪除一些元素,這可以將類陣列物件轉換為真正的陣列。
function format (text,bold) { if (bold) { text = '' + text + '' } 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')
強大的.splice
.splice 是我最喜歡的原生陣列函式,只需要呼叫一次,就允許你刪除元素、插入新的元素,並能同時進行刪除、插入操作。需要注意的是,不同於`.concat和.slice,這個函式會改變源陣列。
var source = [1,11,13]
var spliced = source.splice(3,7)
console.log(source)
// <- [1,13]
spliced
// <- [8,8]
正如你看到的,.splice會返回刪除的元素。如果你想遍歷已經刪除的陣列時,這會非常方便。
var source = [1,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,9]
查詢:.indexOf
利用.indexOf 可以在陣列中查詢一個元素的位置,沒有匹配元素則返回-1。我經常使用.indexOf的情況是當我有比較時,例如:a === ‘a' || a === ‘b' || a === ‘c',或者只有兩個比較,此時,可以使用.indexOf:['a','b','c'].indexOf(a) !== -1。
注意,如果提供的引用相同,.indexOf也能查詢物件。第二個可選引數用於指定開始查詢的位置。
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,5]
1 in a
// <- true,but because of the 2!
5 in a
// <- false
問題是in操作符是檢索物件的鍵而非值。當然,這在效能上比.indexOf快得多。
var a = [3,6]
1 in a === !!a[1]
// <- true
走近.reverse
該方法將陣列中的元素倒置。
var a = [1,1,8]
a.reverse()
// [8,1]
.reverse 會修改陣列本身。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。