数组的本质

数组,是按次序排列的一组值。在本质上,它是一个特殊的对象?!

typeof [1, 2, 3]   // "object"

[ 键名及其访问形式 ]数组的特殊性体现在:它的键名,是按次序排列的一组整数(0,1,2…)。

// 由于数组成员的键名是固定的,因此数组不用为每个元素指定键名,而对象的每个成员都必须指定键名

var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr));// ["0", "1", "2"]
 
var obj = {
    name1: 'a',
    name2: 'b',
    name3: 'c'
};
  • 数组是对象的特殊形式,使用方括号访问数组元素,就像用方括号访问对象的属性一样。

JS 规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串,然后将其作为属性名来使用。

o={};       //创建一个普通的对象
o[1]="one"; //用一个整数来索引它
 
//数值键名被自动转成字符串
var arr = ['a', 'b', 'c'];
arr['0'] // 'a'
arr[0] // 'a'

单独的数值不能作为标识符(identifier)。所以,数组成员只能用方括号法表示

var arr = [1, 2, 3];
arr[0];//1
arr.0;//SyntaxError

  • 要区分数组索引和对象的属性名:所有的索引都是属性名,但只有在0~232-2(4294967294)之间的整数属性名才是索引

可以使用负数或非整数来索引数组。但由于其不在0~2的32次方-2的范围内,所以其只是数组的属性名,而不是数组的索引,明显的特征是不改变数组的长度。

var a = [1,2,3];
 
//属性名
a[-1.23]=true;
console.log(a.length);//3
 
//索引
a[10] = 5;
console.log(a.length);//11
 
//属性名
a['abc']='testing';
console.log(a.length);//11

[ 稀疏数组 ]即,包含从0开始的不连续索引的数组。

  • 制造稀疏数组最直接的方法就是使用delete操作符
var a = [1,2,3,4,5];
delete a[1];
console.log(a[1]);//undefined
console.log(1 in a);//false
  • 数组的逗号之间可以省略元素值,通过省略元素值也可以制造稀疏数组
var a =[1,,3,4,5];
console.log(a[1]);//undefined
console.log(1 in a);//false

省略的元素值和值为undefined的元素值是有区别的

var a =[1,,3,4,5];
console.log(a[1]);//undefined
console.log(1 in a);//false
 
var a =[1,undefined,3,4,5];
console.log(a[1]);//undefined
console.log(1 in a);//true

[ 浏览器差别 ] 如果在数组的末尾使用逗号时,标准浏览器会忽略该逗号,而IE8-浏览器则会在末尾添加undefined值。

// 标准浏览器输出[1,2],而IE8-浏览器输出[1,2,undefined]
   var a = [1,2,];
   console.log(a);
 
// 标准浏览器输出2,而IE8-浏览器输出3
   var a = [,,];
   console.log(a.length);

类数组对象 Array-Like Object — 待

拥有length属性和对应非负整数属性的对象叫做类数组(array-like object)

//类数组演示
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];
}

有三个常见的类数组对象:

1. arguments对象

// arguments对象
function args() { return arguments }
var arrayLike = args('a', 'b');
arrayLike[0] // 'a'
arrayLike.length // 2
arrayLike instanceof Array // false

2. DOM方法(如document.getElementsByTagName()方法)返回的对象

// DOM元素
var elts = document.getElementsByTagName('h3');
elts.length // 3
elts instanceof Array // false

3. 字符串

// 字符串
'abc'[1] // 'b'
'abc'.length // 3
'abc' instanceof Array // false

[注意] 字符串是不可变值,故当把它们作为数组看待时,它们是只读的。如push()、sort()、reverse()、splice()等数组方法会修改数组,它们在字符串上是无效的,且会报错

var str = 'abc';
Array.prototype.forEach.call(str, function(chr) {
  console.log(chr);//a b c
});

Array.prototype.splice.call(str,1);
console.log(str);//TypeError: Cannot delete property '2' of [object String]

数组的slice方法将类数组对象变成真正的数组

var arr = Array.prototype.slice.call(arrayLike);

JavaScript数组方法是特意定义为通用的,因此它们不仅应用在真正的数组而且在类数组对象上都能正确工作。在ECMAScript5中,所有的数组方法都是通用的。在ECMAScript3中,除了toString()和toLocaleString()以外的所有方法也是通用的

var a = {'0':'a','1':'b','2':'c',length:3};
Array.prototype.join.call(a,'+');//'a+b+c'
Array.prototype.slice.call(a,0);//['a','b','c']
Array.prototype.map.call(a,function(x){return x.toUpperCase();});//['A','B','C']