参考:http://www.cnblogs.com/dolphinX/p/3353590.html
数组是一段线性分配的内存,它是通过整数计算偏移量并访问其中的元素,所以数组是性能出色的数据结构,但JavaScript没有像此类数组一样的数据结构
作为替代,JavaScript提供一种拥有类数组(array-like)特性的对象。
JavaScript本质是Object,多提供了一个length 属性 && 继承Array
var a = {
length:1
}
var arr = Array.prototype.slice.call(a,0);
console.log(Array.isArray(arr));
//返回 true 证明:只要有length 就能转为Array 参见附录,这样并不能证明什么
1数组的创建和length属性
1.1 数组创建(两种创建方式)
1.1.1字面量创建
var a = [];
var b = [2];//字面量创建 不管参数是几个 都无法像“new Array(3)”创建length为3的数组
var c = [1,2,3];
1.1.2 构造函数创建
var a=new Array();
var b= new Array(3);
var c = new Array("a","b");
var d = Array(3); //可以省略 new
var e=Array("a","b");
1.1.3 数组判断
由于JavaScript的内置类型检测并不完全可靠(具体为什么不可靠,参见后续博客
)
所以Array 判断也是 原理 调用Object.protptype.toString()方法
参见:http://www.cnblogs.com/ziyunfei/archive/2012/11/05/2754156.html
function isArray(arr){
//判断是否是数组 Object.prototype.toString是一个[native code]
return Object.prototype.toString.call(arr) ==="[object Array]"
}
var a = [];
isArray(a);//true
1.2 数组length
每个数组都有length属性,但和java不同,javascript数组length没有上界,可以自己手动改变length 大小,导致一系列问题,也是一些列美妙的开始
手动改变length
/*eg1*/
var a = [1,2,3];
console.log(a.length);//3
a.length = 100;
console.log(a.length);//100
/*eg2*
* 虽然直接对a[100]赋值不会影响a[4]或a[99],但数组的长度却受到影响,数组length属性等于数组中最大的index+1,我们知道数组的length属性同样是个可写的属性,当强制把数组的length属性值设置为小于等于最大index值时,数组会自动删除indexd大于等于length的数据,
/
var a = [1,2,3];
console.log(a.length);//3
a[100] = 100;
console.log(a.length);//101
console.log(a[99]);//undefined 如果数组未具体的赋值,则为"undefined"
var b = [1,2,3];
console.log(b);//VM1679:3 [1, 2, 3]
b.length = 2;
console.log(b);//VM1679:5 [1, 2]
/*eg3
* 本质上JavaScript数组是一个object对象 所以可以使用a[‘s‘] = ‘s‘来设置属性
* a[-10] = -10; 个人认为是设计不严谨 因为“-10”属性被当成属性(非array数字属性),但JavaScript Object 不能通过‘-10’来访问
*/
var a = [1,2,3];
console.log(a.length);//3
a[-10] = -10;
a[‘s‘] = ‘s‘;//
console.log(a.length);//3
console.log(a); //[1, 2, 3, -10: -10, s: "s"]
2.数组的增删改查
2.1 添加和删除方法
2.1.1数组头部添加和删除(shift和unshift)
var arry = [1,2,3];
arry.unshift(4);
console.log(arry);
//[4, 1, 2, 3]
console.log(arry.shift());//4,注意:返回的是被删除的元素
console.log(arry);//[ 1, 2, 3]
2.1.2数组尾部添加和删除(push和pop)
var arry = [1,2,3];
console.log(arry.push(4));//4 尾部添加
console.log(arry);//[ 1, 2, 3, 4]
console.log(arry.pop());//4 尾部删除
console.log(arry);//[ 1, 2, 3]
2.1.3 数组中间(任意位置)添加和删除
使用splice 万能的方法 w3c splice 方法的解释
/*添加*/
var arry = [1,2,3];
//添加 注意 第二个参数为“0”
console.log(arry.splice(1,0,4));//[] 这个返回的值是 被删除的数组
console.log(arry);//[1, 4, 2, 3]
/*删除*/
var arry = [1,2,3];
console.log(arry.splice(1,1));
//注意删除参数(第一个参数:删除的第几位,从0开始,第二个表示删除几位)
console.log(arry);
2.2 更新
更新 也是用的是万能的 splice 方法 w3c splice 方法的解释
var arry = [1,2,3];
console.log(arry.splice(1,1,0));
console.log(arry);
2.3 查询
2.3.1 indexOf 和 lastIndexOf 方法
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
参考:indexOf
同样还有lastIndexOf方法
var fruits=["Banana","Orange","Apple","Mango","Banana","Orange","Apple"];
var a = fruits.indexOf("Apple",4);
console.log(a);//6
2.4 for 迭代方法
参考:《JavaScript权威指南》《JavaScript高级程序设计》
遍历有两大问题(当前水平),
1.性能
2.JavaScript 遍历中length特殊,可能是稀疏数组
var arg = [1,2,3];
for(var i=0;i<arg.length;i++){
//i<arg.length,每一次遍历都查询一次,所以需要优化
console.log(arg[i]);
}
/***********优化后********/
for(var i=0,len=arg.length; i<len; i++){
console.log(arg[i]);
}
/*
* 上例,假设数组是稠密的,且所有的元素都是合法的。
* 否则,在使用前应该先检测他们
*/
var arg = [1,2,3];
arg[4} = undefined;
arg.length = 10;//此处 特殊处理一下
for(var i=0,len=arg.length; i<len; i++){
if(!arg[i]){//跳过null,undefined,不存在
//if(arg[i] === undefined){//跳过undefined,不存在
// if(!(i in arg)){//跳过不存在(如果 属性设置为undefined,in 返回true)
continue;
}
console.log(arg[i]);
}
2.4.2 对稀疏数组处理(使用for/in循环)
2.4.2.1 基本方法
/*
* 对稀疏数组处理
* 使用for/in循环
*/
//基本方法
var arg = [0,1];
arg[3] = 3;
arg[5] = 5;
for(var index in arg){
console.log(arg[index]);
}
/**控制台打印
0
VM594:5 1
VM594:5 3
VM594:5 5
*/
与上面代码输出对比:
var arg = [0,1];
arg[3] = 3;
arg[5] = 5;
for(var i=0; i<arg.length; i++){
console.log(arg[i]);
}
/** 控制台打印
0
VM595:5 1
VM595:5 undefined
VM595:5 3
VM595:5 undefined
VM595:5 5
*/
2.4.2.2 优化完善
for/in 循环 能够枚举继承的属性,如添加在Array.prototype的方法/属性,
因此,需要校验属性,过滤继承来的属性
可能出现的特殊情况:
//可能出现的特殊情况
var arg = [0,1];
arg[3] = 3;
arg[5] = 5;
arg.a = ‘a‘;//添加非数字属性
Array.prototype.proto = ‘proto‘;//添加继承 属性
for(var index in arg){
console.log(arg[index]);
}
/**
0
VM604:7 1
VM604:7 3
VM604:7 5
VM604:7 a
VM604:7 proto
*/
解决上面可能出现的特殊情况:
var arg = [0,1];
arg[3] = 3;
arg[5] = 5;
arg.a = ‘a‘;//添加非数字属性
Array.prototype.proto = ‘proto‘;//添加继承 属性
for(var index in arg){
//跳过继承属性
if(!arg.hasOwnProperty(index)){ continue;}
//跳过 非负整数的 index
if(String(Math.abs(Number(index))) !== index){ continue;}//注意 for/in 返回的index 值为string
console.log(arg[index]);
//console.log(typeof(index));
}
/**
* String(Math.abs(Number(index))) !== index 需要细细研究
Number(index) 将 如‘1‘,‘2‘这种数字型 string转化为nmber,如非 数字型 string 则返回为 ‘NaN’
for/in 返回的index 是String类型
*/
for/in 遍历数组顺序无法保证
ECMAAScript容许以不同顺序遍历,但一般具体浏览器的实现是升序,但有特列:
数组元素 拥有1对象属性 2.数组元素 参考下面代码:
var arg = [0,1];
arg[‘b‘] = ‘b‘;
arg[3] = 3;
arg[5] = 5;
arg.a = ‘a‘;//添加非数字属性
arg[4] = 4;//注意顺序
Array.prototype.proto = ‘proto‘;//添加继承 属性
for(var index in arg){
console.log(arg[index]);
}
/** chrome 浏览器 控制台输出
VM431:9 0
VM431:9 1
VM431:9 3
VM431:9 4
VM431:9 5
VM431:9 b
VM431:9 a
VM431:9 proto
*/
2.4.3 ECMAAScript5 中数组的方法
ECMAAScript5 中定义了9个新数组方法(待后期)
3.常用方法
ECMAScript3在Array.prototype定义了一些操作数组的函数
3.1 join()
将所有的元素转换为字符串 并连接在一起,可以指定一个连接符
var arg = [0,1,5,6,10,15];
console.log(arg.join());//0,1,5,6,10,15 默认为“,”
console.log(arg.join(‘-‘));//0-1-5-6-10-15
该方法是String.split方法 的逆向过程
3.2 concat()
创建一个并返回一个新数组
可以理解为 连接多个数组,并返回一个副本(也就是新数组)
var arg = [1,2,3];
//注意 可以是具体的值,也可以是数组
console.log(arg.concat(4,5));//[1, 2, 3, 4, 5]
console.log(arg);//[1, 2, 3]
console.log(arg.concat([4,5]));//[1, 2, 3, 4, 5]
console.log(arg);//[1, 2, 3]
3.3 slice()
方法可从已有的数组中返回选定的元素。
var arr = new Array(6)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
arr[3] = "James"
arr[4] = "Adrew"
arr[5] = "Martin"
console.log(arr.slice(2,4))
console.log(arr)
/** 控制台打印
VM2235:9 ["Thomas", "James"]
VM2235:10 ["George", "John", "Thomas", "James", "Adrew", "Martin"]
*/
3.4 toString 和 toLocaleString()
toString 方法和无参数的join()方法返回的字符串是一致的
4.数组排序方法
数组中有两个默认排序的方法
reverse()和sort();
但是,默认排序规则是,按照比较字母顺序来排序
下面 证明是按照字母顺序排序:
var arg = [0,1,5,10,15];
console.log(arg.sort());
//VM144:2 [0, 1, 10, 15, 5] 控制台打印
解决方案:
sort()方法接受一个function,该function 接受两个参数,
第一个 在第二个之前 return 负数,
如果相等 则返回为0
第一个 在第二个之后 return 正数,
var arg = [0,1,5,6,10,15];
console.log(arg.sort(function(v1,v2){
return v2-v1;
}));
//[15, 10, 6, 5, 1, 0] 控制台打印
5.多维数组
JavaScript不支持正真的多为数组,因为数组本身就是一个对象,且数组的属性也可以为引用类型,所以,可以用数组的数组进行模拟多维数组。
下面实现一个9*9乘法口诀,来感受一下其中美妙
var table = new Array(10);
for(var i=1,len=table.length;i<len;i++){
table[i] = new Array(10);
}
for(var i=1,len=table.length;i<len;i++){
for(var j=1,len2=table[i].length;j<len2;j++){
table[i][j] = i*j;
}
}
console.log(table);
table[6][8]; //48
6.附录
var a = {
a:‘aaa‘
}
debugger;
var arr = Array.prototype.slice.call(a,0);
console.log(Array.isArray(arr));//true 返回也是true,证明object被强转为Array,
//但属性“a”,被干掉,证明 只获得属性为number的