详解Javascript中的Array对象

Posted 攻城狮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解Javascript中的Array对象相关的知识,希望对你有一定的参考价值。

基础介绍

创建数组

和Object对象一样,创建Array也有2种方式:构造函数、字面量法。

构造函数创建

使用构造函数的方式可以通过new关键字来声明,如下所示:

1
2
var arr = new Array();
console.log(arr);//[]

 

 

当然也可以不通过new关键字来声明:

1
2
var arr = Array();
console.log(arr); //[]

 

 

如果知道数组元素的个数,也可以直接传入数字表示元素个数:

1
2
var arr2 = new Array(5);
console.log(arr2.length); //5

 

 

也可以直接传入数组元素:

1
2
var arr3 = new Array(5, "aa", "bb");
console.log(arr3); //[5, "aa", "bb"]

 

 
字面量法创建

通过字面量创建数组非常简单,推荐这种方式去创建数组:

1
2
var arr = [];
console.log(arr);//[]

 

 

如果数组有一些初始值,可以直接写上去:

1
2
var arr2 = [5, "aa", "bb"];
console.log(arr2); //[5, "aa", "bb"]

 

 

数组长度

我们都知道要访问数组元素的个数很简单,直接通过length属性来获取到。

1
2
var arr = [2, 3, 4, 5];
console.log(arr.length); //4

 

 

但是和其他语言不同的是,在JS中,length属性是可以被设置的。
假设我们要清空一个数组,我们可以直接将length设置成0:

1
2
arr.length = 0;
console.log(arr); //[]

 

 

可以看到,arr数组的元素被清空的

如果我们设置成负数会怎么样呢:

1
2
arr.length = -1;//Uncaught RangeError: Invalid array length
console.log(arr);

 

 

很明显,length是不允许被设置成负数的。

通过设置length属性,我们可以删除元素,比如:

1
2
3
4
var arr = [2, 3, 4, 5];
console.log(arr);//[2, 3, 4, 5]
arr.length = 2;
console.log(arr);[2, 3]

 

 

 

将length属性设置成比原来小的数值,后面的元素就会被移除掉。

如果将length设置成比原来大的数值会怎么样呢?

1
2
3
4
arr.length = 5;
console.log(arr);//[2, 3, 4, 5]
console.log(arr[4]);//undefined
console.log(arr.length);//5

 

 

 

可以看到,设置成比较大的数值后,多出来的元素值是undefined

数组检测

简单地介绍了Array之后,我们来说说如果检测一个变量是否是一个Array对象。这个也是一个比较常见的话题。
在ES5中,Array新增了一个检测数组对象的方法:Array.isArray。这个方法可以完美地确认一个对象是不是数组,无论这个对象是在哪个全局执行环境中创建的。

1
2
var arr = [2, 3, 4, 5];
console.log(Array.isArray(arr)); //true

 

 

对于不支持该方法的浏览器中,我们可以采用下面的polyfill:

1
2
3
4
5
if (!Array.isArray) {
Array.isArray = function (Obj) {
return Object.prototype.toString.apply(Obj) === "[object Array]";
}
}

 

 

 

一些常用的数组对象方法

Array对象中包含着很多有用的方法,尤其是在ES5,ES6中新增了许多方法,下面我们来总结一下。

静态方法

Array.from

Array.from是ES6种新增的方法,它可以将类数组对象或可迭代对象转换成数组对象。
常见的类数组对象比如有函数的arguments值,或者NodeList,htmlCollection对象等等。
常见的可迭代对象比如字符串,还有就是ES6新增的Set对象和Map对象。

我们来看看的基本用法,将一个arguments转换成数组对象:

1
2
3
4
var arr = (function () {
return Array.from(arguments);
})(1, 2, 3);
console.log(arr);//[1,2,3]

 

 

 

也可以将一个字符串转换成数组对象:

1
console.log(Array.from("abcdefg")); //["a", "b", "c", "d", "e", "f", "g"]

 

 

Array.from还包含2个可选参数:mapFn,thisArg
mapFn:将from返回的数组再进行处理再返回
thisArg:执行mapFn函数时this指向的值
假设页面上有多个span标签,我们想获取这些span标签里面的文本,这是html代码

