程序员

JavaScript数组

2016-05-15  本文已影响255人  kissLife

数组是值的有序集合。每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引

JavaScript数组的索引是基于0的32位数值:第一个元素的索引是0,最大可能为4294967294(2^32 - 2)。

通常,数组的实现是经过优化的,用数字索引来访问数组元素一般比访问常规的对象属性要快很多。

实际上,数组是对象的特殊形式,索引可理解为对象的属性,使用[]访问数组时,索引首先转换为字符串,然后作为属性使用。

JavaScript数组有以下特点:

创建数组

使用直接量创建

var empty = [];                 // 空数组
var misc  = [1.1, true, "a"];   // 包含3个不同类型的数组
var count = [1,,3];             // 包含2个元素的数组,中间的值为undefined

使用new创建

var a = new Array(10);          // 定义长度为10的数组,注:元素为空
var b = new Array(5, 4, 3, "a");// 定义包含4个元素的数组,长度也为4

数组元素的读写

所有的数组都是对象,可以为其创建任意名字的属性。但如果使用的属性是数组的索引,数组就会更新length属性值。

var a = [1];        // 数组的length为 1
a[-1.23] = true;    // 数组的length为 1,只是数组多了个属性"-1.23"
a["1000"] = 0;      // 数组的length为 1001
a[0.00];            // =>1,相当于a[0]

由于数组也是对象,所以JavaScript数组没有"越界"的情况。当试图查询不存在的属性时,不会报错,只会得到undefined值。

稀疏数组

稀疏数组就是包含不连续索引的数组,此时数组的length属性值大于元素的个数(undefined不计入元素个数)。

var a = [1,,3];         // 第2个元素为undefined
0 in a;                 // true
1 in a;                 // false,元素不存在
2 in a;                 // true
a.length;               // 3,实际元素为2个

var b = new Array(3);
0 in b;                 // false
1 in b;                 // false
2 in b;                 // false
b.length;               // 3,实际元素为0个

var c = [undefined];    // 显式定义,元素存在
0 in c;                 // true
c.length;               // 1,实际元素为1个

数组长度

JavaScript的数组长度length是可写的。

var a = [1,2,3,4,5];
a.length = 3;           // 现在a为[1,2,3]
a.length = 0;           // 现在a为[]
a.length = 5;           // 长度为5,但是没有元素,相当于new Array(5)

var b = [1,2,3,4,5];
b.length = 7;           // 增大数组长度
alert(6 in b);          // false, 并没有添加元素
alert(b.length);        // 7,但是只有5个元素

数组元素的添加和删除

元素的添加有3种方法:
直接量、push()、unshift(),这3个方法添加元素后都会影响数组的length属性值。

元素的删除有3种方法:
delete、pop()、shift(),这3个方法中只有delete不会影响数组的length属性值,pop()、shift()都会影响length属性值。

var a = [1, 2];
a[2] = 3;       // a.length = 3
a.push(4);      // a.length = 4
a.pop();        // a.length = 3
delete a[1];    // a.length = 3,注意:delete不改变length属性,但是a[1]元素变成了undefined

数组遍历

for(var i=0; i < a.length; i++) {
    // 跳过元素值为undefined的元素和不存在的元素
    if (a[i] == undefined) continue;
}

for(var i=0; i < a.length; i++) {
    // 跳过不存在的元素
    if (!(i in a)) continue;    
}

由于数组也是对象,所以可以使用for/in对数组进行遍历,但是遍历出的属性会包含继承的属性,所以一般不使用for/in对数组进行遍历。如果使用,则需要添加过滤条件:

for(var i in a) {
    // 跳过继承属性
    if (!a.hasOwnProperty(i)) continue;
}

或者

for(var i in a) {
    // 跳过不是非负整数的i
    if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
}

多维数组

JavaScript不支持真正的多维数组,但可以用数组的数组来近似。访问数组的数组中的元素,只要简单地使用两次[]操作符即可。

var table = new Array(10);
for(var i=0; i < table.length; i++)
    table[i] = new Array(10);

table[5][7] = 35;

数组方法

join()

var a = [1, 2, 3];
a.join();               // => "1,2,3",默认使用","隔开元素
a.join("&");            // => "1&2&3",指定分隔符

var b = new Array(10);  // 空数组
b.join("-");            // => "---------",9个分隔符

reverse()

var a = [1, 2, 3];
a.reverse().join();     // => "3,2,1",此时的a是[3, 2, 1]

sort()

var a = new Array("banana", "cherrry", "apple");
a.sort();
var s = a.join(", ");   // => "apple, banana, cherrry",数组a现在是["apple", "banana", "cherrry"]

concat()

var a = [1,2,3];
a.concat(4, 5);         // 返回[1,2,3,4,5]
a.concat([4,5]);        // 返回[1,2,3,4,5]
a.concat([4,5],[6,7]);  // 返回[1,2,3,4,5,6,7]
a.concat(4, [5, [6,7]]);// 返回[1,2,3,4,5,[6,7]]
a.join();               // "1,2,3",原始值不发生改变

slice()

var a = [1,2,3,4,5];
a.slice(0, 3);          // 返回[1,2,3]
a.slice(3);             // 返回[4,5]

