通过控制台我们可以看到数组有很多方法
下面就对以上方法和属性做一一介绍
一、数组常用方法
1、数组的创建
在JavaScript中,一共有如下创建数组的方法
1. 用数组对象的构造函数Array(),像创建对象一样(实际上就是对象)用new操作符进行实例化数组对象。
var arrayObj =new Array()
此方法创建的数组为空 长度为0
2. 使用构造函数Array()可以直接明确的指定数组的前n位元素。
var arrayObj = new Array([element0[, element1[, ...[, elementN]]]]); //创建一个数组并赋值
用这种方式创建的数组长度为n,数组的下标是从0到n-1
3. 使用构造函数new Array(),直接加一个整数作为参数直接指定了数组的长度,被创建数组的每个元素值都为undefined
var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长度
注意size不能小于零,size也会随着数组的元素的增删而改变
4.数组直接量
要创建一个数组直接量,只需要将一个用逗号分隔的值列表放入方括号[]之间即可。
2、数组元素的访问
var testGetArrValue=arrayObj[1]; //获取数组的元素值
arrayObj[1]= "这是新值"; //给数组元素赋予新的值
3、数组元素的添加
arrayObj. push([item1 [item2 [. . . [itemN ]]]]);// 将一个或多个新元素添加到数组结尾,并返回数组新长度
arrayObj.unshift([item1 [item2 [. . . [itemN ]]]]);// 将一个或多个新元素添加到数组开始,数组中的元素自动后移,返回数组新长度
arrayObj.splice(index,howmany,[item1[, item2[, . . . [,itemN]]]]);//将一个或多个新元素插入到数组的指定位置,插入位置的元素自动后移,返回""。index:整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置.howmany:要删除的项目数量。如果设置为 0,则不会删除项目。
4、数组元素的删除
arrayObj.pop(); //移除最后一个元素并返回该元素值
arrayObj.shift(); //移除最前一个元素并返回该元素值,数组中元素自动前移
arrayObj.splice(deletePos,deleteCount); //删除从指定位置deletePos开始的指定数量deleteCount的元素,数组形式返回所移除的元素
5、数组的截取与合并
arrayObj.slice(start, [end]); //以数组的形式返回数组的一部分,注意不包括 end 对应的元素,如果省略 end 将复制 start 之后的所有元素
arrayObj.concat([item1[, item2[, . . . [,itemN]]]]); //将多个数组(也可以是字符串,或者是数组和字符串的混合)连接为一个数组,返回连接好的新的数组
6、数组的拷贝
arrayObj.slice(0); //返回数组的拷贝数组,注意是一个新的数组,不是指向
arrayObj.concat(); //返回数组的拷贝数组,注意是一个新的数组,不是指向
7、数组元素的排序
rrayObj.reverse(); //反转元素(最前的排到最后、最后的排到最前),返回数组地址
arrayObj.sort(); //对数组元素排序,返回数组地址
注意:arr.sort() 排序只按数组的第一个数字来排序,所以要实现真正的排序要自己写一个方法:
function sortNum(a,b){
return a-b;
}
arr.sort(sortNum);
8、数组元素的字符串化
arrayObj.join(separator); //返回字符串,这个字符串将数组的每一个元素值连接在一起,中间用 separator 隔开。
indexOf() 来搜索一个指定的元素的位置。如果数组中存在则返回该元素在数组中的位置,如果匹配元素不存在则返回-1;
二、数组对象的三个属性
1、length属性Length属性表示数组的长度,即其中元素的个数。因为数组的索引总是由0开始,所以一个数组的上下限分别是:0和length-1。和其他大多数语言不同的是,JavaScript数组的length属性是可变的,这一点需要特别注意。当length属性被设置得更大时,整个数组的状态事实上不会发生变化,仅仅是length属性变大;当length属性被设置得比原来小时,则原先数组中索引大于或等于length的元素的值全部被丢失
由上面的代码我们可以清楚的看到length属性的性质。但length对象不仅可以显式的设置,它也有可能被隐式修改。JavaScript中可以使用一个未声明过的变量,同样,也可以使用一个未定义的数组元素(指索引超过或等于length的元素),这时,length属性的值将被设置为所使用元素索引的值加1
在编写代码时,不建议直接修改Array的大小,访问索引时要确保索引不会越界。
2、prototype属性
返回对象类型原型的引用。prototype 属性是 object 共有的。
objectName.prototype:objectName 参数是object对象的名称。
说明:用 prototype 属性提供对象的类的一组基本功能。 对象的新实例“继承”赋予该对象原型的操作。
对于数组对象,以以下例子说明prototype 属性的用途。
给数组对象添加返回数组中最大元素值的方法。要完成这一点,声明一个函数,将它加入 Array.prototype, 并使用它。
function array_max()
{
var i,
max = this[0];
for (i = 1; i < this.length; i++)
{
if (max < this[i])
max = this[i];
}
return max;
}
Array.prototype.max = array_max;
var x = new Array(1, 2, 3, 4, 5, 6);
var y = x.max();//6
3、constructor属性
表示创建对象的函数。object.constructor //object是对象或函数的名称。
说明:constructor 属性是所有具有 prototype 的对象的成员。它们包括除 Global 和 Math 对象以外的所有 JScript 固有对象。constructor 属性保存了对构造特定对象实例的函数
的引用。
以下代码中的[native code],表示这是JavaScript的底层内部代码实现,无法显示代码细节。
// 字符串:String()
var str = "张三";
alert(str.constructor); // function String() { [native code] }
alert(str.constructor === String); // true
// 数组:Array()
var arr = [1, 2, 3];
alert(arr.constructor); // function Array() { [native code] }
alert(arr.constructor === Array); // true
// 数字:Number()
var num = 5;
alert(num.constructor); // function Number() { [native code] }
alert(num.constructor === Number); // true
// 自定义对象:Person()
function Person(){
this.name = "CodePlayer";
}
var p = new Person();
alert(p.constructor); // function Person(){ this.name = "CodePlayer"; }
alert(p.constructor === Person); // true
// JSON对象:Object()
var o = { "name" : "张三"};
alert(o.constructor); // function Object() { [native code] }
alert(o.constructor === Object); // true
// 自定义函数:Function()
function foo(){
alert("CodePlayer");
}
alert(foo.constructor); // function Function() { [native code] }
alert(foo.constructor === Function); // true
// 函数的原型:bar()
function bar(){
alert("CodePlayer");
}
alert(bar.prototype.constructor); // function bar(){ alert("CodePlayer"); }
alert(bar.prototype.constructor === bar); // true
三、判断是否为数组
js因为设计上的某些缺陷,导致在对于Array的判断,也是颇费周折的。typeof 操作符:对于Function, String, Number ,Undefined 等几种类型的对象来说,他完全可以胜任,但是为Array时,难免会让人失望:
var arr=new Array("1","2","3","4","5");
alert(typeof(arr)); // Object
instanceof 操作符: 运算符会返回一个 Boolean 值,指出对象是否是特定类的一个实例。
var arrayStr=new Array("1","2","3","4","5");
alert(arrayStr instanceof Array); //true
虽然此时能够完好的工作,但,事实上在多个frame中穿梭就会产生大问题了。所以~~~
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray("1","2","3","4","5");//这个写法IE大哥下是不支持的,FF下才有
alert(arr instanceof Array); // false
alert(arr.constructor === Array); // false
ECMA-262中规范定义了Object.prototype.toString的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于”[object Array]”的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。于是利用这点,就有了下面这种方法:
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
call改变toString的this引用为待检测的对象,返回此对象的字符串表示,然后对比此字符串是否是’[object Array]’,以判断其是否是Array的实例。也许你要问了,为什么不直接o.toString()?嗯,虽然Array继承自Object,也会有toString方法,但是这个方法有可能会被改写而达不到我们的要求,而Object.prototype则是老虎的屁股,很少有人敢去碰它的,所以能一定程度保证其“纯洁性”:)。这也是Array.isArray()方法的兼容旧环境(Polyfill)。
如此很好的解决了跨frame对象构建的问题,经过测试,各大浏览器兼容性也很好,可以放心使用。很多框架,比如jQuery、Base2等等,都计划借鉴此方法以实现某些特殊的,比如数组、正则表达式等对象的类型判定!当然也可以写成如下这样:
function isArray2 (v){
return toString.apply(v) === '[object Array]';
}
Array.isArray()方法用来判断某个值是否为数组。如果是,则返回 true,否则返回 false。
/ 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 鲜为人知的事实:其实 Array.prototype 也是一个数组。
Array.isArray(Array.prototype);
// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });
四、数组的迭代
1.filter()
详见:filter()
方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。
语法:arr.filter(callback[, thisArg])
如果为 filter 提供一个 thisArg 参数,则它会被作为 callback 被调用时的 this 值。否则,callback 的 this 值在非严格模式下将是全局对象,严格模式下为 undefined。
filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或 等价于 true 的值 的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。
function isBigEnough(value) {
return value >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
// ES6 way
const isBigEnough = value => value >= 10;
let [...spraed]= [12, 5, 8, 130, 44];
let filtered = spraed.filter(isBigEnough);
// filtered is [12, 130, 44]
2.foreach()
详见:foreach
forEach() 方法对数组的每个元素执行一次提供的函数。
语法:
array.forEach(callback(currentValue, index, array){
//do something
}, this)
array.forEach(callback[, thisArg])
forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。 注意: 没有办法中止 forEach 循环。如果要中止,可使用 Array.every 或 Array.some。见下面的例子。
示例:打印出数组的内容
let a = ['a', 'b', 'c'];
a.forEach(function(element) {
console.log(element);
});
// a
// b
// c
3.every()
详见:every
方法测试数组的所有元素是否都通过了指定函数的测试。
语法:arr.every(callback[, thisArg])
every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个使 callback 返回 falsy(表示可转换为布尔值 false 的值)的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。callback 被调用时传入三个参数:元素值,元素的索引,原数组。 every 不会改变原数组。
实例:检测所有数组元素的大小
//检测数组中的所有元素是否都大于 10
function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
// passed is false
passed = [12, 54, 18, 130, 44].every(isBigEnough);
// passed is true
4.map()
详见:map()
方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。
语法: array.map(callback[, thisArg])
map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)。
let numbers = [1, 5, 10, 15];
let doubles = numbers.map((x) => {
return x * 2;
});
// doubles is now [2, 10, 20, 30]
// numbers is still [1, 5, 10, 15]
let numbers = [1, 4, 9];
let roots = numbers.map(Math.sqrt);
// roots is now [1, 2, 3]
// numbers is still [1, 4, 9]
实例一使用 map 重新格式化数组中的对象
以下代码将一个包含对象的数组用以创建一个包含新重新格式化对象的新数组。
var kvArray = [{key: 1, value: 10},
{key: 2, value: 20},
{key: 3, value: 30}];
var reformattedArray = kvArray.map(function(obj) {
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
// reformattedArray is now [{1: 10}, {2: 20}, {3: 30}],
// kvArray is still:
// [{key: 1, value: 10},
// {key: 2, value: 20},
// {key: 3, value: 30}]
5.some()
详见:some()
方法测试数组中的某些元素是否通过了指定函数的测试。
语法: arr.some(callback[, thisArg])
描述:some 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some 将会立即返回 true。否则,some 返回 false。callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。
const isBiggerThan10 = (element, index, array) => {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10);
// false
[12, 5, 8, 1, 4].some(isBiggerThan10);
// true
6.reduce()
详见:reduce()
接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
语法: array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)
callback
执行数组中每个值的函数,包含四个参数
accumulator上一次调用回调返回的值,或者是提供的初始值(initialValue)
currentValue
数组中正在处理的元素
currentIndex
数据中正在处理的元素索引,如果提供了 initialValue ,从0开始;否则从1开始
array
调用 reduce 的数组
initialValue
可选项,其值用于第一次调用 callback 的第一个参数。如果没有设置初始值,则将数组中的第一个元素作为初始值。空数组调用reduce时没有设置初始值将会报错。
描述:reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
回调函数第一次执行时,previousValue 和 currentValue 可以是一个值,如果 initialValue 在调用 reduce 时被提供,那么第一个 previousValue 等于 initialValue ,并且
currentValue 等于数组中的第一个值;如果initialValue 未被提供,那么previousValue 等于数组中的第一个值,currentValue等于数组中的第二个值。
如果数组为空并且没有提供initialValue, 会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么
此唯一值将被返回并且callback不会被执行。
示例1:将数组所有项相加
var total = [0, 1, 2, 3].reduce(function(a, b) {
return a + b;
});
// total == 6
示例2: 数组扁平化
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(a, b) {
return a.concat(b);
},
[]
);
// flattened is [0, 1, 2, 3, 4, 5]
或者
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
( acc, cur ) => acc.concat(cur),
[]
);
示例3: 统计一个数组中有多少个不重复的单词
不使用reduce时的写法
var arr = ["apple","orange","apple","orange","pear","orange"];
function getWordCnt(){
var obj = {};
for(var i= 0, l = arr.length; i< l; i++){
var item = arr[i];
obj[item] = (obj[item] +1 ) || 1;
}
return obj;
}
console.log(getWordCnt());
使用reduce时的写法
var arr = ["apple","orange","apple","orange","pear","orange"];
function getWordCnt(){
return arr.reduce(function(prev,next){
prev[next] = (prev[next] + 1) || 1;
return prev;
},{});
}
console.log(getWordCnt());
这其中一个需要注意的点在于,initialValue提供与否对prev和next的影响;
/* 二者的区别,在console中运行一下即可知晓*/
var arr = ["apple","orange",'pear','jade'];
function noPassValue(){
return arr.reduce(function(prev,next){
console.log("prev:",prev);
console.log("next:",next);
//console.info('prev type:'+ typeof(prev)); //prev type:string
return prev + " " +next;
});
}
function passValue(){
return arr.reduce(function(prev,next){
console.log("prev:",prev);
console.log("next:",next);
prev[next] = 1;
//console.info('prev type:'+ typeof(prev)); // object
return prev;
},{});
}
console.log("No Additional parameter:",noPassValue());
console.log("----------------");
console.log("With {} as an additional parameter:",passValue());