1
2
3
4
<span>第一个span</span>
<span>第二个span</span>
<span>第三个span</span>
<span>第四个span</span>

 

 

 

我们要获取span标签里面的文本成组成一个数组,可以这么做:

1
2
3
4
5
var spans = document.getElementsByTagName("span");
var texts = Array.from(spans, function (val, key) {
return val.innerText;
})
console.log(texts);

 

 

 

 

通过from函数将其转换成数组之后,再通过mapFn进行处理,获取每一个元素的innerText。

Array.from是ES6中新增的功能,必然有很多浏览器不支持,可以使用下面的polyfill:

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var isArrayLike = function (collection) {
    var length = collection && collection.length;
    return typeof length == ‘number‘ && length >= 0 && length <= MAX_ARRAY_INDEX;
};
var isFunction = function (fn) {
    return Object.prototype.toString.call(fn) === ‘[object Function]‘;
} 

if (!Array.from) {
    Array.from = function (arrayLike, mapFn, thisArg) {
        if (!isArrayLike(arrayLike)) {
            throw new TypeError("被转换的对象不是一个类数组对象或可迭代对象");
        }
        mapFn = isFunction(mapFn) ? mapFn : function (val, key) {
            return val;
        }
    
        var result = [];
        for (var i = 0, length = arrayLike.length; i < length; i++) {
            result.push(mapFn.call(thisArg, arrayLike[i], i));
        }
        return result;
    }
}
 
 

 

 

Array.isArray

Array.isArray是用来判断一个对象是否是数组,在前面判断数组类型的章节我们已经提到过了,这里就不再赘述啦。

Array.of

Array.of方法是ES6中新增的方法,它可以将传入的多个参数作为一个数组返回。看下面例子:

1
console.log(Array.of(2, 3, 4, 5)); //[2, 3, 4, 5]

 

 

通过传入4个参数,返回一个包含4个元素的数组。
注意Array.of与采用Array构造函数的区别,看下面代码:

 

1
2
console.log(Array(4));//[]
console.log(Array.of(4));//[4]

 

 

 

第一种方式采用Array构造函数的方式,创建了一个4个元素的数组,每个元素的值都是undefined。
第二中方式采用Array.of方法的方式,创建了一个1个元素的数组,元素值是4。

在不支持的浏览器中,可以采用下面的polyfill:

1
2
3
4
5
if (!Array.of) {
Array.of = function () {
return Array.prototype.slice.call(arguments);
};
}

 

 

 

继承自Object的方法

我们知道,所有的引用类型都继承自Object对象,自然而然地包含了Object的一些方法。在Array中,我们主要说说其继承自Object的toString方法和valueOf方法。

toString方法

toString方法会返回对象的字符串表示,对于Array来说,这个方法会将每一个元素值用逗号分隔起来,最终形成一个字符串返回:

1
console.log([1, 2, 3, 4].toString()); //1,2,3,4

 

 
valueOf方法

valueOf方法用来返回对象的原始值,对于Array来说,它将返回数组本身:

1
console.log([1, 2, 3, 4].valueOf());//[1,2,3,4]

 

 

元素判断方法

在ES5中,Array原型中增加了2个判断数组是否满足某一条件的方法,下面分别来说明一下:

every方法

every方法用来判断数组中的所有元素是否都满足条件,如果全部满足则返回true,否则false。
every的用法如下:

1
arr.every(callback[, thisArg])

 

 

其中callback是用来判断每个元素是否满足条件的函数,它包含两个参数:元素值,索引,数组本身。
thisArg参数是可选的,它表示callback中this指向的对象。
看看下面的例子:

1
2
3
4
 var arr = [1, 2, 3]; 
console.log(arr.every(function (val, index) {
return val > 0;
}));//true

 

 

 

在不支持的浏览器中,可以采用下面的polyfill:

1
2
3
4
5
6
7
8
9
10
11
if (Array.prototype.every) {
Array.prototype.every = function (fn, thisArg) {
var arr = this;
for (var i = 0, length = arr.length; i < length; i++) {
if (!fn.call(thisArg, arr[i], i, arr)) {
return false;
}
}
return true;
};
}

 

 
 
 
 
 
some方法

some方法和every方法用法类似,但是它只需要数组中的某一个元素符合条件即返回true。
我们来看下面的例子:

