走進javascript——重拾數組

Array構造器

若是參數只有一個而且是Number類型,那麼就是指定數組的長度,但不能是NaN,若是是多個會被當作參數列表。javascript

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類型,但又不是一個具體的數字所以報錯)

注意當只傳遞一個參數時,它只是指定該數組的長度,並不會去填充內容java

因爲傳遞一個參數時不會填充數組內容,所以forEach不會循環這些空內容,或者說forEach不是根據數組長度來循環的,如下代碼就不會被輸出任何內容數組

new Array(6).forEach(function(item,index){
  console.log(index)
});

像咱們本身模擬的forEach基本上都是有問題的,由於我看大部分人都是經過for循環數組的長度來模擬的forEachprototype

function forEach(arr,fun){
    for(var i = 0; i < arr.length; i++){
        fun(arr[i]);
    }
}

這就說明在某些狀況下數組的長度是不可靠的,而且咱們沒有辦法去真實的模擬forEach,經過判斷是否是undefined也是不許確的。code

因爲傳遞一個參數時只會增長數組長度而不會填充內容,所以咱們能夠利用這個特色來實現自定義索引發始位置。對象

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

固然咱們也能夠這樣玩blog

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
// "哈哈哈哈哈"

咱們用它來輸出一個好玩的ip

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屬性,跟對象沒什麼兩樣。

相關文章
相關標籤/搜索