js中的對象理解和使用起來都很簡單,并且很頻繁的使用。但是,總有細節(jié),是我們可能會忽略的、或者是拿捏不定的
參考鏈接:http://javascript.ruanyifeng.com/grammar/object.html
1. 概述#
1.1對象的含義
所謂對象,就是一種無序的數(shù)據(jù)集合,由若干個“鍵值對”(key-value)構(gòu)成。
對象的生成方法,通常有三種方法:
var o1 = {};
var o2 = new Object();
var o3 = Object.create(null);
1.2 對象的引用
如果不同的變量名指向同一個對象,那么它們都是這個對象的引用,也就是說指向同一個內(nèi)存地址。修改其中一個變量,會影響到其他所有變量。
var o1 = {};
var o2 = o1;
o1.a = 1;
o2.a // 1
o2.b = 2;
o1.b // 2
此時,如果取消某一個變量對于原對象的引用,不會影響到另一個變量。
var o1 = {};
var o2 = o1;
o1 = 1;
o2 // {}
但是,這種引用只局限于<code>對象</code>,對于原始類型的數(shù)據(jù)則是<code>傳值引用</code>,也就是說,都是值的拷貝。
var x = 1;
var y = x;
x = 2;
y // 1
1.3 表達式還是語句區(qū)別
對象采用大括號表示,這導(dǎo)致了一個問題:如果行首是一個大括號,它到底是表達式還是語句?
{ foo: 123 }
JavaScript引擎讀到上面這行代碼,會發(fā)現(xiàn)可能有兩種含義。第一種可能是,這是一個表達式,表示一個包含foo屬性的對象;第二種可能是,這是一個語句,表示一個代碼區(qū)塊,里面有一個標(biāo)簽foo,指向表達式123。
為了避免這種歧義,JavaScript規(guī)定,如果行首是<b>大括號</b>,一律解釋為語句(<b>即代碼塊</b>)。如果要解釋為表達式(<b>即對象</b>),必須在大括號前加上<b>圓括號</b>。
這種差異在eval語句中反映得最明顯:
eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}
2. 相關(guān)操作#
2.1 查看所有key
var o = { key1: 1, key2: 2};
Object.keys(o);// ['key1', 'key2']
2.2 刪除屬性
delet命令用于刪除對象的屬性,刪除成功后返回true。
var o = {p: 1};
Object.keys(o) // ["p"]
delete o.p // true
o.p // undefined
Object.keys(o) // []
注意,刪除一個不存在的屬性,delete不報錯,而且返回true。
var o = {};
delete o.p // true
因此,不能根據(jù)delete命令的結(jié)果,認定某個屬性是存在的。
var o = Object.defineProperty({}, 'p', { value: 123, configurable: false});
o.p // 123
delete o.p // false
<code>delete命令只能刪除對象本身的屬性!!!</code>
2.3 in運算符
in運算符用于檢查對象是否包含某個屬性(注意,檢查的是鍵名,不是鍵值),如果包含就返回true,否則返回false。in運算符的一個問題是,它不能識別對象<i>繼承</i>的屬性。
var o = new Object();
o.hasOwnProperty('toString') // false
'toString' in o // true
使用for in遍歷對象
var o = {a: 1, b: 2, c: 3};
for (var i in o) {
console.log(o[i]);
}
//提取對象屬性
var obj = { x: 1, y: 2};
var props = [];
var i = 0;
for (props[i++] in obj);
props // ['x', 'y']
2.4 with語句
(1)它的作用是操作同一個對象的多個屬性時,提供一些書寫的方便。
// 例一
with (o) {
p1 = 1;
p2 = 2;
}
// 等同于
o.p1 = 1;
o.p2 = 2;
// 例二
with (document.links[0]){
console.log(href);
console.log(title);
console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);
注意,with區(qū)塊內(nèi)部的變量,必須是當(dāng)前對象已經(jīng)存在的屬性,否則會創(chuàng)造一個當(dāng)前作用域的全局變量。這是因為with區(qū)塊沒有改變作用域,它的內(nèi)部依然是當(dāng)前作用域。
var o = {};
with (o) {
x = "abc";
}
o.x // undefined
x // "abc"
(2)這是with語句的一個很大的弊病,就是綁定對象不明確。
with (o) { console.log(x);}
單純從上面的代碼塊,根本無法判斷x到底是全局變量,還是o對象的一個屬性。這非常不利于代碼的除錯和模塊化,編譯器也無法對這段代碼進行優(yōu)化,只能留到運行時判斷,這就拖慢了運行速度。因此,建議不要使用with
語句,可以考慮用一個<code>臨時變量</code>代替with。
with(o1.o2.o3) { console.log(p1 + p2);}
// 可以寫成
var temp = o1.o2.o3;console.log(temp.p1 + temp.p2);
(3)with語句少數(shù)有用場合之一,就是替換模板變量。