《JavaScript權威指南》讀書筆記5 數組方法

join()

Array.join()方法將數組中所有元素都轉化為字符串并連接在一起,返回最后生成的字符串。可以指定一個可選的字符串在生成的字符串中來分隔數組的各個元素。如果不指定分隔符,默認使用逗號。如以下代碼所示:

var a = [1,2,3];  //創建一個包含三個元素的數組
a.join();  //=>"1,2,3"
a.join(" ");  //=>"1 2 3"
a.join("");  //=>"123"
var b = new Array(10);  //長度為10的空數組
b.join('-')  //=>'---------':9個連字號組成的字符串

Array.join()方法是String.split()方法的逆向操作,后者是將字符串分割成若干塊來創建一個數組。

reverse()

Array.reverse()方法將數組中的元素顛倒順序,返回逆序的數組。它采取了替換;換句話說,它不通過重新排列的元素創建新的數組,而是在原先的數組中重新排列它們。例如,下面的代碼使用reverse()和join()方法生成字符串“3,2,1”:

var a = [1,2,3];
a.reverse().join();  //=>"3,2,1",并且現在的a是[3,2,1]

sort()

Array.sort()方法將數組中的元素排序并返回排序后的數組。當不帶參數調用sort()時,數組元素以字母表順序排序(如有必要將臨時轉化為字符串進行比較):

var a = new Array("banana", "cherry", "apple");
a.sort();
var s = a.join(",");  //s=="apple,banana,cherry"

如果數組包含undefined元素,它們會被排到數組的尾部。

為了按照其他方式而非字母表順序進行數組排序,必須給sort()方法傳遞一個比較函數。該函數決定了它的兩個參數在排好序的數組中的先后順序。假設第一個參數應該在前,比較函數應該返回一個小于0的數值。反之,假設第一個參數應該在后,函數應該返回一個大于0的數值。并且,假設兩個值相等(也就是說,它們的順序無關緊要),函數應該返回0。因此,例如,用數值大小而非字母表順序進行數組排序,代碼如下:

var a = [33, 4, 1111, 222];
a.sort();  //字母表順序:1111,222,33,4
a.sort(function(a, b) {   //數值順序:4,33,222,1111
    return a - b;  //根據順序,返回負數、0、正數
});

a.sort(function(a, b) {return b-a});//數值大小相反的順序

注意,這里使用匿名函數表達式非常方便。既然比較函數只使用一次,就沒必要給它們命名了。

另外一個數組元素排序的例子,也許需要對一個字符串數組執行不區分大小寫的字母表排序,比較函數首先將參數都轉化為小寫字符串(使用toLowerCase()方法),再開始比較:

a = ['ant', 'Bug', 'cat', 'Dog'];
a.sort();  //區分大小寫的排序:['Bug','Dog','ant',cat']

a.sort(function(s, t) {    //不區分大小寫的排序
    var a = s.toLowerCase();
    var b = t.toLowerCase();

    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
});  //=>['ant','Bug','cat','Dog']

concat()

Array.concat()方法創建并返回一個新數組,它的元素包括調用concat()的原始數組的元素和concat()的每個參數。如果這些參數中的任何一個自身是數組,則連接的是數組的元素,而非數組本身。但要注意,concat()不會遞歸扁平化數組的數組。concat()也不會修改調用的數組。下面有一些示例:

var a = [1, 2, 3];
a.concat(4, 5);  //返回[1,2,3,4,5]
a.concat([4, 5]);  //返回[1,2,3,4,5]
a.concat([4, 5], [6, 7]);  //返回[1,2,3,4,5,6,7]
a.concat(4, [5, [6, 7]]);  //返回[1,2,3,4,5,[6,7]]

slice()

Array.slice()方法返回指定數組的一個片段或子數組。它的兩個參數分別指定了片段的開始和結束的位置。返回的數組包含第一個參數指定的位置和所有到但不含第二個參數指定的位置之間的所有數組元素。如果只指定一個參數,返回的數組將包含從開始位置到數組結尾的所有元素。如參數中出現負數,它表示相對于數組中最后一個元素的位置。例如,參數-1指定了最后一個元素,而-3指定了倒數第三個元素。注意,slice()不會修改調用的數組。下面有一些示例:

var a = [1, 2, 3, 4, 5];
a.slice(0, 3);  //返回[1,2,3]
a.slice(3);  //返回[4,5]
a.slice(1, -1);  //返回[2,3,4]
a.slice(-3, -2);  //返回[3]

splice()

Array.splice()方法是在數組中插入或刪除元素的通用方法。不同于slice()和concat(),splice()會修改調用的數組。注意,splice()和slice()擁有非常相似的名字,但它們的功能卻有本質的區別。

splice()能夠從數組中刪除元素、插入元素到數組中或者同時完成這兩種操作。在插入或刪除點之后的數組元素會根據需要增加或減小它們的索引值,因此數組的其他部分仍然保持連續的。splice()的第一個參數指定了插入和(或)刪除的起始位置。第二個參數指定了應該從數組中刪除的元素的個數。如果省略第二個參數,從起始點開始到數組結尾的所有元素都將被刪除。splice()返回一個由刪除元素組成的數組,或者如果沒有刪除元素就返回一個空數組。例如:

