JavaScript中的數組與僞數組的區別

在JavaScript中,除了5種原始數據類型以外,其餘全部的都是對象,包括函數(Function)。javascript

基本數據類型:String,boolean,Number,Undefined, Nullphp

引用數據類型:Object(Array,Date,RegExp,Function)java

在這個前提下,我們再來討論JavaScript的對象。node

一、建立對象

var obj = {}; //種方式建立對象,被稱之爲對象直接量(Object Literal)
var obj = new Object(); // 建立一個空對象,和{}同樣

更多建立對象的知識,參見《JavaScript權威指南(第6版)》第6章算法

二、建立數組數組

var arr = [];//這是使用數組直接量(Array Literal)建立數組
var arr = new Array();//構造函數Array() 建立數組對象

 更多建立數組的知識,參見《JavaScript權威指南(第6版)》第7章。ide

三、對象與數組的關係

在說區別以前,須要先提到另一個知識,就是JavaScript的原型繼承。全部JavaScript的內置構造函數都是繼承自 Object.prototype。在這個前提下,能夠理解爲使用 new Array() 或 [] 建立出來的數組對象,都會擁有 Object.prototype 的屬性值。函數

對於題主的問題意味着:測試

var obj = {};// 擁有Object.prototype的屬性值
var arr = [];
//使用數組直接量建立的數組,因爲Array.prototype的屬性繼承自 Object.prototype,
//那麼,它將同時擁有Array.prototype和Object.prototype的屬性值

能夠獲得對象和數組的第一個區別:對象沒有數組Array.prototype的屬性值spa

四、什麼是數組

數組具備一個最基本特徵:索引,這是對象所沒有的,下面來看一段代碼:

var obj = {};
var arr = [];

obj[2] = 'a';
arr[2] = 'a';

console.log(obj[2]); // 輸出 a
console.log(arr[2]); // 輸出 a
console.log(obj.length); // 輸出 undefined
console.log(arr.length); // 輸出 3

經過上面這個測試,能夠看到,雖然 obj[2]與arr[2] 都輸出'a',可是,在輸出length上有明顯的差別,這是爲何呢?

obj[2]與arr[2]的區別

  • obj[2]輸出'a',是由於對象就是普通的鍵值對存取數據

  • 而arr[2]輸出'a' 則不一樣,數組是經過索引來存取數據,arr[2]之因此輸出'a',是由於數組arr索引2的位置已經存儲了數據

obj.length與arr.length的區別

  • obj.length並不具備數組的特性,而且obj沒有保存屬性length,那麼天然就會輸出undefined

  • 而對於數組來講,length是數組的一個內置屬性,數組會根據索引長度來更改length的值。

爲何arr.length輸出3,而不是1呢?

  • 這是因爲數組的特殊實現機制,對於普通的數組,若是它的索引是從0開始連續的,那麼length的值就會等於數組中元素個數

  • 而對於上面例子中arr,在給數組添加元素時,並無按照連續的索引添加,因此致使數組的索引不連續,那麼就致使索引長度大於元素個數,那麼咱們稱之爲稀疏數組。

有關稀疏數組的特性就再也不討論更多,參見《JavaScript權威指南(第6版)》7.3節。

五、僞數組

定義:

一、擁有length屬性,其它屬性(索引)爲非負整數(對象中的索引會被當作字符串來處理,這裏你能夠當作是個非負整數串來理解)
二、不具備數組所具備的方法

僞數組,就是像數組同樣有 length 屬性,也有 0123 等屬性的對象,看起來就像數組同樣,但不是數組,好比

var fakeArray = {
    length: 3,
    "0": "first",
    "1": "second",
    "2": "third"
};

for (var i = 0; i < fakeArray.length; i++) {
    console.log(fakeArray[i]);
}

Array.prototype.join.call(fakeArray,'+');