1
2
3
4
var arr = [1, 2, 3];
console.log(arr.some(function (val, index) {
return val > 2;
})); //true

 

 

 

 

在数组中,只有一项元素大于2,则返回true。
在不支持的浏览器中,可以采用下面的polyfill:

 

1
2
3
4
5
6
7
8
9
10
11
if (!Array.prototype.some) {
Array.prototype.some = function (fn, thisArg) {
var arr = this;
for (var i = 0, length = arr.length; i < length; i++) {
if (fn.call(thisArg, arr[i], i)) {
return true;
}
}
return false;
};
}

 

 

 

 

 

 

栈和队列方法

在js中,数组即可以像栈那个操作,也可以像队列那样操作,它提供了几个关于栈和队列的方法,这些方法相信大家非常熟悉,在这里简单地说明一下:

pop方法

pop方法会将数组的最后一个元素删除,然后返回这个被删除的元素

push方法

push方法是一个比较常用的方法,和pop方法相反,它用来将一个元素添加到元素的末尾,然后返回数组的长度。

shift方法

shift方法将第一个元素删除,然后返回这个元素

unshift方法

unshift在数组开头添加一个或多个元素,然后返回这个元素的长度:

1
2
3
var arr = [1, 2, 3];
console.log(arr.unshift(3, 2, 1));//6
console.log(arr); // [3,2,1,1,2,3]

 

 

 

元素索引方法

indexOf方法

indexOf方法用来返回元素在数组中的位置,不存在则返回-1:

1
2
var arr = [1, 2, 3];
console.log(arr.indexOf(2)); //1

 

 

indexOf方法有第二个可选参数,这个参数表示从哪个索引开始查找:

1
console.log(arr.indexOf(2, 1)); //1

 

 

如果这个参数大于数组长度,则直接返回-1,如果是负数,则将末尾进行抵消,然后开始查找,比如-1就从倒数第一开始查找,-2从倒数第二开始查找。
indexOf方法是ES5中提供的方法,对于不支持的浏览器,可以采用下面的polyfill:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (element, fromIndex) {
if (this.length === 0 || this.length < fromIndex) {
return -1;
}
var index = fromIndex || 0;
var length = this.length;
if (fromIndex < 0) {
index = length + fromIndex;
}

for (; index < length; index++) {
if (this[index] === element) {
return index;
}
}
return -1;
}
}

 

 
 
 
 
 
 
 
 


lastIndexOf方法

lastIndexOf方法和indexOf方法类似,它用于查找元素在数组最后一项的索引,如果不存在则返回-1:

1
2
3
var arr = [1, 5, 3, 4, 5, 6, 7];
console.log(arr.indexOf(5));//1
console.log(arr.lastIndexOf(5)); //4

 

 

 

如上面例子所示,数组中存在着两个数字5,使用indexOf方法将返回1,使用lastIndexOf将返回5。
lastIndexOf方法同样拥有第二个可选参数fromIndex,表示从该位置开始逆向查找。
如果fromIndex值大于或等于数组长度,则整个数组都会被查找。
如果fromIndex值为负值,并且其绝对值小于数组长度时,将从数组末尾向前查找。
如果fromIndex只为负数,但是其绝对值大于数组长度时,则直接返回-1。

1
2
3
4
var arr = [1, 5, 3, 4, 5, 6, 7];
console.log(arr.lastIndexOf(5, 10)); //4
console.log(arr.lastIndexOf(5, -4)); //1
console.log(arr.lastIndexOf(5, -10)); //-1

 

 

 

对于不支持的浏览器,可以使用下面的polyfill: 

 

if (!Array.prototype.lastIndexOf) {
    Array.prototype.lastIndexOf = function (element, fromIndex) {
        if (this.length === 0 || (fromIndex < 0 && this.length < Math.abs(fromIndex))) {
            return -1;
        }
            
        var length = this.length;
        var index = fromIndex || length - 1;
        if (fromIndex < 0) {
            index = length + fromIndex;
        }
        
        for (; index > -1; index--) {
            if (this[index] === element) {
                return index;
            }
        }
        return -1;
    }
}

 

元素查找方法

findIndex方法

