02 September 2013

JS,数组,伪数组与对象

我们都知道,数组与对象非常的相似,但它们还是有区别的。

虽然在JS中任何变量都是对象,(除了null和undefined),但是Array对象有它自己的特性:

  1. 它从 Array.prototype 中继承了一些它的专属方法,如 push() , pop() , sort() , slice() , splice() 等,这些方法在Object对象中是没有的。
  2. 它有属性length,等

好了,下面我们来看看一些伪数组(Array-like Object),比较典型的就是 function.arguments 与HTML中的 NodeList

我们通过查看arguments与nodeList对象,可以看到它里面有length属性,但是它并不是数组!

如:

var node_list = document.getElementsByTagName(‘div’);
node_list.length = xx;
typeof node_list ; //   “object"
node_list.join(‘,’);     //Object xxx has no method “join”   它不是一个数组!

好吧,虽然这让人很不爽,但是我们有新的办法!

我们知道 Array.prototype 中有个 slice(start,end) 方法,它返回数组中从start开始,end结束(不包括)的元素组成的数组。

我们可以这样调用它,

var node_array = Array.prototype.slice.call(node_list);

好了!现在node_array就是一个真正的数组了!

node_array.join(‘,’); // "[object HTMLDivElement],[object HTMLDivElement],[object HTMLDivElement]…”;

问题:

在神奇的IE中, NodeList 并不是一个JS对象。所以我们并不能使用 Array.prototype.slice.call() 来调用它。

这个时候我们只能用土办法,for循环遍历它并push进新数组。

我们可以这样写:

function make_real_array(obj) {
    var arr = [];
    try {
        arr = Array.prototype.slice.call(obj);
        return arr;
    }
    catch (e) {
        var length = obj.length;
        if (!length) return false;
        for (var i = 0; i < length; i++) {
            arr.push(obj[i]);
        }

        return arr;
    }
} 

另外从参考文章中看到的高级方法:将要转换的数组用一个对象包装

var ArrayContainer = function (arr) { //数组包装对象
    this.arr = arr || [];
    this.length = this.arr.length;
};

ArrayContainer.prototype.add = function (item) { //添加add方法
    index = this.arr.length;
    this.arr[index] = item;
    this.length = this.arr.length;
    return index;
};

ArrayContainer.prototype.get = function (index) { //添加get方法
    return this.arr[index];
};

ArrayContainer.prototype.forEach = function (fn) { //遍历,传入一个function,function可以接收3个参数,i,arr[i],arr
    if (this.arr.forEach) this.arr.forEach(fn); // use native code if it's there
    else {
        for (i in this.arr) {
            fn(i, this.arr[i], this.arr);
        }
    }
};

调用:

var nodelist = document.getElementsByTagName('div');
var array = new ArrayContainer(nodelist);
array.forEach(function (i, v) {
    console.log(‘index’ + i + 'value' + v)
});

虽然效率没有第一种方法高,但是更为可靠。我们可以在特殊需要的时候使用下面一种方法。

参考文章地址:http://nfriedly.com/techblog/2009/06/advanced-javascript-objects-arrays-and-array-like-objects/

Posted in 2013-09-02 16:07