数组的基本特点
- 数组元素是任意类型的
- 可能的最大索引是2^32-2,默认起始索引是 0
- Javascript的数组是动态的,无需手动开辟内存
- 数组可能不连续
- 每个数组都与一个length属性,length之比数组中所有元素的索引值都大
1.创建数组
- 四种方式
1. var arr = []; //空数组,不含任何元素
2. var arr = new Array(); //空数组,不含任何元素 效果与1一样
3. var arr = [1,2,3]; //初始化数组的同时,添加新元素
4. var arr = new Array(1,'',3); //效果与3一样,数组用元素可以是任意类型
5. var arr = new Array(10); //指定长度创建一个数组,此时数组长度length=10
- 注意点
数组直接量的末尾可以有可选逗号,因此创建数组的时候末尾的逗号一般可以省略
1. var arr = [1,,3]; //此时数组中有三个元素,中间那个元素是undefined
2. var arr = [,,]; //此时数组中只有两个元素,都是undefined
2.元素读写与删除
- 使用 [ ] 来操作数组元素
- 数组是对象的特殊形式,用方括号访问数组元素就像用其访问对象属性一样
- javascript中对于小于2^32-2的非负整数索引,会自动维护length的值
- 使用负数或者非整数作为数组的索引的时候,会自动转化为字符串做索引,因此不存在数组“越界”的概念
- 字符串做索引的时候能转化为非负整数的时候,会默认转化为非负整数的索引
- 试图查询数组中不存在的索引的时候,会返回undefined
var a = [1,2,3];
var a1 =a[0]; //读数组中的第一个元素,默认索引从0开始
a[0] = 'A'; //给数组中0索引的写入新值 'A'
a[10] = 'B'; //数组中没有索引为10的元素,则直接生产索引为10的元素,此时length=11
a[-1.1] =1.1; //创建“-1.1”的属性,值为1.1
a['1000']=1000; //此时该元素是数组的第1001个元素
a[1.000] = 1; //等价于a[1] = 1
a.push(0); //等价于a[a.length] = 0;
a.push(1,3,5); //在数组末尾连续添加三个元素
a.pop(); //删除数组末尾的元素,length = length-1;
delete a[1]; //删除索引1处的元素,此操作不会改变length值
3.稀疏数组
数组中的索引不是连续的,则称这个数组是稀疏数组,此时数组length值大于数组元素的个数
- 例子
var a = new Array(10);//数组没有元素,length=10
a = [] ;//空数组(也就是没有元素),length=0;
a[1000] = 1; //添加新元素1,此时length =10001
- 注意点
在数组中直接量中省略值时不会创建稀疏数组,省略的元素是存在于数组中的,其值为undefined,和数组中根本不存在元素是有差别的
var a1 = [,];//无元素的空数组,length=1;
var a2 = [undefined];//含元素undefined元素的数组,length = 1;
0 in a1 ; //false ,a1在索引0处没有元素
0 in a2 ; //true ,a2在索引0出有一个undefined元素
var a1 = [,,,]; // length = 3;
var a2 = new Array(3); // length =3;
0 in a1 ; //true ,a1在索引0处有元素undefined
0 in a2 ; //false ,a2在索引0处没有元素
//a与b效果一样
var a = [1,,3];
var b = [1,undefined,3];
4.数组长度
- 数组长度length 在非稀疏数组中,为数组元素赋值的时候,当前索index引大于等于length,那么length = index +1,这是数组自动维护的。
- 将length设置为一个小于当前length值并且是非负整数 L 的时候,数组中大于等于索引L的元素会被删除,删除方式是逐个删除
- 当设置数组长度length大于当前数组的长度值时,不会创建新的元素,只是在数组的末尾创建一个空的区域
var a = [1,2,3,4,5]; // length=5;
a.length = 3; //此时数组为[1,2,3]
a.length = 0; //此时数组为[ ]
a.length = 5; //length =5,数组为[ ]
在ECMAScript 5中可以通过Object.defineProperty()让数组的长度变为只读,但是数组内部还是能维护数组的长度length的
var a =[1,2,3];
Object.defineProperty(a,"length",{writable:false});
a.length = 0; //此时数组的长度将不会被设置成0
5.数组遍历
使用for in 遍历数组的时候需要注意 for in 遍历能枚举集成的属性名,例如添加到Array.Prototype中的方法,因此遍历的时候因该过滤掉这些不必要的属性
var a =[1,2,3,4,5];
for(var i =0,l = a.length;i<l;i++){
//跳过null undefined 和 不存在的元素
if(!a[i])
continue;
//跳过undefined 和 不存在的元素
if(a[i]===undefined)
continue;
//跳过不存在的元素
if(!(i in a))
continue;
}
//用for in 处理稀疏数组
// i 是得到数组中含有元素的索引
for(var i in a){
//获取索引i的值
var value = a[i];
//过滤继承过来的属性名
if(!a.hasOwnProperty(i)) continue;
//跳过非负整数的元素
if(String(Math.floor(Math.abs(Number(i))))!==i) continue;
}
6.多维数组
在表面上javascript不支持多维数组,但是数组可以存放任意的类型的这个特点可以变向的实现多维数组,实际中也很常用。
基本思想就是数组中在存放另一个数组,可以多层嵌套,但是层数太多,管理和操作都会越来越复杂
- 一个简单的多维数组
var table = new Array(5);
for(var i = 0,l = table.length;i<l)
table[i] = new Array(10);
for(var i = 0,l = table.length;i<l;i++)
{
for(var j = 0,l = table.length;j<l;j++){
table[i][j] = i*j;
}
}
7.数组方法
ECMAScript 3 :
数组方法是定义在Array.prototype中的,对所有数组都可以使用
- join()
将数组中所有元素都转化为字符串并连接在一起,默认分隔符是',',可以指定分隔符
var a = [1,2,3];
a.join(); // "1,2,3"
a,join("");// "123"
- reverse()
数组元素顺序反转,返回反转后的数组,此过程在原数组进行,不创建新数组
var a = [1,2,3];
a.reverse().join(); //结果是"3,2,1"
- sort()
将数组元素进行排序,不带参数将默认按字典序排序。设比较的两数为(未排序时,a在b前面) a,b 返回值 >0 则使a排在b之后,返回值 < 0 则使a排在b之前,返回值 ==0 则使a,b顺序无关紧要
var a = [3,1,5,6,2];
a.sort().join();
a.sort(function(a,b){
//自定义的排序规则(此处是递减排序)
if(a>b)
return -1;
if(a<b)
return 1;
return 0;
}).join();
- concat()
创建并返回一个数组,他的元素是原数组和concat()中的每个参数,参数是数组的时候,连接的是数组的元素,而非数组本身。当参数是多层嵌套的数组的时候不会递归的把多层嵌套的数组元素取出来拼接到原数组。
var a = [1,2,3];
a.concat(4,[5,6,[7,8]]);// 新数组[1,2,3,4,5,6,[7,8]]
- slice()
返回指定数组的一个片段(子数组),一个参数的时候截取的是 参数i - length,连个参数(a,b)的时候是截取 a包括a到b之间的元素,当参数为负整数时是从末尾元素开始数的第|x|个
var a = [1,2,3,4,5];
a.slice(3); //[4,5]
a.slice(1,2); //[2]
a.slice(-4,-2); //[2,3]
- splice()
在数组中删除或者插入数据,一个参数是删除指定索引到结尾的全部元素,两个参数的时候是删除指定区间元素,大于两个参数的时候是删除指定元素后插入指定位置。第一个参数是要删除元素的索引,第二个参数是由起始索引到结束索引的长度,第二个之后的参数是插入到起始删除索引位置的元素。
var a = [1,2,3,4];
a.splice(2,1); //[1,2,4]
a.splice(1); //[1]
a.splice(1,0,2,3,4,[5,6]); // [1,2,3,4,[5,6]]
- push() 和 pop()
和栈结构中的圧栈出栈概念一样。push()带多个参数的时候是按顺序压入
var s = [];
s.push(1,2);
s.push([3,4]);
s.pop();
- shift() 和 unshift()
shift():从数组首部删除一个元素并返回该元素
unshift():在数组首部添加一个或者多个元素,添加的顺序从参数尾部向前添加
var s = [1,2];
a.unshift(3,4,[6,7]); // s = [3,4,[6,7],1,2]
a.shift(); // s = [4,[6,7],1,2]
- toString() toLocalString()
toString():将数组中的每个元素转化成字符串并输出用逗号做分隔符的字符串序列,数组有多层数组嵌套的时候会递归的进行转化字符串
toLocalString()是toString()的本地化方法,将toString()转化的字符串本地化
var s = [1,2,[3,'a']];
s.toString(); // "1,2,3,a"
ECMAScript 5 :
- 关于ECMAScript 5数组方法的一些说明:
大多数方法的第一个参数都传递一个函数,并且对每个元素都调用一次这个函数,稀疏数组中对不存在的元素则不调用。
- forEach()
从头到尾遍历数组,为每个元素调用指定的函数。forEach无法用break中途停止遍历。
var a = [1,2,3];
var sum = 0;
s.forEach(function(v){sum+=v});
//sum = 6;
// v:当前索引的元素,i:当前索引 ,a:调用该方法的数组
a.forEach(function(v,i,a){
a[i] = v + i;
});
// 结果是:a =[2,3,4];
- map()
将调用数组中的每个元素传递给指定的函数。map不改变调用它的数组本身,会返回一个新的数组,如果是稀疏数组,那么返回的数组和调用map的稀疏数组有一样的length 和 缺失元素
var a = [1,2,3];
var b = a.map(function(x){ return x++;});
// b = [2,3,4];
- filter()
返回一个新数组,新数组是调用该函数数组的一个子集,filter中传递的函数返回true 或者 false ,true:新数组添加该元素。filter() 会跳过稀疏数组总缺少的元素,所以返回的新数组总是稠密数组
var a = [1,2,3,4,5];
var b = a.filter(function(x){
if(x>3) return true; //筛选大于3的元素
return false;
});
// b = [4,5];
//压缩稀疏数组
var v = a.filter(function(){ return true;});
//压缩并删除undefined 和 null 元素
var v = a.filter(function(x){ return x!==undefined && x!= null;});
- every() 和 some()
逻辑判断函数,返回值都是true 或者false,every:所有元素调用判定函数返回true 最后结果才是true,遇到判定返回false则停止遍历,结果是false。some :至少有一个元素调用判定函数返回true ,结果返回true,判定返回遇到true,则停止遍历,结果返回true。
var a = [1,2,3,4,5];
a.every(function(x){ return x>0}); //true
a.some(function(x){ return x > 5}); //false
- reduce() 和 reduceRight()
- 两个方法都是使用指定的函数将元素进行组合。区别在于两者的遍历数组顺序刚好相反。reduce是索引从低到高,reduceright是索引从高到低。
- 函数中需要两个参数,参数1:化简操作的函数,参数2(可选):函数初始值(没有初始值的时候,会默认使用遍历的第一个元素的值作为初始值)
3.空数组的时候,不传递初始值会导致类型错误异常
var a = [1,2,3];
//简单的数组求和,初始值为0
//第一次调用时是 return 的是 0(初始值)+a;然后才是a+b
var res = a.reduce(function(a,b){ return a+b;},0); //res = 6
//简单的数组求积,初始值为1
//第一次调用时是 return 的是 1(初始值)* a;然后才是a*b
var res = a.reduce(function(a,b){ return a+b;},1); //res = 6
//对象求并集
var a = [{x:1,a:1},{y:2,a:2},{z:3,a:3}];
//不带初始值的时候默认使用第一个遍历到的元素值
a.reduce(function(union)); //结果是:{x:1,y:2,z:3,a:1}
a.reduceRight(function(union)); //结果是:{x:1,y:2,z:3,a:3}
- indexOf() 和 lastIndexOf()
- 搜索整个数组中具有给定值的元素,返回第一个找到的元素的索引,没找到则返回-1
- indexOf :从头到尾搜索,lastIndexOf:从尾到头搜索
- 第一个参数:给定搜索的值,参数二(可选):指定开始搜索的索引
var a = [1,3,5,7];
var i = a.indexOf(7,2); // i = 3
//参数2可以为负数,表示相对末尾的偏移量
var i = a.lastIndexOf(3,-2);// i = 1
8.数组类型
- ECMAScript 5中使用Array.isArray()判定是否是数组
Array.isArray([]); // true
- ECMAScript 3中使用isArray()的方法是判断一个对象的属性是否是“Array”
var isArray = Function.isArray() || function(o){
return typeof o === "object" && Object.protitype.toString.call(o)
=== "[Object Array]";
}
- instanceof 在浏览器中开启多窗口多窗口时,只能正对该窗口做检测,不能全局(整个浏览器)检测,因为每个窗口都有自己的全局环境
9.数组相关
9.1 作为数组的字符串
常见的是用[] 代替字符串的chatAt()方法
var s = "String";
s.chatAt(1) == s[1]; //
因为字符串是不可变值的所以不能用 s[0] = 3 的方式复制,也不能使用数组中的push(),pop(),sort(),reverse(),splice()等方法
Array.prototype.join.call(s,","); //结果是:"S,t,r,i,n,g"
Array.prototype.filter.call(s,function(x){ return x >'a';}).join("");
//结果是:"tring"
9.2 类数组对象
-
类数组对象与数组有明显的区别。体现在数组用类数组对象没有的特点:
- 数组中有新元素添加,会自动更新length属性
- 通过设置length的值为一个较小的非负整数截断数组
- 数组从Array.protitype中继承了有用的方法
- 数组的类属性是"Array"
- 通过[ ]将对象伪装成对象
var o ={};
var i = 0;
while(i<10){
o[i] = i;
i++;
}
a.lenght = i;
ECMAScript 5 中 数组方法都是通用的,所以能在类数组对象上使用,ECMAScript 3中除了toString() ,toLocalString()外的方法也是通用。
但是类数组对象没有继承Array.prototype,所以不能直接在类数组对象上调用数组方法,可以使用Function.call()方法调用
var a={"0":"a","1":"b","2":"c",length:3};//类数组对象
Array.prototype.join.call(a,"_"); // 结果是:"a_b_c"
Array.prototype.map.call(a,function(x){
return x.toUpperCase();
}); // 结果是:"["A","B","C"]"