常見的參數的參數 arguments,DOM 對象列表(好比經過 document.getElementsByTags 獲得的列表),jQuery 對象(好比 $("div"))。

僞數組是一個 Object,而真實的數組是一個 Array

fakeArray instanceof Array === false;
Object.prototype.toString.call(fakeArray) === "[object Object]";

var arr = [1,2,3,4,6];
arr instanceof Array === true;
Object.prototype.toString.call(arr) === "[object Array]"

《javascript權威指南》上給出了代碼用來判斷一個對象是否屬於「類數組」。以下:

// Determine if o is an array-like object.
// Strings and functions have numeric length properties, but are 
// excluded by the typeof test. In client-side JavaScript, DOM text
// nodes have a numeric length property, and may need to be excluded 
// with an additional o.nodeType != 3 test.
function isArrayLike(o) {    
	if (o &&                                // o is not null, undefined, etc.
	        typeof o === 'object' &&            // o is an object
	        isFinite(o.length) &&               // o.length is a finite number
	        o.length >= 0 &&                    // o.length is non-negative
	        o.length===Math.floor(o.length) &&  // o.length is an integer
	        o.length < 4294967296)              // o.length < 2^32
	        return true;                        // Then o is array-like
	else
	        return false;                       // Otherwise it is not
}

 不過有個更簡單的辦法來判斷,用 Array.isArray

Array.isArray(fakeArray) === false;
Array.isArray(arr) === true;

 從外觀上看僞數組,看不出來它與數組的區別,在JavaScript內置對象中常見的僞數組就是大名鼎鼎的auguments:

(function() {
  console.log(typeof arguments); // 輸出 object,它並非一個數組
}());

 另外在DOM對象中,childNodes也是僞數組

console.log(typeof document.body.childNodes); // 輸出 object

除此以外,還有不少經常使用的僞數組,就不一一列舉。

僞數組存在的意義,是可讓普通的對象也能正常使用數組的不少算法,好比:

var arr = Array.prototype.slice.call(arguments)

或者
var arr = Array.prototype.slice.call(arguments, 0); // 將arguments對象轉換成一個真正的數組

Array.prototype.forEach.call(arguments, function(v) {
  // 循環arguments對象
});

 除了使用 Array.prototype.slice.call(arguments),你也能夠簡單的使用[].slice.call(arguments) 來代替。另外,你可使用 bind 來簡化該過程。

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

function list() {
  return slice(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

將具備length屬性的對象轉換成數組對象,arguments是每一個函數在運行的時候自動得到的一個近似數組的對象(傳入函數的參數從0開始按數字排列,並且有length)。

好比當你 func('a', 'b', 'c') 的時候,func裏面得到的arguments[0] 是 'a',arguments[1] 是 'b',依次類推。但問題在於這個arguments對象其實並非Array,因此沒有slice方法。Array.prototype.slice.call( )能夠間接對其實現slice的效果,並且返回的結果是真正的Array

對於IE9之前的版本(DOM實現基於COM),咱們可使用makeArray來實現。

// 僞數組轉化成數組
var makeArray = function(obj) {    
	if (!obj || obj.length === 0) {        
		return [];
	}    
	// 非僞類對象,直接返回最好
	if (!obj.length) {        
		return obj;
	}    
	// 針對IE8之前 DOM的COM實現
	try {        
		return [].slice.call(obj);
	} catch (e) {        
		var i = 0,
	    	j = obj.length,
	    	res = [];        
		for (; i < j; i++) {
			res.push(obj[i]);
		}
		return res;
	}

};

 更多關於僞數組的知識,參見《JavaScript權威指南(第6版)》7.11節。

六、總結

  • 對象沒有數組Array.prototype的屬性值,類型是Object,而數組類型是Array;

  • 數組是基於索引的實現,length會自動更新,而對象是鍵值對;

  • 使用對象能夠建立僞數組,僞數組能夠正常使用數組的大部分方法;

相關文章
相關標籤/搜索