findIndex方法用来查找数组中符合条件的元素的索引,如果没有则返回-1。它包含两个参数:
callback:用来判断元素是否符合条件的回调函数,包含三个参数,分别是:当前元素,当前元素索引,数组
thisArg:可选参数,表示callback中this对象。
来看看下面的例子:

1
2
3
4
var arr = [1, 2, 3, 4, 5, 6];
console.log(arr.findIndex(function (val, idx) {
return val > 3;
})) //3

 

 

 

查找第一个大于3的元素的索引,结果为3。
如果是一个比较复杂元素的数组,我们可以来查找其中符合某个条件的元素的索引:

1
2
3
4
5
 var arr = [{ a: 1 }, { a: 2 }];
console.log(arr.indexOf({ a: 2 }));//-1
console.log(arr.findIndex(function (val, idx) {
return val.a == 2;//1
}));

 

 

 

 

如果是要查找一个复杂对象,使用indexOf可能查找不到其索引,但是我们可以通过findIndex来找到其索引。这个对于查找复杂元素非常有用。
对于不支持的浏览器,可以使用下面的polyfill:

if (!Array.prototype.findIndex) {
    Array.prototype.findIndex = function (fn, thisArg) {
        if (!isFunction(fn)) {
            throw new TypeError("fn不是一个有效的函数");
        }
        
        var arr = this;
        for (var i = 0, length = arr.length; i < length; i++) {
            if (fn.call(thisArg, arr[i], i, arr)) {
                return i;
            }
        }
        return -1;
    }
}

 


find方法

find方法用户查找满足条件的第一个元素,如果没有满足条件的元素,则返回undefined。
find方法的用法和findIndex类似,它包含两个参数:
callback:用来判断元素是否符合条件的回调函数,包含三个参数,分别是:当前元素,当前元素索引,数组
thisArg:可选参数,表示callback中this对象。
来看看下面的例子:

 

1
2
3
4
var arr = [{ v: 1 }, { v: 3 }, { v: 4 }, { v: 5 }, { v: 6 }];
console.log(arr.find(function (val, idx) {
return val.v > 3;
}))//Object {v: 4}

 

 

 

 

通过find方法,查找到第一个其属性v大于3的元素并返回。
大家在日常的开发中一定会遇到这种查找符合条件的元素的需求,find方法是一个非常有用的方法。
对于不支持的浏览器,可以采用下面的polyfill:

 

if (!Array.prototype.find) {
    Array.prototype.find = function (fn, thisArg) {
        if (!isFunction(fn)) {
            throw new TypeError("fn不是一个有效的函数");
        }
        var arr = this;
        for (var i = 0, length = arr.length; i < length; i++) {
            if (fn.call(thisArg, arr[i], i, arr)) {
                return arr[i];
            }
        }
    }
}

 

元素排序方法

在Array对象中,它还包含了一些排序的方法,主要有sort和reverse两个方法,下面来说明一下这两个方法。

sort方法

sort方法用来对数组进行排序,并返回排序后的数组。它包含一个参数,这个参数是一个函数,用它来比较每个参数之前的前后关系。如果不传,则默认按照字符串的Unicode码位点进行排序。
看看下面的例子:

 

1
2
3
4
5
var arr = [2, 4, 6, 2, 4, 8, 11, 34];
console.log(arr.sort().toString()); //11,2,2,34,4,4,6,8
console.log(arr.sort(function (a, b) {
return a - b;
}).toString()); //2,2,4,4,6,8,11,34

 

 

 

 

 

如上结果所示,不指定比较函数的话,11排到了2前面,所以一般来说,我们要指定这个比较函数。

通过比较函数,我们可以来自定义数组排序的规则:
(1)返回-1,则元素a则排在了b前面
(2)返回0,位置不变
(3)返回1,元素a排在b后面

reverse方法

reverse方法是一个很简单的方法,它将数组元素的顺序进行倒序,并返回这个数组。

 

1
2
3
var arr = [1, 2, 3, 4, 5, 6, 7];
console.log(arr.reverse()); //[7, 6, 5, 4, 3, 2, 1]
console.log(arr); //[7, 6, 5, 4, 3, 2, 1]

 

 

 

元素循环方法

Array对象中包含一些对元素进行遍历的方法,通过对元素进行遍历,从而进行不同的操作。

filter方法

