在JavaScript中,除了5種原始數據類型之外,其他所有的都是對象,包括函數(Function)。
基本數據類型:String,boolean,Number,Undefined, Null
引用數據類型:Object(Array,Date,RegExp,Function)
在這個前提下,咱們再來討論JavaScript的對象。
1、創建對象
var obj = {}; //種方式創建對象,被稱之為對象直接量(Object Literal) var obj = new Object(); // 創建一個空對象,和{}一樣
更多創建對象的知識,參見《JavaScript權威指南(第6版)》第6章
2、創建數組
var arr = [];//這是使用數組直接量(Array Literal)創建數組 var arr = new Array();//構造函數Array() 創建數組對象
更多創建數組的知識,參見《JavaScript權威指南(第6版)》第7章。
3、對象與數組的關系
在說區別之前,需要先提到另外一個知識,就是JavaScript的原型繼承。所有JavaScript的內置構造函數都是繼承自 Object.prototype。在這個前提下,可以理解為使用 new Array() 或 [] 創建出來的數組對象,都會擁有 Object.prototype 的屬性值。
對於題主的問題意味着:
var obj = {};// 擁有Object.prototype的屬性值 var arr = []; //使用數組直接量創建的數組,由於Array.prototype的屬性繼承自 Object.prototype, //那么,它將同時擁有Array.prototype和Object.prototype的屬性值
可以得到對象和數組的第一個區別:對象沒有數組Array.prototype的屬性值
4、什么是數組
數組具有一個最基本特征:索引,這是對象所沒有的,下面來看一段代碼:
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節。
5、偽數組
定義:
1、擁有length屬性,其它屬性(索引)為非負整數(對象中的索引會被當做字符串來處理,這里你可以當做是個非負整數串來理解)
2、不具有數組所具有的方法
偽數組,就是像數組一樣有 length
屬性,也有 0
、1
、2
、3
等屬性的對象,看起來就像數組一樣,但不是數組,比如
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節。
6、總結
-
對象沒有數組Array.prototype的屬性值,類型是Object,而數組類型是Array;
-
數組是基於索引的實現,length會自動更新,而對象是鍵值對;
-
使用對象可以創建偽數組,偽數組可以正常使用數組的大部分方法;