a.slice(-3, -1);        // 返回[3,4],反向索引,从倒数第3个到倒数第1个元素

splice()

var a = [1,2,3,4,5,6,7,8];
a.splice(4);                // 返回[5,6,7,8],a是[1,2,3,4]
a.splice(1,2);              // 返回[2,3],a是[1,4]
a.splice(1,1);              // 返回[4],a是[1]

var b = [1,2,3,4,5];
a.splice(2,0, "a", "b");    // 返回[],a是[1,2, "a","b", 3,4,5]
a.splice(2,2, [1,2], 3);    // 返回["a", "b"],a是[1,2, [1,2],3, 3,4,5]

push()和pop()

var stack = [];
stack.push(1,2);    // stack:[1,2],返回2
stack.push([1,2]);  // stack:[1,2, [1,2]],返回3

stack.pop();        // stack:[1,2],返回[1,2]

unshift()和shift()

var a = [1];
a.unshift(2);           // a:[2, 1],返回2
a.unshift(3, [4,5]);    // a:[3, [4,5], 2,1],返回4。 注意:"3,[4,5]"是一次性插入的,顺序不变

a.shift();              // a:[[4,5], 2, 1],返回3

toString()和toLocaleString()

[1,2,3].toString();         // "1,2,3"
[1, [2, "c"]].toString();   // "1,2,c"

ECMAScript5中的数组方法

ECMAScript5中大部分数组方法的第1个参数接收一个函数,并且对数组的每个元素调用一次该函数。如果是稀疏数组,对不存在的元素不调用传递的函数。

在大多数情况下,传递的函数使用3个参数:数组元素、元素的索引和数组本身。通常,只需要第1个参数值,可以忽略后2个参数。

forEach()

var data = [1,2,3,4,5];
var sum  = 0;
data.forEach(function(value) { sum += value;} );
sum;         // => 15
function foreach(a, f, t) {
    try {
        a.forEach(f, t);
    }
    catch(e) {
        if(e === foreach.break) return; // 提前终止
        else throw e;
    }
}
foreach.break = new Error("StopIteration");

map()

a = [1,2,3];
b = a.map(function(x) {return x*x; });  // b是[1,4,9]

注意:map()返回的是新数组,它不修改原始数组,如果是稀疏数组,返回的也是相同方式的稀疏数月:它具有相同的长度,相同的缺失元素。

filter()

a = [5,4,3,2,1];
smallvalues = a.filter(function(x) { return x < 3; });  // smallvalues是[2, 1]

every()和some()

var a = [1,2,3,4,5];
a.every(function(x) { return x < 10; });    // => true,所有的值<10
a.every(function(x) { return x % 2 === 0}); // => false,不是所有的值都是偶数

a.some(function(x) { return x % 2 === 0; }) // => true,a含有偶数值
a.some(isNaN);                              // => false,a不包含非数值元素

reduce()和reduceRight()

var a   = [1,2,3,4,5];
var sum = a.reduce(function(x,y) { return x+y; }, 0);       // 数组求和
var max = a.reduce(function(x,y) { return (x>y)?x:y; });    // 求最大值

在求和的调用中,第1次传递的参数为0(初始值)和1(数组的第1个元素),返回1;第2次调用使用参数1(返回值)和2(数组的第2个元素),返回3;然后计算3+3=6、6+4=10、10+5=15。

  1. 在空数组上,不带初始值调用reduce将导致类型错误异常。
  1. 如果数组只有一个元素并且没有指定初始值,或者有一个空数组并且指定一个初始值,reduce()只是简单地返回那个值而不会调用函数。

indexOf()和lastIndexOf()

var a = [0,1,2,1,0];
a.indexOf(1);           // =>1: a[1] = 1
a.lastIndexOf(1);       // =>3: a[3] = 1
a.indexOf(3);           // =>-1: a中没有值为3的元素

数组类型判断

在ECMAScript5中,可以使用Array.isArray()来判断一个对象是否是数组。

Array.isArray([]);      // true
Array.isArray({});      // false

在ECMAScript3中isArray()函数的代码可以这样写:

var isArray = Function.isArray || function(o) {
    return typeof o === "object" &&
            Object.prototype.toString.call(o) === "[objet Array]";
};

类数组对象

数组有一些特性是其他对象所有没有的:

这些特性让数组与常规的对象有明显的区别。但是它们不是定义数组的本质特性。

可以把拥有数值length属性和对应非负整数属性的对象看作是一种类型的数组
很多数组算法针对类数组对象工作得很好,就像针对真正的数组一样。
定义一个类数组对象,如下所示:

var a = {};
var i = 0;
while(i < 10) {
    a[i] = i*i;
    i++;
}
a.length = i;

// 现在,可以当真正的数组进行遍历操作
var total = 0;
for(var j=0; j < a.length; j++)
    total += a[j];

Arguments对象就是一个类数组对象;在客户端JavaScript中,一些DOM方法(如document.getElementsByTagName())也返回类数组对象。

作为数组的字符串

s = "JavaScript";
Array.prototype.join.call(s, " ");  // => "J a v a S c r i p t"

注意:不能使用会修改数组原始值的算法(如,reverse(), sort())操作字符串,否则会抛出类型错误异常。

上一篇 下一篇

猜你喜欢

热点阅读