var a = [1, 2, 3, 4, 5, 6, 7, 8];
a.splice(4);  //返回[5,6,7,8];a是[1,2,3,4]
a.splice(1, 2);  //返回[2,3];a是[1,4]
a.splice(1, 1);  //返回[4];a是[1]

splice()的前兩個參數指定了需要刪除的數組元素。緊隨其后的任意個數的參數指定了需要插入到數組中的元素,從第一個參數指定的位置開始插入。例如:

var a = [1, 2, 3, 4, 5];
a.splice(2, 0, 'a', 'b');  //返回[];a是[1,2,'a','b',3,4,5]
a.splice(2, 2, [1, 2], 3);  //返回['a','b'];a是[1,2,[1,2],3,3,4,5]

注意,區別于concat(),splice()會插入數組本身而非數組的元素。

push()和pop()

push()和pop()方法允許將數組當做棧來使用。push()方法在數組的尾部添加一個或多個元素,并返回數組新的長度。pop()方法則相反:它刪除數組的最后一個元素,減小數組長度并返回它刪除的值。注意,兩個方法都修改并替換原始數組而非生成一個修改版的新數組。組合使用push()和pop()能夠用JavaScript數組實現先進后出的棧。例如:

var stack = [];  //stack:[]
stack.push(1, 2);  //stack:[1,2] 返回2
stack.pop();  //stack:[1] 返回2
stack.push(3);  //stack:[1,3] 返回2
stack.pop();  //stack:[1] 返回3
stack.push([4, 5]);  //stack:[1,[4,5]] 返回2
stack.pop();  //stack:[1] 返回[4,5]
stack.pop();  //stack:[] 返回1

unshift()和shift()

unshift()和shift()方法的行為非常類似于push()和pop(),不一樣的是前者是在數組的頭部而非尾部進行元素的插入和刪除操作。unshift()在數組的頭部添加一個或多個元素,并將已存在的元素移動到更高索引的位置來獲得足夠的空間,最后返回數組新的長度。shift()刪除數組的第一個元素并將其返回,然后把所有隨后的元素下移一個位置來填補數組頭部的空缺。例如:

var a = [];  //a:[]
a.unshift(1);  //a:[1]返回:1
a.unshift(22);  //a:[22,1]返回:2
a.shift();  //a:[1]返回:22
a.unshift(3, [4, 5]);  //a:[3,[4,5],1]返回:3
a.shift();  //a:[[4,5],1]返回:3
a.shift();  //a:[1]返回:[4,5]
a.shift();  //a:[]返回:1

注意,當使用多個參數調用unshift()時它的行為令人驚訝。參數是一次性插入的(就像splice()方法)而非一次一個地插入。這意味著最終的數組中插入的元素的順序和它們在參數列表中的順序一致。而假如元素是一次一個地插入,它們的順序應該是反過來的。

toString()和toLocaleString()

數組和其他JavaScript對象一樣擁有toString()方法。針對數組,該方法將其每個元素轉化為字符串(如有必要將調用元素的toString()方法)并且輸出用逗號分隔的字符串列表。注意,輸出不包括方括號或其他任何形式的包裹數組值的分隔符。例如:

[1,2,3].toString();  //生成'1,2,3'
["a","b","c"].toString();  //生成'a,b,c'
[1,[2,'c']].toString();  //生成'1,2,c'

注意,這里與不使用任何參數調用join()方法返回的字符串是一樣的。

toLocaleString()是toString()方法的本地化版本。它調用元素的toLocaleString()方法將每個數組元素轉化為字符串,并且使用本地化(和自定義實現的)分隔符將這些字符串連接起來生成最終的字符串。

forEach()

forEach()方法從頭至尾遍歷數組,為每個元素調用指定的函數。如上所述,傳遞的函數作為forEach()的第一個參數。然后forEach()使用三個參數調用該函數:數組元素、元素的索引和數組本身。如果只關心數組元素的值,可以編寫只有一個參數的函數——額外的參數將忽略:

var data = [1, 2, 3, 4, 5];  //要求和的數組

//計算數組元素的和值
var sum = 0;  //初始為0
data.forEach(function(value) {sum += value;});  //將每個值累加到sum上
sum;  //=>15//每個數組元素的值自加1

data.forEach(function(v, i, a) {a[i] = v + 1;});
data;  //=>[2,3,4,5,6]

map()

map()方法將調用的數組的每個元素傳遞給指定的函數,并返回一個數組,它包含該函數的返回值。例如:

a = [1, 2, 3];
b = a.map(function(x) {return x * x;});  //b是[1,4,9]

傳遞給map()的函數的調用方式和傳遞給forEach()的函數的調用方式一樣,但傳遞給map()的函數應該有返回值。注意,map()返回的是新數組:它不修改調用的數組。如果是稀疏數組,返回的也是相同方式的稀疏數組:它具有相同的長度,相同的缺失元素。

filter()

