在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會自動更新,而對象是鍵值對;
-
使用對象可以創建偽數組,偽數組可以正常使用數組的大部分方法;
