天來(lái)重學(xué) JavaScript 中的數(shù)組,看看有哪些你不知道的細(xì)節(jié)!
數(shù)組是最常用的數(shù)據(jù)類型之一,ECMAScript數(shù)組跟其他語(yǔ)言的數(shù)組一樣,都是一組有序的數(shù)據(jù),但跟其他語(yǔ)言不同的是,數(shù)組中每個(gè)槽位可以存儲(chǔ)任意類型的數(shù)據(jù)。除此之外,ECMAScript數(shù)組的長(zhǎng)度也是動(dòng)態(tài)的,會(huì)隨著數(shù)據(jù)的增刪而改變。
數(shù)組是被等分為許多小塊的連續(xù)內(nèi)存段,每個(gè)小塊都和一個(gè)整數(shù)關(guān)聯(lián),可以通過(guò)這個(gè)整數(shù)快速訪問(wèn)對(duì)應(yīng)的小塊。除此之外,數(shù)組擁有一個(gè)length屬性,該屬性表示的并不是數(shù)組元素的數(shù)量,而是指數(shù)組元素的最高序號(hào)加1。
let a=[1, 2, 3];
a.length===3
在ES6中,可以使用擴(kuò)展運(yùn)算符(...)來(lái)獲取數(shù)組元素:
let a=[1, 2, 3];
let b=[0, ...a, 4];
數(shù)組的創(chuàng)建方式有以下兩種。
最常用的創(chuàng)建數(shù)組的方式就是數(shù)組字面量,數(shù)組元素的類型可以是任意的,如下:
let colors=["red", [1, 2, 3], true];
使用構(gòu)造函數(shù)創(chuàng)建數(shù)組的形式如下:
let array=new Array();
如果已知數(shù)組元素?cái)?shù)量,那么就可以給構(gòu)造函數(shù)傳入一個(gè)數(shù)值,然后length屬性就會(huì)被自動(dòng)創(chuàng)建并保存這個(gè)值,比如創(chuàng)建一個(gè)長(zhǎng)度為10的數(shù)組:
let array=new Array(); // [undefined × 10]
這樣,就可以創(chuàng)建一個(gè)長(zhǎng)度為10的數(shù)組,數(shù)組每個(gè)元素的值都是undefined。
還可以給Array構(gòu)造函數(shù)傳入要保存的元素,比如:
let colors=new Array("red", "blue", "green");
這就出現(xiàn)問(wèn)題了,當(dāng)我們創(chuàng)建數(shù)組時(shí),如果給數(shù)組傳入一個(gè)值,如果傳入的值是數(shù)字,那么就會(huì)創(chuàng)建一個(gè)長(zhǎng)度為指定數(shù)字的數(shù)組;如果這個(gè)值是其他類型,就會(huì)創(chuàng)建一個(gè)質(zhì)保函該特定制度額數(shù)組。這樣我們就無(wú)法直接創(chuàng)建一個(gè)只包含一個(gè)數(shù)字的數(shù)組了。
Array 構(gòu)造函數(shù)根據(jù)參數(shù)長(zhǎng)度的不同,有如下兩種不同的處理方式:
在使用Array構(gòu)造函數(shù)時(shí),也可以省略 new 操作符,結(jié)果是一樣的:
let array=Array();
鑒于數(shù)組的常用性,ES6 專門(mén)擴(kuò)展了數(shù)組構(gòu)造器 Array ,新增了 2 個(gè)方法:Array.of和Array.from。Array.of 用得比較少,Array.from 具有很強(qiáng)的靈活性。
Array.of 用于將參數(shù)依次轉(zhuǎn)化為數(shù)組項(xiàng),然后返回這個(gè)新數(shù)組。它基本上與 Array 構(gòu)造器功能一致,唯一的區(qū)別就在單個(gè)數(shù)字參數(shù)的處理上。
比如,在下面的代碼中,可以看到:當(dāng)參數(shù)為2個(gè)時(shí),返回的結(jié)果是一致的;當(dāng)參數(shù)是一個(gè)時(shí),Array.of 會(huì)把參數(shù)變成數(shù)組里的一項(xiàng),而構(gòu)造器則會(huì)生成長(zhǎng)度和第一個(gè)參數(shù)相同的空數(shù)組:
Array.of(8.0); // [8]
Array(8.0); // [empty × 8]
Array.of(8.0, 5); // [8, 5]
Array(8.0, 5); // [8, 5]
Array.of('8'); // ["8"]
Array('8'); // ["8"]
Array.from? 的設(shè)計(jì)初衷是快速基于其他對(duì)象創(chuàng)建新數(shù)組,準(zhǔn)確來(lái)說(shuō)就是從一個(gè)類似數(shù)組的可迭代對(duì)象中創(chuàng)建一個(gè)新的數(shù)組實(shí)例。其實(shí),只要一個(gè)對(duì)象有迭代器,Array.from 就能把它變成一個(gè)數(shù)組(注意:該方法會(huì)返回一個(gè)的數(shù)組,不會(huì)改變?cè)瓕?duì)象)。
從語(yǔ)法上看,Array.from 有 3 個(gè)參數(shù):
這三個(gè)參數(shù)里面第一個(gè)參數(shù)是必選的,后兩個(gè)參數(shù)都是可選的:
var obj={0: 'a', 1: 'b', 2:'c', length: 3};
Array.from(obj, function(value, index){
console.log(value, index, this, arguments.length);
return value.repeat(3); //必須指定返回值,否則返回 undefined
}, obj);
結(jié)果如圖:
以上結(jié)果表明,通過(guò) Array.from 這個(gè)方法可以自定義加工函數(shù)的處理方式,從而返回想要得到的值;如果不確定返回值,則會(huì)返回 undefined,最終生成的是一個(gè)包含若干個(gè) undefined 元素的空數(shù)組。
實(shí)際上,如果這里不指定 this,加工函數(shù)就可以是一個(gè)箭頭函數(shù)。上述代碼可以簡(jiǎn)寫(xiě)為以下形式。
Array.from(obj, (value)=> value.repeat(3));
// 控制臺(tái)打印 (3) ["aaa", "bbb", "ccc"]
除了上述 obj 對(duì)象以外,擁有迭代器的對(duì)象還包括 String、Set、Map 等,Array.from 都可以進(jìn)行處理:
// String
Array.from('abc'); // ["a", "b", "c"]
// Set
Array.from(new Set(['abc', 'def'])); // ["abc", "def"]
// Map
Array.from(new Map([[1, 'ab'], [2, 'de']])); // [[1, 'ab'], [2, 'de']]
當(dāng)我們使用數(shù)組字面量初始化數(shù)組時(shí),可以使用一串逗號(hào)來(lái)創(chuàng)建空位,ECMAScript會(huì)將逗號(hào)之間相應(yīng)索引位置的值當(dāng)成空位,ES6 重新定義了該如何處理這些空位。
我們可以這樣來(lái)創(chuàng)建一個(gè)空位數(shù)組:
let array=[,,,,,];
console.log(array.length);
console.log(array)
運(yùn)行結(jié)果如下:
ES6新增的方法和迭代器與早期版本中存在的方法的行為不同,ES6新增方法普遍將這些空位當(dāng)成存在的元素,只不過(guò)值為undefined,使用字面量形式創(chuàng)建如下數(shù)組:
let array=[1,,,5];
for(let i of array){
console.log(i===undefined)
}
// 輸出結(jié)果:false true true false
使用ES6的Array.form創(chuàng)建數(shù)組:
let array=Array.from([1,,,5]);
for(let i of array){
console.log(i===undefined)
}
// 輸出結(jié)果:false true true false
而ES6之前的方法則會(huì)忽略這個(gè)空位:
let array=[1,,,5];
console.log(array.map(()=> 10))
// 輸出結(jié)果:[10, undefined, undefined, 10]
由于不同方法對(duì)空位數(shù)組的處理方式不同,因此盡量避免使用空位數(shù)組。
在數(shù)組中,我們可以通過(guò)使用數(shù)組的索引來(lái)獲取數(shù)組的值:
let colors=new Array("red", "blue", "green");
console.log(array[1]) // blue
如果指定的索引值小于數(shù)組的元素?cái)?shù),就會(huì)返回存儲(chǔ)在相應(yīng)位置的元素,也可以通過(guò)這種方式來(lái)設(shè)置一個(gè)數(shù)組元素的值。如果設(shè)置的索引值大于數(shù)組的長(zhǎng)度,那么就會(huì)將數(shù)組長(zhǎng)度擴(kuò)充至該索引值加一。
數(shù)組長(zhǎng)度length的獨(dú)特之處在于,他不是只讀的。通過(guò)length屬性,可以在數(shù)組末尾增加刪除元素:
let colors=new Array("red", "blue", "green");
colors.length=2
console.log(colors[2]) // undefined
colors.length=4
console.log(colors[3]) // undefined
數(shù)組長(zhǎng)度始終比數(shù)組最后一個(gè)值得索引大1,這是因?yàn)樗饕刀际菑?開(kāi)始的。
一個(gè)很經(jīng)典的ECMASript問(wèn)題就是如何判斷一個(gè)對(duì)象是不是數(shù)組,下面來(lái)看常用的數(shù)據(jù)類型檢測(cè)的方法。
在 ES6 之前,至少有如下 5 種方式去判斷一個(gè)對(duì)象是否為數(shù)組。
Object.prototype.toString.call(obj).slice(8,-1)==='Array';
obj.constructor===Array;
obj instanceof Array
Array.prototype.isPrototypeOf(obj)
Object.getPrototypeOf(obj)===Array.prototype;
如果obj是一個(gè)數(shù)組,那么上面這 5 個(gè)判斷全部為 true,推薦通過(guò) Object.prototype.toString 去判斷一個(gè)值的類型。
ES6 新增了 Array.isArray 方法,可以直接判斷數(shù)據(jù)類型是否為數(shù)組:
Array.isArrray(obj);
如果 isArray 不存在,那么 Array.isArray 的 polyfill 通??梢赃@樣寫(xiě):
if (!Array.isArray){
Array.isArray=function(arg){
return Object.prototype.toString.call(arg)==='[object Array]';
};
}
數(shù)字就像是一個(gè)森林,里面有很多函“樹(shù)”,有些方法純凈如水,并不會(huì)改變?cè)瓟?shù)組,有些則會(huì)改變?cè)瓟?shù)組。
ES提供了兩個(gè)方法:批量復(fù)制方法copeWithin(),以及填充數(shù)組方法fill()。這兩個(gè)方法的簽名類似,都需要指定已有數(shù)組實(shí)例上的一個(gè)范圍,包含開(kāi)始索引,不包含結(jié)束索引。下面就分別來(lái)看一下這兩個(gè)方法。
使用fill()方法可以向一個(gè)已有數(shù)組中插入全部或部分相同的值,開(kāi)始索引用于指定開(kāi)始填充的位置,它是可選的。如果不提供結(jié)束索引,則一直填充到數(shù)組末尾。如果是負(fù)值,則將從負(fù)值加上數(shù)組的長(zhǎng)度而得到的值開(kāi)始。該方法的語(yǔ)法如下:
array.fill(value, start, end)
其參數(shù)如下:
使用示例如下:
const arr=[0, 0, 0, 0, 0];
// 用5填充整個(gè)數(shù)組
arr.fill(5);
console.log(arr); // [5, 5, 5, 5, 5]
arr.fill(0); // 重置
// 用5填充索引大于等于3的元素
arr.fill(5, 3);
console.log(arr); // [0, 0, 0, 5, 5]
arr.fill(0); // 重置
// 用5填充索引大于等于1且小于等于3的元素
arr.fill(5, 3);
console.log(arr); // [0, 5, 5, 0, 0]
arr.fill(0); // 重置
// 用5填充索引大于等于-1的元素
arr.fill(5, -1);
console.log(arr); // [0, 0, 0, 0, 5]
arr.fill(0); // 重置
copyWithin()方法會(huì)按照指定范圍來(lái)淺復(fù)制數(shù)組中的部分內(nèi)容,然后將它插入到指定索引開(kāi)始的位置,開(kāi)始與結(jié)束索引的計(jì)算方法和fill方法一樣。該方法的語(yǔ)法如下:
array.copyWithin(target, start, end)
其參數(shù)如下:
使用示例如下:
const array=[1,2,3,4,5];
console.log(array.copyWithin(0,3));
數(shù)組的轉(zhuǎn)化方法主要有四個(gè):toLocaleString()、toString()、valueOf()、join()。下面就分別來(lái)看一下這4個(gè)方法。
toString()方法返回的是由數(shù)組中每個(gè)值的等效字符串拼接而成的一個(gè)逗號(hào)分隔的字符串,也就是說(shuō),對(duì)數(shù)組的每個(gè)值都會(huì)調(diào)用toString()方法,以得到最終的字符串:
let colors=["red", "blue", "green"];
console.log(colors.toString()) // red,blue,green
valueOf()方法返回的是數(shù)組本身,如下面代碼:
let colors=["red", "blue", "green"];
console.log(colors.valueOf()) // ["red", "blue", "green"]
toLocaleString()方法可能會(huì)返回和toString()方法相同的結(jié)果,但也不一定。在調(diào)用toLocaleString()方法時(shí)會(huì)得到一個(gè)逗號(hào)分隔的數(shù)組值的字符串,它與toString()方法的區(qū)別是,為了得到最終的字符串,會(huì)調(diào)用每個(gè)值的toLocaleString()方法,而不是toString()方法,看下面的例子:
let array=[{name:'zz'}, 123, "abc", new Date()];
let str=array.toLocaleString();
console.log(str); // [object Object],123,abc,2016/1/5 下午1:06:23
需要注意,如果數(shù)組中的某一項(xiàng)是null或者undefined,則在調(diào)用上述三個(gè)方法后,返回的結(jié)果中會(huì)以空字符串來(lái)表示。
join() 方法用于把數(shù)組中的所有元素放入一個(gè)字符串。元素是通過(guò)指定的分隔符進(jìn)行分隔的。其使用語(yǔ)法如下:
arrayObject.join(separator)
其中參數(shù)separator是可選的,用來(lái)指定要使用的分隔符。如果省略該參數(shù),則使用逗號(hào)作為分隔符。
該方法返回一個(gè)字符串。該字符串是通過(guò)把 arrayObject 的每個(gè)元素轉(zhuǎn)換為字符串,然后把這些字符串連接起來(lái),在兩個(gè)元素之間插入 separator 字符串而生成的。
使用示例如下:
let array=["one", "two", "three","four", "five"];
console.log(array.join()); // one,two,three,four,five
console.log(array.join("-")); // one-two-three-four-five
ECMAScript給數(shù)組添加了幾個(gè)方法來(lái)使它像棧一樣。眾所周知,棧是一種后進(jìn)先出的結(jié)構(gòu),也就是最近添加的項(xiàng)先被刪除。數(shù)據(jù)項(xiàng)的插入(稱為推入,push),和刪除(稱為彈出,pop)只在棧頂發(fā)生。數(shù)組提高了push()和pop()來(lái)實(shí)現(xiàn)類似棧的行為。下面就分別來(lái)看看這兩個(gè)方法。
push()方法可以接收任意數(shù)量的參數(shù),并將它們添加了數(shù)組末尾,并返回?cái)?shù)組新的長(zhǎng)度。該方法會(huì)改變?cè)瓟?shù)組。 其語(yǔ)法形式如下:
arrayObject.push(newelement1,newelement2,....,newelementX)
使用示例如下:
let array=["football", "basketball", "badminton"];
let i=array.push("golfball");
console.log(array); // ["football", "basketball", "badminton", "golfball"]
console.log(i); // 4
pop() 方法用于刪除并返回?cái)?shù)組的最后一個(gè)元素。它沒(méi)有參數(shù)。該方法會(huì)改變?cè)瓟?shù)組。 其語(yǔ)法形式如下:
arrayObject.pop()
使用示例如下:
let array=["cat", "dog", "cow", "chicken", "mouse"];
let item=array.pop();
console.log(array); // ["cat", "dog", "cow", "chicken"]
console.log(item); // mouse
隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),隊(duì)列在隊(duì)尾添加元素,在對(duì)頭刪除元素。上面我們已經(jīng)說(shuō)了在結(jié)果添加數(shù)據(jù)的方法push(),下面就再來(lái)看看從數(shù)組開(kāi)頭刪除和添加元素的方法:shift()和unshift()。實(shí)際上unshift()并不屬于操作隊(duì)列的方法,不過(guò)這里也一起說(shuō)了。
shift()方法會(huì)刪除數(shù)組的第一項(xiàng),并返回它,然后數(shù)組長(zhǎng)度減一,該方法會(huì)改變?cè)瓟?shù)組。 語(yǔ)法形式如下:
arrayObject.shift()
使用示例如下:
let array=[1,2,3,4,5];
let item=array.shift();
console.log(array); // [2,3,4,5]
console.log(item); // 1
注意:如果數(shù)組是空的,那么 shift() 方法將不進(jìn)行任何操作,返回 undefined 值。
unshift()方法可向數(shù)組的開(kāi)頭添加一個(gè)或更多元素,并返回新的長(zhǎng)度。該方法會(huì)改變?cè)瓟?shù)組。 其語(yǔ)法形式如下:
arrayObject.unshift(newelement1,newelement2,....,newelementX)
使用示例如下:
let array=["red", "green", "blue"];
let length=array.unshift("yellow");
console.log(array); // ["yellow", "red", "green", "blue"]
console.log(length); // 4
數(shù)組有兩個(gè)方法可以對(duì)數(shù)組進(jìn)行重新排序:sort()和reverse()。下面就分別來(lái)看看這兩個(gè)方法。
sort()方法是我們常用給的數(shù)組排序方法,該方法會(huì)在原數(shù)組上進(jìn)行排序,會(huì)改變?cè)瓟?shù)組,其使用語(yǔ)法如下:
arrayObject.sort(sortby)
其中參數(shù)sortby是可選參數(shù),用來(lái)規(guī)定排序順序,它是一個(gè)比較函數(shù),用來(lái)判斷哪個(gè)值應(yīng)該排在前面。默認(rèn)情況下,sort()方法會(huì)按照升序重新排列數(shù)組元素。為此,sort()方法會(huì)在每一個(gè)元素上調(diào)用String轉(zhuǎn)型函數(shù),然后比較字符串來(lái)決定順序,即使數(shù)組的元素都是數(shù)值,也會(huì)將數(shù)組元素先轉(zhuǎn)化為字符串在進(jìn)行比較、排序。這就造成了排序不準(zhǔn)確的情況,如下代碼:
let array=[5, 4, 3, 2, 1];
let array2=array.sort();
console.log(array2) // [1, 2, 3, 4, 5]
let array=[0, 1, 5, 10, 15];
let array2=array.sort();
console.log(array2) // [0, 1, 10, 15, 5]
可以看到,上面第二段代碼就出現(xiàn)了問(wèn)題,雖然5是小于10的,但是字符串10在5的前面,所以10還是會(huì)排在5前面,因此可知,在很多情況下,不添加參數(shù)是不行的。
對(duì)于sort()方法的參數(shù),它是一個(gè)比較函數(shù),它接收兩個(gè)參數(shù),如果第一個(gè)參數(shù)應(yīng)該排在第二個(gè)參數(shù)前面,就返回-1;如果兩個(gè)參數(shù)相等,就返回0;如果第一個(gè)參數(shù)應(yīng)該排在第二個(gè)參數(shù)后面,就返回1。一個(gè)比較函數(shù)的形式可以如下:
function compare(value1, value2) {
if(value1 < value2){
return -1
} else if(value1 > value2){
return 1
} else{
return 0
}
}
let array=[0, 1, 5, 10, 15];
let array2=array.sort(compare);
console.log(array2) // [0, 1, 5, 10, 15]
使用箭頭函數(shù)來(lái)定義:
let array=[0, 1, 5, 10, 15];
let array2=array.sort((a, b)=> a - b); // 正序排序
console.log(array2) // [0, 1, 5, 10, 15]
let array3=array.sort((a, b)=> b - a); // 倒序排序
console.log(array3) // [15, 10, 5, 1, 0]
reverse() 方法用于顛倒數(shù)組中元素的順序。該方法會(huì)改變?cè)瓉?lái)的數(shù)組,而不會(huì)創(chuàng)建新的數(shù)組。其使用語(yǔ)法如下:
arrayObject.reverse()
使用示例如下:
let array=[1,2,3,4,5];
let array2=array.reverse();
console.log(array); // [5,4,3,2,1]
console.log(array2===array); // true
對(duì)于數(shù)組,還有很多操作方法,下面我們就來(lái)看看常用的concat()、slice()、splice()方法。
concat() 方法用于連接兩個(gè)或多個(gè)數(shù)組。該方法不會(huì)改變現(xiàn)有的數(shù)組,而僅僅會(huì)返回被連接數(shù)組的一個(gè)副本。其適用語(yǔ)法如下:
arrayObject.concat(arrayX,arrayX,......,arrayX)
其中參數(shù)arrayX是必需的。該參數(shù)可以是具體的值,也可以是數(shù)組對(duì)象??梢允侨我舛鄠€(gè)。
使用示例如下:
let array=[1, 2, 3];
let array2=array.concat(4, [5, 6], [7, 8, 9]);
console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(array); // [1, 2, 3], 可見(jiàn)原數(shù)組并未被修改
該方法還可以用于數(shù)組扁平化,后面會(huì)介紹。
slice() 方法可從已有的數(shù)組中返回選定的元素。返回一個(gè)新的數(shù)組,包含從 start 到 end (不包括該元素)的數(shù)組元素。方法并不會(huì)修改數(shù)組,而是返回一個(gè)子數(shù)組。其使用語(yǔ)法如下:
arrayObject.slice(start,end)
其參數(shù)如下:
使用示例如下:
let array=["one", "two", "three", "four", "five"];
console.log(array.slice(0)); // ["one", "two", "three","four", "five"]
console.log(array.slice(2,3)); // ["three"]
splice()方法可能是數(shù)組中的最強(qiáng)大的方法之一了,使用它的形式有很多種,它會(huì)向/從數(shù)組中添加/刪除項(xiàng)目,然后返回被刪除的項(xiàng)目。該方法會(huì)改變?cè)紨?shù)組。其使用語(yǔ)法如下:
arrayObject.splice(index, howmany, item1,.....,itemX)
其參數(shù)如下:
從上面參數(shù)可知,splice主要有三種使用形式:
使用示例如下:
let array=["one", "two", "three","four", "five"];
console.log(array.splice(1, 2)); // 刪除:["two", "three"]
let array=["one", "two", "three","four", "five"];
console.log(array.splice(2, 0, 996)); // 插入:[]
let array=["one", "two", "three","four", "five"];
console.log(array.splice(2, 1, 996)); // 替換:["three"]
ECMAScript為數(shù)組提供了兩個(gè)歸并方法:reduce()和reduceRight()。下面就分別來(lái)看看這兩個(gè)方法。
reduce() 方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值。其使用語(yǔ)法如下:
arr.reduce(callback,[initialValue])
reduce 為數(shù)組中的每一個(gè)元素依次執(zhí)行回調(diào)函數(shù),不包括數(shù)組中被刪除或從未被賦值的元素,接受四個(gè)參數(shù):初始值(或者上一次回調(diào)函數(shù)的返回值),當(dāng)前元素值,當(dāng)前索引,調(diào)用 reduce 的數(shù)組。(1) callback (執(zhí)行數(shù)組中每個(gè)值的函數(shù),包含四個(gè)參數(shù))
(2) initialValue (作為第一次調(diào)用 callback 的第一個(gè)參數(shù)。)
let arr=[1, 2, 3, 4]
let sum=arr.reduce((prev, cur, index, arr)=> {
console.log(prev, cur, index);
return prev + cur;
})
console.log(arr, sum);
輸出結(jié)果如下:
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
再來(lái)加一個(gè)初始值看看:
let arr=[1, 2, 3, 4]
let sum=arr.reduce((prev, cur, index, arr)=> {
console.log(prev, cur, index);
return prev + cur;
}, 5)
console.log(arr, sum);
輸出結(jié)果如下:
5 1 0
6 2 1
8 3 2
11 4 3
[1, 2, 3, 4] 15
通過(guò)上面例子,可以得出結(jié)論:如果沒(méi)有提供initialValue,reduce 會(huì)從索引1的地方開(kāi)始執(zhí)行 callback 方法,跳過(guò)第一個(gè)索引。如果提供initialValue,從索引0開(kāi)始。
注意,該方法如果添加初始值,就會(huì)改變?cè)瓟?shù)組,將這個(gè)初始值放在數(shù)組的最后一位。
該方法和的上面的reduce()?用法幾乎一致,只是該方法是對(duì)數(shù)組進(jìn)行倒序查找的。而reduce()方法是正序執(zhí)行的。
let arr=[1, 2, 3, 4]
let sum=arr.reduceRight((prev, cur, index, arr)=> {
console.log(prev, cur, index);
return prev + cur;
}, 5)
console.log(arr, sum);
輸出結(jié)果如下:
5 4 3
9 3 2
12 2 1
14 1 0
[1, 2, 3, 4] 15
ECMAScript提供了兩類搜索數(shù)組的方法:按照嚴(yán)格相等搜索和按照斷言函數(shù)搜索。
ECMAScript通過(guò)了3個(gè)嚴(yán)格相等的搜索方法:indexOf()、lastIndexOf()、includes()。這些方法都接收兩個(gè)參數(shù):要查找的元素和可選的其實(shí)搜索位置。lastIndexOf()方法會(huì)從數(shù)組結(jié)尾元素開(kāi)始向前搜索,其他兩個(gè)方法則會(huì)從數(shù)組開(kāi)始元素向后進(jìn)行搜索。indexOf()和lastIndexOf()返回的是查找元素在數(shù)組中的索引值,如果沒(méi)有找到,則返回-1。includes()方法會(huì)返回布爾值,表示是否找到至少一個(gè)與指定元素匹配的項(xiàng)。在比較第一個(gè)參數(shù)和數(shù)組的每一項(xiàng)時(shí),會(huì)使用全等(===)比較,也就是說(shuō)兩項(xiàng)必須嚴(yán)格相等。
使用示例如下:
let arr=[1, 2, 3, 4, 5];
console.log(arr.indexOf(2)) // 1
console.log(arr.lastIndexOf(3)) // 2
console.log(arr.includes(4)) // true
ECMAScript也允許按照定義的斷言函數(shù)搜索數(shù)組,每個(gè)索引都會(huì)調(diào)用這個(gè)函數(shù),斷言函數(shù)的返回值決定了相應(yīng)索引的元素是否被認(rèn)為匹配。使用斷言函數(shù)的方法有兩個(gè),分別是find()和findIndex()方法。這兩個(gè)方法對(duì)于空數(shù)組,函數(shù)是不會(huì)執(zhí)行的。并且沒(méi)有改變數(shù)組的原始值。他們的都有三個(gè)參數(shù):元素、索引、元素所屬的數(shù)組對(duì)象,其中元素是數(shù)組中當(dāng)前搜索的元素,索引是當(dāng)前元素的索引,而數(shù)組是當(dāng)前正在搜索的數(shù)組。
這兩個(gè)方法都從數(shù)組的開(kāi)始進(jìn)行搜索,find()返回的是第一個(gè)匹配的元素,如果沒(méi)有符合條件的元素返回 undefined;findIndex()返回的是第一個(gè)匹配的元素的索引,如果沒(méi)有符合條件的元素返回 -1。
使用示例如下:
let arr=[1, 2, 3, 4, 5]
arr.find(item=> item > 2) // 結(jié)果:3
arr.findIndex(item=> item > 2) // 結(jié)果:2
在ES6中,Array的原型上暴露了3個(gè)用于檢索數(shù)組內(nèi)容的方法:keys()、values()、entries()。keys()方法返回?cái)?shù)組索引的迭代器,values()方法返回?cái)?shù)組元素的迭代器,entries()方法返回索引值對(duì)的迭代器。
使用示例如下(因?yàn)檫@些方法返回的都是迭代器,所以可以將他們的內(nèi)容通過(guò)Array.from直接轉(zhuǎn)化為數(shù)組實(shí)例):
let array=["one", "two", "three", "four", "five"];
console.log(Array.from(array.keys())) // [0, 1, 2, 3, 4]
console.log(Array.from(array.values())) // ["one", "two", "three", "four", "five"]
console.log(Array.from(array.entries())) // [[0, "one"], [1, "two"], [2, "three"], [3, "four"], [4, "five"]]
ECMAScript為數(shù)組定義了5個(gè)迭代方法,分別是every()、filter()、forEach()、map()、some()。這些方法都不會(huì)改變?cè)瓟?shù)組。這五個(gè)方法都接收兩個(gè)參數(shù):以每一項(xiàng)為參數(shù)運(yùn)行的函數(shù)和可選的作為函數(shù)運(yùn)行上下文的作用域?qū)ο螅ㄓ绊懞瘮?shù)中的this值)。傳給每個(gè)方法的函數(shù)接收三個(gè)參數(shù),分別是當(dāng)前元素、當(dāng)前元素的索引值、當(dāng)前元素所屬的數(shù)對(duì)象。
forEach 方法用于調(diào)用數(shù)組的每個(gè)元素,并將元素傳遞給回調(diào)函數(shù)。該方法沒(méi)有返回值,使用示例如下:
let arr=[1,2,3,4,5]
arr.forEach((item, index, arr)=> {
console.log(index+":"+item)
})
該方法還可以有第二個(gè)參數(shù),用來(lái)綁定回調(diào)函數(shù)內(nèi)部this變量(回調(diào)函數(shù)不能是箭頭函數(shù),因?yàn)榧^函數(shù)沒(méi)有this):
let arr=[1,2,3,4,5]
let arr1=[9,8,7,6,5]
arr.forEach(function(item, index, arr){
console.log(this[index]) // 9 8 7 6 5
}, arr1)
map() 方法會(huì)返回一個(gè)新數(shù)組,數(shù)組中的元素為原始數(shù)組元素調(diào)用函數(shù)處理后的值。該方法按照原始數(shù)組元素順序依次處理元素。該方法不會(huì)對(duì)空數(shù)組進(jìn)行檢測(cè),它會(huì)返回一個(gè)新數(shù)組,不會(huì)改變?cè)紨?shù)組。使用示例如下:
let arr=[1, 2, 3];
arr.map(item=> {
return item+1;
})
// 結(jié)果: [2, 3, 4]
第二個(gè)參數(shù)用來(lái)綁定參數(shù)函數(shù)內(nèi)部的this變量:
var arr=['a', 'b', 'c'];
[1, 2].map(function (e) {
return this[e];
}, arr)
// 結(jié)果: ['b', 'c']
該方法可以進(jìn)行鏈?zhǔn)秸{(diào)用:
let arr=[1, 2, 3];
arr.map(item=> item+1).map(item=> item+1)
// 結(jié)果: [3, 4, 5]
forEach和map區(qū)別如下:
filter()方法用于過(guò)濾數(shù)組,滿足條件的元素會(huì)被返回。它的參數(shù)是一個(gè)回調(diào)函數(shù),所有數(shù)組元素依次執(zhí)行該函數(shù),返回結(jié)果為true的元素會(huì)被返回。該方法會(huì)返回一個(gè)新的數(shù)組,不會(huì)改變?cè)瓟?shù)組。
let arr=[1, 2, 3, 4, 5]
arr.filter(item=> item > 2)
// 結(jié)果:[3, 4, 5]
可以使用filter()方法來(lái)移除數(shù)組中的undefined、null、NAN等值
let arr=[1, undefined, 2, null, 3, false, '', 4, 0]
arr.filter(Boolean)
// 結(jié)果:[1, 2, 3, 4]
該方法會(huì)對(duì)數(shù)組中的每一項(xiàng)進(jìn)行遍歷,只有所有元素都符合條件時(shí),才返回true,否則就返回false。
let arr=[1, 2, 3, 4, 5]
arr.every(item=> item > 0)
// 結(jié)果:true
該方法會(huì)對(duì)數(shù)組中的每一項(xiàng)進(jìn)行遍歷,只要有一個(gè)元素符合條件,就返回true,否則就返回false。
在JavaScript中,定義數(shù)組并添加內(nèi)容非常簡(jiǎn)單。以下是一個(gè)基本的示例:
// 定義一個(gè)空數(shù)組
var myArray=[];
// 添加內(nèi)容到數(shù)組
myArray.push('第一項(xiàng)');
myArray.push('第二項(xiàng)');
myArray.push('第三項(xiàng)');
// 輸出數(shù)組內(nèi)容
console.log(myArray);
// 輸出: [ '第一項(xiàng)', '第二項(xiàng)', '第三項(xiàng)' ]
在這個(gè)例子中,我們首先定義了一個(gè)名為myArray的空數(shù)組。然后,我們使用push方法將三個(gè)字符串元素添加到數(shù)組中。最后,我們使用console.log來(lái)輸出數(shù)組的內(nèi)容。
另外,你還可以在定義數(shù)組的同時(shí)初始化其內(nèi)容,如下:
// 定義并初始化數(shù)組
var myArray=['第一項(xiàng)', '第二項(xiàng)', '第三項(xiàng)'];
// 輸出數(shù)組內(nèi)容
console.log(myArray);
// 輸出: [ '第一項(xiàng)', '第二項(xiàng)', '第三項(xiàng)' ]
在這個(gè)例子中,我們直接在定義數(shù)組的同時(shí)初始化了它的內(nèi)容。這種方式在你知道數(shù)組初始內(nèi)容的情況下非常有用。
在上面數(shù)組的基礎(chǔ)上,我們來(lái)讀取數(shù)組的長(zhǎng)度。以下是一個(gè)基本的示例:
// 讀取數(shù)組長(zhǎng)度
var arrayLength=myArray.length;
console.log('數(shù)組長(zhǎng)度:', arrayLength);
// 輸出: 數(shù)組長(zhǎng)度: 3
在這個(gè)例子中,我們使用myArray.length來(lái)獲取數(shù)組的長(zhǎng)度。
在上面數(shù)組的基礎(chǔ)上,我們來(lái)判斷數(shù)組是否為空。以下是一個(gè)基本的示例:
// 判斷數(shù)組是否為空
var isEmpty=myArray.length===0;
console.log('數(shù)組是否為空:', isEmpty);
// 輸出: 數(shù)組是否為空: false
在這個(gè)例子中,我們通過(guò)比較數(shù)組長(zhǎng)度是否為0來(lái)判斷數(shù)組是否為空。
在上面數(shù)組的基礎(chǔ)上,我們來(lái)使用forEach迭代輸出數(shù)組中的每一個(gè)元素。以下是一個(gè)基本的示例:
// 迭代輸出數(shù)組中的每一個(gè)元素
myArray.forEach(function(item, index) {
console.log('元素:', item, '索引:', index);
});
// 輸出:
// 元素: 第一項(xiàng) 索引: 0
// 元素: 第二項(xiàng) 索引: 1
// 元素: 第三項(xiàng) 索引: 2
在這個(gè)例子中,我們使用forEach方法來(lái)迭代數(shù)組,并輸出每個(gè)元素及其索引。
另外,我們還可以使用for循環(huán)迭代輸出數(shù)組中的每一個(gè)元素,以下是一個(gè)基本的示例:
for (var i=0; i < myArray.length; i++) {
console.log('元素:', myArray[i], '索引:', i);
}
// 輸出:
// 元素: 第一項(xiàng) 索引: 0
// 元素: 第二項(xiàng) 索引: 1
// 元素: 第三項(xiàng) 索引: 2
和for Each迭代結(jié)果是一樣的。但是也有區(qū)別,具體請(qǐng)“使用break退出循環(huán)”章節(jié)。
在上面數(shù)組的基礎(chǔ)上,我們來(lái)輸出數(shù)組中的第一個(gè)元素,如下:
// 獲取并輸出數(shù)組的第一個(gè)元素
var firstElement=myArray[0];
console.log('第一個(gè)元素:', firstElement);
// 輸出: 第一個(gè)元素: 第一項(xiàng)
在這個(gè)例子中,我們通過(guò)索引0獲取數(shù)組的第一個(gè)元素。
在上面數(shù)組的基礎(chǔ)上,我們來(lái)輸出數(shù)組中的最后一個(gè)元素,如下:
// 獲取并輸出數(shù)組的最后一個(gè)元素
var lastElement=myArray[myArray.length - 1];
console.log('最后一個(gè)元素:', lastElement);
// 輸出: 最后一個(gè)元素: 第三項(xiàng)
在這個(gè)例子中,我們通過(guò)索引myArray.length - 1獲取數(shù)組的最后一個(gè)元素。
在JavaScript中,forEach循環(huán)不能使用break語(yǔ)句來(lái)提前退出循環(huán)。forEach是數(shù)組的一個(gè)方法,它專門(mén)為迭代數(shù)組的每個(gè)元素而設(shè)計(jì),但不提供像傳統(tǒng)for循環(huán)那樣的退出機(jī)制。
如果你需要在迭代過(guò)程中提前退出,你可以考慮使用其他循環(huán)結(jié)構(gòu),如for循環(huán)、while循環(huán)或do...while循環(huán),或者使用數(shù)組方法如find、findIndex、some、every等,這些方法會(huì)在滿足某個(gè)條件時(shí)停止執(zhí)行回調(diào)函數(shù)。
例如,使用for循環(huán)和break:
for (var i=0; i < myArray.length; i++) {
if (/* 某個(gè)條件 */) {
break; // 退出循環(huán)
}
console.log('元素:', myArray[i], '索引:', i);
}
如果你只是想找到滿足某個(gè)條件的第一個(gè)元素,可以使用find方法:
var foundItem=myArray.find(function(item, index) {
if (/* 某個(gè)條件 */) {
return true; // 找到后,find方法會(huì)立即停止執(zhí)行并返回該元素
}
return false;
});
if (foundItem) {
console.log('找到的元素:', foundItem);
} else {
console.log('未找到滿足條件的元素');
}
在這個(gè)find方法的示例中,一旦回調(diào)函數(shù)返回true,find方法就會(huì)停止執(zhí)行,并返回當(dāng)前元素。如果沒(méi)有元素使回調(diào)函數(shù)返回true,則find方法返回undefined。
如果你想要獲取滿足條件的元素的索引,可以使用findIndex方法,它的工作方式與find類似,但返回的是元素的索引而不是元素本身。
下面的示例著重來(lái)介紹查找元素索引。
在JavaScript中,如果你想要返回?cái)?shù)組中指定元素的索引,你可以使用數(shù)組的indexOf方法或者findIndex方法。這兩個(gè)方法有不同的用途:
下面是使用這兩個(gè)方法返回指定元素索引的示例:
使用 indexOf 方法:
var myArray=['第一項(xiàng)', '第二項(xiàng)', '第三項(xiàng)'];
var targetElement='第二項(xiàng)';
var index=myArray.indexOf(targetElement);
if (index !==-1) {
console.log('元素的索引是:', index); // 輸出: 元素的索引是: 1
} else {
console.log('元素不在數(shù)組中');
}
使用 findIndex 方法(適用于更復(fù)雜的條件或當(dāng)元素不是原始類型時(shí)):
var myArray=[{ name: '第一項(xiàng)' }, { name: '第二項(xiàng)' }, { name: '第三項(xiàng)' }];
var targetElementName='第二項(xiàng)';
var index=myArray.findIndex(function(item) {
return item.name===targetElementName;
});
if (index !==-1) {
console.log('元素的索引是:', index); // 輸出: 元素的索引是: 1
} else {
console.log('元素不在數(shù)組中');
}
在findIndex的示例中,我們有一個(gè)包含對(duì)象的數(shù)組,我們想要找到name屬性為第二項(xiàng)的對(duì)象的索引。我們通過(guò)提供一個(gè)回調(diào)函數(shù)來(lái)實(shí)現(xiàn)這一點(diǎn),該函數(shù)檢查每個(gè)對(duì)象的name屬性是否匹配目標(biāo)值。
注意,如果數(shù)組中有多個(gè)相同的元素,indexOf和findIndex都只會(huì)返回第一個(gè)匹配元素的索引。如果你需要找到所有匹配元素的索引,你需要自己實(shí)現(xiàn)一個(gè)循環(huán)來(lái)遍歷數(shù)組并收集索引。
組是Javascript中一種非常重要的數(shù)據(jù)結(jié)構(gòu)!
它使用單獨(dú)的變量名來(lái)存儲(chǔ)一系列的值,代表現(xiàn)實(shí)世界中一個(gè)集體或者組的概念。
譬如定義一個(gè)水果的數(shù)組:
var fruits=new Array( "apple", "orange", "mango" );
或者直接這樣:
var fruits=[ "apple", "orange", "mango" ];
然后,我就可以訪問(wèn)數(shù)組元素了,像這樣:
console.log(fruits[0]) //得到“apple"
console.log(fruits[1]) //得到"orange"。
想得到數(shù)字里面元素的個(gè)數(shù),可以使用數(shù)組的length屬性:
fruits.length
怎么樣來(lái)理解數(shù)組呢?我們可以理解為一個(gè)隊(duì)列(類似于我們?nèi)粘5呐抨?duì)),我找了一個(gè)圖,大概像這樣:
數(shù)組就看作這樣一個(gè)隊(duì)列,根據(jù)它的索引(0、1、2、3等等)來(lái)訪問(wèn)數(shù)組具體位置上面的值,訪問(wèn)length就可以得到隊(duì)列中的人數(shù)。
數(shù)組提供了很多已有的函數(shù)讓你調(diào)用,跟實(shí)際的隊(duì)列也非常的類似。下面的內(nèi)容,你可以跟著在腦子里面想象一個(gè)隊(duì)列!
譬如我想插入一個(gè)元素到隊(duì)首(插隊(duì)這個(gè)不提倡啊),可以用unshift函數(shù):
fruits.unshift("banana")
這樣fruits就變成了:
banana,apple,orange,mango
如果想刪除第一個(gè)元素(把banana吃掉),就使用shift(插隊(duì)的GD):
fruits.shift()
fruits重新變回了:
apple,orange,mango
隊(duì)尾操作也是類似的,他使用的函數(shù)是
fruits.push("purple");//隊(duì)尾添加,來(lái)晚了,但我排隊(duì)了
fruits.pop(); //隊(duì)尾刪除,不排了走了,等不起
下面是我們的一段代碼,請(qǐng)大家實(shí)驗(yàn)一下(代碼1):
//定義一個(gè)函數(shù),打印數(shù)組里面的值
function PrintArray(arr1){
console.log("數(shù)組現(xiàn)在的值----------");
for(var i=0;i<arr1.length;i++) {
console.log(arr1[i]);
}
}
var fruits=[ "apple", "orange", "mango" ];
PrintArray(fruits);
fruits.unshift("banana");console.log("數(shù)組隊(duì)首增加了banana----------");
PrintArray(fruits);
fruits.shift("banana");console.log("數(shù)組隊(duì)首刪除了banana----------");
PrintArray(fruits);
fruits.push("purple");console.log("數(shù)組隊(duì)尾增加了purple----------");
PrintArray(fruits);
fruits.pop();console.log("數(shù)組隊(duì)尾刪除了purple----------");
PrintArray(fruits);
另外,數(shù)組還提供針對(duì)每一個(gè)元素的具體操作方法(用for循環(huán)訪問(wèn)也可以),這些方法都非常方便,都是通過(guò)js的匿名函數(shù)(就是一個(gè)沒(méi)有名字的函數(shù))來(lái)實(shí)現(xiàn)的。
舉幾個(gè)方法的例子,方法的說(shuō)明如下:
forEach
每一個(gè)都調(diào)用
map
每一個(gè)都調(diào)用,并返回一個(gè)新數(shù)組filter
每一個(gè)都調(diào)用,返回符合條件的值到一個(gè)新數(shù)組
下面是一段實(shí)例代碼(代碼2):
//定義一個(gè)函數(shù),打印數(shù)組里面的值
function PrintArray(arr1){
console.log("數(shù)組現(xiàn)在的值----------");
for(var i=0;i<arr1.length;i++) {
console.log(arr1[i]);
}
}
var arr2=[50,4,39,9]
console.log("數(shù)組forEach----------");arr2.forEach(function(i){
console.log(i); //打印每一個(gè)值
})
console.log("數(shù)組map----------");var arr3=arr2.map(function(i){
return i*i*i; //數(shù)的立方
}
)
PrintArray(arr3); //打印新的立方數(shù)組
console.log("數(shù)組filter----------");var arr4=arr2.filter(function(i){
return i>35; //只保留35以上的中年人
}
)
PrintArray(arr4); //打印新數(shù)組
好了,今天數(shù)組的內(nèi)容就到這里!
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。