filter()方法返回的數組元素是調用的數組的一個子集。傳遞的函數是用來邏輯判定的:該函數返回true或false,調用判定函數就像調用forEach()和map()一樣。如果返回值為true或能轉化為true的值,那么傳遞給判定函數的元素就是這個子集的成員,它將被添加到一個作為返回值的數組中。例如:

a = [5, 4, 3, 2, 1];
smallvalues = a.filter(function(x) {return x < 3});  //[2,1]
everyother = a.filter(function(x, i) {return i % 2 == 0});  //[5,3,1]

注意,filter()會跳過稀疏數組中缺少的元素,它的返回數組總是稠密的。為了壓縮稀疏數組的空缺,代碼如下:

var dense = sparse.filter(function() {return true;});

甚至,壓縮空缺并刪除undefined和null元素,可以這樣使用filter():

a = a.filter(function(x) {return x !== undefined && x != null;});

every()和some()

every()和some()方法是數組的邏輯判定:它們對數組元素應用指定的函數進行判定,返回true或false。

every()方法就像數學中的“針對所有”的量詞:當且僅當針對數組中的所有元素調用判定函數都返回true,它才返回true:

a = [1, 2, 3, 4, 5];
a.every(function(x) {return x < 10;});  //=>true:所有的值<10
a.every(function(x) {return x % 2 === 0;});  //=>false:不是所有的值都是偶數

some()方法就像數學中的“存在”的量詞:當數組中至少有一個元素調用判定函數返回true,它就返回true;并且當且僅當數值中的所有元素調用判定函數都返回false,它才返回false:

a = [1, 2, 3, 4, 5];
a.some(function(x) {return x % 2 === 0;});  //=>true:a含有偶數值
a.some(isNaN);  //=>false:a不包含非數值元素

注意,一旦every()和some()確認該返回什么值它們就會停止遍歷數組元素。some()在判定函數第一次返回true后就返回true,但如果判定函數一直返回false,它將會遍歷整個數組。every()恰好相反:它在判定函數第一次返回false后就返回false,但如果判定函數一直返回true,它將會遍歷整個數組。注意,在空數組上調用時,every()返回true,some()返回false。

reduce()和reduceRight()

reduce()和reduceRight()方法使用指定的函數將數組元素進行組合,生成單個值。這在函數式編程中是常見的操作,也可以稱為“注入”和“折疊”。舉例說明它是如何工作的:

var a = [1, 2, 3, 4, 5]
var sum = a.reduce(function(x, y) {return x + y}, 0);  //數組求和
var product = a.reduce(function(x, y) {return x * y},1);  //數組求積
var max = a.reduce(function(x, y) {return(x > y) ? x : y;});  //求最大值

reduce()需要兩個參數。第一個是執行化簡操作的函數。化簡函數的任務就是用某種方法把兩個值組合或化簡為一個值,并返回化簡后的值。在上述例子中,函數通過加法、乘法或取最大值的方法組合兩個值。第二個(可選)的參數是一個傳遞給函數的初始值。

reduce()使用的函數與forEach()和map()使用的函數不同。比較熟悉的是,數組元素、元素的索引和數組本身將作為第2~4個參數傳遞給函數。第一個參數是到目前為止的化簡操作累積的結果。第一次調用函數時,第一個參數是一個初始值,它就是傳遞給reduce()的第二個參數。在接下來的調用中,這個值就是上一次化簡函數的返回值。在上面的第一個例子中,第一次調用化簡函數時的參數是0和1。將兩者相加并返回1。再次調用時的參數是1和2,它返回3。然后它計算3+3=6、6+4=10,最后計算10+5=15。最后的值是15,reduce()返回這個值。

可能已經注意到了,上面第三次調用reduce()時只有一個參數:沒有指定初始值。當不指定初始值調用reduce()時,它將使用數組的第一個元素作為其初始值。這意味著第一次調用化簡函數就使用了第一個和第二個數組元素作為其第一個和第二個參數。在上面求和與求積的例子中,可以省略初始值參數。

在空數組上,不帶初始值參數調用reduce()將導致類型錯誤異常。如果調用它的時候只有一個值——數組只有一個元素并且沒有指定初始值,或者有一個空數組并且指定一個初始值——reduce()只是簡單地返回那個值而不會調用化簡函數。

reduceRight()的工作原理和reduce()一樣,不同的是它按照數組索引從高到低(從右到左)處理數組,而不是從低到高。

indexOf()和lastIndexOf()

indexOf()和lastIndexOf()搜索整個數組中具有給定值的元素,返回找到的第一個元素的索引或者如果沒有找到就返回-1。indexOf()從頭至尾搜索,而lastIndexOf()則反向搜索。

a = [0, 1, 2, 1, 0];
a.indexOf(1);  //=>1:a[1]是1
a.lastIndexOf(1);  //=>3:a[3]是1
a.indexOf(3);  //=>-1:沒有值為3的元素

第一個參數是需要搜索的值,第二個參數是可選的:它指定數組中的一個索引,從那里開始搜索。如果省略該參數,indexOf()從頭開始搜索,而lastIndexOf()從末尾開始搜索。第二個參數也可以是負數,它代表相對數組末尾的偏移量。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容