Array構造器 如果參數只有一個並且是Number類型,那麼就是指定數組的長度,但不能是NaN,如果是多個會被當做參數列表。 註意當只傳遞一個參數時,它只是指定該數組的長度,並不會去填充內容 由於傳遞一個參數時不會填充數組內容,因此forEach不會迴圈這些空內容,或者說forEach不是根據數組 ...
Array構造器
如果參數只有一個並且是Number類型,那麼就是指定數組的長度,但不能是NaN,如果是多個會被當做參數列表。
new Array(12)
// (12) [undefined × 12]
new Array('')
// [""]
new Array({})
// [Object]
new Array([])
// [Array(0)]
new Array(null)
// [null]
new Array(NaN)
// Uncaught RangeError: Invalid array length (無效的數組長度,因為NaN是Number類型,但又不是一個具體的數字因此報錯)
註意當只傳遞一個參數時,它只是指定該數組的長度,並不會去填充內容
由於傳遞一個參數時不會填充數組內容,因此forEach不會迴圈這些空內容,或者說forEach不是根據數組長度來迴圈的,以下代碼就不會被輸出任何內容
new Array(6).forEach(function(item,index){
console.log(index)
});
像我們自己模擬的forEach基本上都是有問題的,因為我看大部分人都是通過for迴圈數組的長度來模擬的forEach
function forEach(arr,fun){
for(var i = 0; i < arr.length; i++){
fun(arr[i]);
}
}
這就說明在某些情況下數組的長度是不可靠的,並且我們沒有辦法去真實的模擬forEach,通過判斷是不是undefined也是不准確的。
由於傳遞一個參數時只會增加數組長度而不會填充內容,因此我們可以利用這個特點來實現自定義索引起始位置。
new Array(10).concat([1,2,3,4,5]).forEach(function(item,index){
console.log(`item: ${item} index: ${index}`);
});
// item: 1 index: 10
// item: 2 index: 11
// item: 3 index: 12
// item: 4 index: 13
// item: 5 index: 14
當然我們也可以這樣玩
new Array(10).concat([1,2,3,4,5]).concat(new Array(5)).concat([6,7,8,9,10])
這種方式有個好處就是,空內容不會被迴圈到。
它還可以用來實現相同的連續字元
new Array(5+1).join("哈") //由於數組索引是從0開始的所以需要加+1才是5
// "哈哈哈哈哈"
我們用它來輸出一個好玩的
new Array(3).concat(['l','o','v','e']).concat(new Array(3)).join('--')
// "------l--o--v--e------"
如果你希望設置預設填充內容可以使用數組的fill方法
new Array(5).fill(999)
[999, 999, 999, 999, 999]
我們也可以使用下麵這種方式來實現預設填充內容
var arr = new Array(5).join('5,').split(',');
arr.splice(-1,1);
// ["5", "5", "5", "5"]
以上這種方式的缺點就是都會變成字元串。
通過Array()方法來創建數組和用new方法來創建效果一樣。
數組的訪問
數組通過下標訪問
[2,3,4,5][1]
// 3
當我們通過以下方式進行訪問時,會被解析成連續運算返回最後一個值
[2,3,4,5][1,2]
// 4
由於以上[1,2]是去訪問數組的下標因而被解析成了1,2結果返回的是2,所以以上輸出4
數組也是一種特殊的對象,因此我們也可以通過鍵值對的形式去訪問
var arr = [];
arr.say = 'Hello';
arr.say
// "Hello"
數組與其他值的運算
數組和任何值相加都會將數組轉換成字元串再進行拼接
[1,2,3] + 6
// "1,2,36"
[1,2,3] + {}
// "1,2,3[object Object]"
[1,2,3] + [1,2,3]
// "1,2,31,2,3"
如果數組只有一個值,那麼當這個數組和其他值相減相乘等時會被轉換為數字,如果為空會被轉換為0
[5] - 2
// 3
如果是多個值,肯定是NaN
遍曆數組
使用for
var arr = [2,3,4,5];
for(let i = 0, len = arr.length; i < len; i++){
console.log(arr[i])
}
// 2
// 3
// 4
// 5
使用forEach
var arr = [2,3,4,5];
arr.forEach((item)=>console.log(item))
// 2
// 3
// 4
// 5
使用map、filter、some等方法都可以達到遍曆數組的目的,不過這些方法都不能直接通過return來跳出迴圈,但我們可以通過以下方式來實現跳出迴圈
var arr = [2,3];
try{
arr.forEach(function(item){
if(item === 3){
throw Error();
}
console.log(item);
});
}catch(e){
}
// 2
使用for in
var arr = [2,3];
for(let k in arr){
console.log(arr[k]);
}
// 2
// 3
不過由於for in會將繼承的屬性和方法也遍歷出來,如下所示
Array.prototype.a = 123;
Array.prototype.foo = function(){};
var arr = [2,3];
for(let k in arr){
console.log(arr[k]);
}
// 2
// 3
// 123
// function (){}
所以我們還得過濾一下
Array.prototype.a = 123;
Array.prototype.foo = function(){};
var arr = [2,3];
for(let k in arr){
if(arr.hasOwnProperty(k)){
console.log(arr[k]);
}
}
// 2
// 3
我們還可以使用for of來實現同樣的效果,並且沒有以上問題
var arr = [2,3];
for(let item of arr){
console.log(item)
}
// 2
// 3
有時我們並不希望一次性遍歷所有的數組項,而是根據需求來執行,此時我們就需要用到迭代器了,數組中有一個keys方法可以生成一個迭代器,如下
var arr = [2,3];
var iterator = arr.keys();
console.log(iterator.next().value);
console.log('-----');
console.log(iterator.next().value);
// 0
// -----
// 1
返回的是索引 Array.prototype.keys
其他
實際上JavaScript中的數組並非是傳統意義上的數組,而是一個關聯數組,索引數組只是個錶面現象,我們通過下標的方式去訪問數組,它最終還是會被轉換為字元串的。
[2,3][1]
// 3
其實它是這樣
[2,3]["1"]
// 3
如果說javascript中的數組不是索引數組而是關聯數組,那麼我們在使用for迴圈時為什麼可以按照順序來輸出呢?
var arr = [2,3];
for(var i = 0, len = arr.length; i < len; i++){
console.log(arr[i]);
}
// 2
// 3
如果我們仔細觀察以上代碼,會發現一個啃爹的現象,我們被欺騙了很久,我們是用0 1 2這樣的形式去訪問的數組,自然是按照順序輸出了,再看看下麵這段代碼,估計你就懂了
var arr = [2,3];
console.log(arr[0]);
console.log(arr[1]);
// 2
// 3
你可是手動去訪問人家某個具體屬性的,你說能不是按照順序輸出嗎。
這也就是為什麼數組可以使用for in方法來迴圈的原因,因為本質上來講數組具有對象的某些特性,也就說其實我們也可以自己用對象來模擬實現數組,不過我們需要手動去維護length屬性,從另外一個角度上來講JavaScript中的數組很大一部分只是維護了length屬性,跟對象沒什麼兩樣。