filter方法是用来过滤数组的,通过传入一个回调函数,如果元素通过回调函数的测试,则保留该元素,否则丢弃。具体用法如下:

 

1
2
3
4
var arr = [2, 3, 4, 5, 6, 7, 8];
console.log(arr.filter(function (val, idx, arr) {
return val > 3;
})) //[4, 5, 6, 7, 8]

 

 

 

 

如上所示,通过回调函数,我们过滤掉那些值不大于3的元素。
对于回调函数,它包含3个参数:元素,元素索引,当前数组。
filter函数还包含一个可选的参数thisArg,它表示回调函数中this的指向。
对于不支持的浏览器,可以采用下面的polyfill:

if (!Array.prototype.filter) {
    Array.prototype.filter = function (fn, thisArg) {
        if (!isFunction(fn)) {
            throw new TypeError("fn不是一个有效的函数");
        }
        var arr = this;
        var result = [];
        for (var i = 0, length = arr.length; i < length; i++) {
            if (fn.call(thisArg, arr[i], i, arr)) {
                result.push(arr[i]);
            }
        }
        return result;
    }
}
 
forEach函数

forEach简单地说就是for循环的语法糖,它用于让数组的每一项都执行给定的函数。
看看下面的例子,循环数组的每一项,分别输入每一项。

1
2
3
4
var arr = [2, 3, 4, 5, 6, 7, 8];
arr.forEach(function (val, idx) {
console.log(val);
})

 

 

 

和其他循环方法一样,forEach包含两个参数:

callback:循环每一项调用的函数,包含三个参数:元素,元素索引,当前数组
thisArg:可选的参数,表示callback中this的指向。
有一点要注意的是:除非是抛出异常,否则无法终止或跳出循环。
对于不支持的浏览器,可以采用下面的polyfill:

if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, thisArg) {
        if (!isFunction(fn)) {
            throw new TypeError("fn不是一个有效的函数");
        }
        var arr = this;
        for (var i = 0, length = arr.length; i < length; i++) {
            fn.call(thisArg, arr[i], i, arr);
        }
    }
}

 

reduce函数

reduct函数我们可以将其想象成一个累加器,从左到右依次将每个元素累加起来。
看看下面的例子:

 

1
2
3
4
var arr = [1, 2, 3, 4, 5];
console.log(arr.reduce(function (prev, current, currentIndex, array) {
return prev + current;
}))

 

 

 

 

这个例子中,通过reduce方法将数组的元素累加起来,计算总和。
reduct包含两个参数:
callback:累加调用函数,包含4个参数:
(1)上一次调用的返回值,默认情况下是第一个元素
(2)当前元素
(3)当前元素索引
(4)被循环的数组
initialValue:累加的初始值,不传则是第一个元素
对于不支持的浏览器,可以采用下面的polyfill:

if (Array.prototype.reduce) {
    Array.prototype.reduce = function (fn, initialValue) {
        if (!isFunction(fn)) {
            throw new TypeError("fn不是一个有效的函数");
        }
        var arr = this;
        var result = initialValue || arr[0];
        var index = !!initialValue ? -1 : 0;

        for (var length = arr.length - 1; index < length; index++) {
            result = fn(result, arr[index + 1], index + 1, arr);
        }
        return result;
    }
}

 

reduceRight方法

reduceRight与reduce类似,只是从右向左开始调用回调函数,这里就不再赘述。
对于不支持的浏览器,可以使用下面的polyfill:

if (!Array.prototype.reduceRight) {
    Array.prototype.reduceRight = function (fn, initialValue) {
        if (!isFunction(fn)) {
            throw new TypeError("fn不是一个有效的函数");
        }
        var arr = this;
        var result = initialValue || arr[arr.length - 1];
        var index = !!initialValue ? arr.length : arr.length - 1;
        
        for (; index > 0; index--) {
            result = fn(result, arr[index - 1], index - 1, arr);
        }
        以上是关于详解Javascript中的Array对象的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript原生对象属性和方法详解——Array对象

javascript常用代码片段

JavaScript原生对象属性和方法详解——Array对象 转载

JavaScript中遍历对象属性方法详解

JavaScript中遍历对象属性方法详解

几个有用的JavaScript/jQuery代码片段(转)