JS-數(shù)據(jù)類型-對象Object

參考文章:對象

1.概述

1.1生成方法

什么是對象如叼?簡單說恳邀,對象就是一組“鍵值對”(key-value)的集合,是一種無序的復(fù)合數(shù)據(jù)集合黄绩。

var obj = {
  foo: 'Hello',
  bar: 'World'
};

上面代碼中,該對象內(nèi)部包含兩個鍵值對:

  • 第一個鍵值對是foo: 'Hello'玷过,其中foo是“鍵名”爽丹,字符串Hello是“鍵值”筑煮。鍵名與鍵值之間用冒號分隔。
  • 第二個鍵值對是``bar: 'World'习劫,bar是鍵名咆瘟,World`是鍵值。

    兩個鍵值對之間用逗號分隔诽里。

1.2鍵名

對象的所有鍵名都會轉(zhuǎn)為字符串ES6 又引入了 Symbol 值也可以作為鍵名)袒餐,所以加不加引號都可以。上面的代碼也可以寫成下面這樣谤狡。

var obj = {
  'foo': 'Hello',
  'bar': 'World'
};
  • 如果鍵名是數(shù)值灸眼,會被自動轉(zhuǎn)為字符串
var obj = {
  1: 'a',
  3.2: 'b',
  1e2: true,
  1e-2: true,
  .234: true,
  0xFF: true
};

obj
// Object {
//   1: "a",
//   3.2: "b",
//   100: true,
//   0.01: true,
//   0.234: true,
//   255: true
// }

obj['100'] // true
  • 如果鍵名不符合標(biāo)識名的條件(比如第一個字符為數(shù)字墓懂,或者含有空格或運(yùn)算符)焰宣,且也不是數(shù)字,則必須加上引號捕仔,否則會報錯匕积。
// 報錯
var obj = {
  1p: 'Hello World'
};

// 不報錯
var obj = {
  '1p': 'Hello World',
  'h w': 'Hello World',
  'p+q': 'Hello World'
};
  • 對象的每一個鍵名又稱為“屬性”(property),它的“鍵值”可以是任何數(shù)據(jù)類型榜跌。如果一個屬性的值為函數(shù)闪唆,通常把這個屬性稱為“方法”,它可以像函數(shù)那樣調(diào)用钓葫。
var obj = {
  p: function (x) {
    return 2 * x;
  }
};

obj.p(1) // 2

上面代碼中悄蕾,對象obj的屬性p,就指向一個函數(shù)础浮。

  • 如果屬性的值還是一個對象帆调,就形成了鏈?zhǔn)揭?/strong>。
var o1 = {};
var o2 = { bar: 'hello' };

o1.foo = o2;
o1.foo.bar // "hello"

上面代碼中豆同,對象o1的屬性foo指向?qū)ο?code>o2番刊,就可以鏈?zhǔn)揭?code>o2的屬性。

  • 屬性可以動態(tài)創(chuàng)建影锈,不必在對象聲明時就指定芹务。
var obj = {};
obj.foo = 123;
obj.foo // 123

上面代碼中,直接對obj對象的foo屬性賦值精居,結(jié)果就在運(yùn)行時創(chuàng)建了foo屬性。

1.3對象的引用

  • 如果不同的變量名指向同一個對象潜必,那么它們都是這個對象的引用靴姿,也就是說指向同一個內(nèi)存地址。修改其中一個變量磁滚,會影響到其他所有變量佛吓。
var o1 = {};
var o2 = o1;

o1.a = 1;
o2.a // 1

o2.b = 2;
o1.b // 2

上面代碼中宵晚,o1o2指向同一個對象,因此為其中任何一個變量添加屬性维雇,另一個變量都可以讀寫該屬性淤刃。

  • 此時,如果取消某一個變量對于原對象的引用吱型,不會影響到另一個變量逸贾。
var o1 = {};
var o2 = o1;

o1 = 1;
o2 // {}

上面代碼中,o1o2指向同一個對象津滞,然后o1的值變?yōu)?code>1铝侵,這時不會對o2產(chǎn)生影響,o2還是指向原來的那個對象触徐。

  • 但是咪鲜,這種引用只局限于對象,如果兩個變量指向同一個原始類型的值撞鹉。那么疟丙,變量這時都是值的拷貝
var x = 1;
var y = x;

x = 2;
y // 1

上面的代碼中鸟雏,當(dāng)x的值發(fā)生變化后享郊,y的值并不變,這就表示yx并不是指向同一個內(nèi)存地址崔慧。

1.4 new創(chuàng)建對象

function foo(){};
foo.prototype.z =3;
var obj = new foo();
obj.y =2;
obj.x =1;

obj.x;//1
obj.y;//2
obj.z;//3

'z' in obj;//true
obj.hasOwnProperty('z');//false

image

obj.z賦值為5時拂蝎,是在obj上新建了一個屬性,賦值為5惶室。不管它原型上的z屬性温自。

image

2.屬性的操作

2.1屬性的讀取

讀取對象的屬性,有兩種方法皇钞,一種是使用點(diǎn)運(yùn)算符悼泌,還有一種是使用方括號運(yùn)算符

var obj = {
  p: 'Hello World'
};

obj.p // "Hello World"
obj['p'] // "Hello World"

上面代碼分別采用點(diǎn)運(yùn)算符和方括號運(yùn)算符夹界,讀取屬性p馆里。

  • 讀取不存在的屬性不報錯,而是返回undefined可柿。

  • 請注意鸠踪,如果使用方括號運(yùn)算符,鍵名必須放在引號里面(數(shù)字鍵除外)复斥,否則會被當(dāng)作變量處理营密。

var foo = 'bar';

var obj = {
  foo: 1,
  bar: 2
};

obj.foo  // 1
obj[foo]  // 2 =>相當(dāng)于obj['bar']

上面代碼中,引用對象objfoo屬性時目锭,如果使用點(diǎn)運(yùn)算符评汰,foo就是字符串纷捞;
如果使用方括號運(yùn)算符,但是不使用引號被去,那么foo就是一個變量主儡,指向字符串bar

  • 方括號運(yùn)算符內(nèi)部還可以使用表達(dá)式惨缆。
obj['hello' + ' world']
obj[3 + 3]
  • 數(shù)字鍵可以不加引號糜值,因為會自動轉(zhuǎn)成字符串。
var obj = {
  0.7: 'Hello World'
};

obj['0.7'] // "Hello World"
obj[0.7] // "Hello World"

上面代碼中踪央,對象obj的數(shù)字鍵0.7臀玄,加不加引號都可以,因為會被自動轉(zhuǎn)為字符串畅蹂。

注意健无,數(shù)字鍵名不能使用點(diǎn)運(yùn)算符(因為會被當(dāng)成小數(shù)點(diǎn)),只能使用方括號運(yùn)算符液斜。

var obj = {
  123: 'hello world'
};

obj.123 // Uncaught SyntaxError: Unexpected number
obj[123] // "hello world"
  • 訪問屬性是通過.操作符完成的累贤,但這要求屬性名必須是一個有效的變量名。如果屬性名包含特殊字符少漆,就必須用''括起來:
var xiaohong = {
    name: '小紅',
    'middle-school': 'No.1 Middle School'
};

xiaohong的屬性名middle-school不是一個有效的變量臼膏,就需要用''括起來。訪問這個屬性也無法使用.操作符示损,必須用['xxx']來訪問:

xiaohong['middle-school']; // 'No.1 Middle School'
xiaohong['name']; // '小紅'
xiaohong.name; // '小紅'

也可以用xiaohong['name']來訪問xiaohongname屬性渗磅,不過xiaohong.name的寫法更簡潔。我們在編寫JavaScript代碼的時候检访,屬性名盡量使用標(biāo)準(zhǔn)的變量名始鱼,這樣就可以直接通過object.prop的形式訪問一個屬性了。

2.2屬性的賦值

  • 點(diǎn)運(yùn)算符和方括號運(yùn)算符脆贵,不僅可以用來讀取值医清,還可以用來賦值。
var obj = {};

obj.foo = 'Hello';
obj['bar'] = 'World';

上面代碼中卖氨,分別使用點(diǎn)運(yùn)算符和方括號運(yùn)算符会烙,對屬性賦值。

  • JavaScript 允許屬性的“后綁定”筒捺,也就是說柏腻,你可以在任意時刻新增屬性,沒必要在定義對象的時候系吭,就定義好屬性五嫂。
var obj = { p: 1 };
// 等價于
var obj = {};
obj.p = 1;

2.3屬性的查看:用Object.keys方法

查看一個對象本身的所有屬性,可以使用Object.keys方法村斟。

var obj = {
  key1: 1,
  key2: 2
};

Object.keys(obj);
// ['key1', 'key2']

2.4屬性的刪除:delete 命令

delete命令用于刪除對象的屬性贫导,刪除成功后返回true

var obj = { p: 1 };
Object.keys(obj) // ["p"]

delete obj.p // true
obj.p // undefined
Object.keys(obj) // []

上面代碼中蟆盹,delete命令刪除對象objp屬性孩灯。刪除后,再讀取p屬性就會返回undefined逾滥,而且Object.keys方法的返回值也不再包括該屬性峰档。

  • 注意,刪除一個不存在的屬性寨昙,delete不報錯讥巡,而且返回true
var obj = {};
delete obj.p // true

上面代碼中舔哪,對象obj并沒有p屬性欢顷,但是delete命令照樣返回true。因此捉蚤,不能根據(jù)delete命令的結(jié)果抬驴,認(rèn)定某個屬性是存在的。

  • 只有一種情況缆巧,delete命令會返回false布持,那就是該屬性存在,且不得刪除陕悬。
var obj = Object.defineProperty({}, 'p', {
  value: 123,
  configurable: false
});

obj.p // 123
delete obj.p // false

上面代碼之中题暖,對象objp屬性是不能刪除的,所以delete命令返回false捉超。

  • 另外胧卤,需要注意的是,delete命令只能刪除對象本身的屬性狂秦,無法刪除繼承的屬性灌侣。
var obj = {};
delete obj.toString // true
obj.toString // function toString() { [native code] }

上面代碼中,toString是對象obj繼承的屬性裂问,雖然delete命令返回true侧啼,但該屬性并沒有被刪除,依然存在堪簿。這個例子還說明痊乾,即使delete返回true,該屬性依然可能讀取到值椭更。

2.5屬性是否存在:in 運(yùn)算符

in運(yùn)算符用于檢查對象是否包含某個屬性(注意哪审,檢查的是鍵名,不是鍵值)虑瀑,如果包含就返回true湿滓,否則返回false滴须。它的左邊是一個字符串,表示屬性名叽奥,右邊是一個對象扔水。

var obj = { p: 1 };
'p' in obj // true
'toString' in obj // true

in運(yùn)算符的一個問題是,它不能識別哪些屬性是對象自身的朝氓,哪些屬性是繼承的魔市。就像上面代碼中,對象obj本身并沒有toString屬性赵哲,但是in運(yùn)算符會返回true待德,因為這個屬性是繼承的。

這時枫夺,可以使用對象的hasOwnProperty方法判斷一下将宪,是否為對象自身的屬性。

var obj = {};
if ('toString' in obj) {
  console.log(obj.hasOwnProperty('toString')) // false
}

2.6屬性的遍歷:for...in 循環(huán)

for...in循環(huán)用來遍歷一個對象的全部屬性(鍵名)橡庞,再可通過鍵名取到鍵值涧偷。

var obj = {a: 1, b: 2, c: 3};

for (var i in obj) {
  console.log('鍵名:', i);
  console.log('鍵值:', obj[i]);
}
// 鍵名: a
// 鍵值: 1
// 鍵名: b
// 鍵值: 2
// 鍵名: c
// 鍵值: 3

for...in循環(huán)有兩個使用注意點(diǎn)。

  1. 它遍歷的是對象所有可遍歷(enumerable)的屬性毙死,會跳過不可遍歷的屬性燎潮。
    它不僅遍歷對象自身的屬性,還遍歷繼承的屬性扼倘。
    舉例來說确封,對象都繼承了toString屬性,但是for...in循環(huán)不會遍歷到這個屬性再菊。
var obj = {};

// toString 屬性是存在的
obj.toString // toString() { [native code] }

for (var p in obj) {
  console.log(p);
} // 沒有任何輸出

上面代碼中爪喘,對象obj繼承了toString屬性,該屬性不會被for...in循環(huán)遍歷到纠拔,因為它默認(rèn)是“不可遍歷”的秉剑。關(guān)于對象屬性的可遍歷性,參見《標(biāo)準(zhǔn)庫》章節(jié)中 Object 一章的介紹稠诲。

  1. 如果繼承的屬性是可遍歷的侦鹏,那么就會被for...in循環(huán)遍歷到。但是臀叙,一般情況下略水,都是只想遍歷對象自身的屬性,所以使用for...in的時候劝萤,應(yīng)該結(jié)合使用hasOwnProperty方法渊涝,在循環(huán)內(nèi)部判斷一下,某個屬性是否為對象自身的屬性。
var person = { name: '老張' };

for (var key in person) {
  if (person.hasOwnProperty(key)) {
    console.log(key);
  }
}
// name

3.with 語句(不常用)

with語句的格式如下:

with (對象) {
  語句;
}

它的作用是操作同一個對象的多個屬性時跨释,提供一些書寫的方便胸私。

// 例一
var obj = {
  p1: 1,
  p2: 2,
};
with (obj) {
  p1 = 4;
  p2 = 5;
}
// 等同于
obj.p1 = 4;
obj.p2 = 5;

// 例二
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)前作用域的全局變量。

var obj = {};
with (obj) {
  p1 = 4;
  p2 = 5;
}

obj.p1 // undefined
p1 // 4

上面代碼中蚯姆,對象obj并沒有p1屬性,對p1賦值等于創(chuàng)造了一個全局變量p1洒敏。正確的寫法應(yīng)該是龄恋,先定義對象obj的屬性p1,然后在with區(qū)塊內(nèi)操作它凶伙。

這是因為with區(qū)塊沒有改變作用域郭毕,它的內(nèi)部依然是當(dāng)前作用域。這造成了with語句的一個很大的弊病函荣,就是綁定對象不明確显押。

with (obj) {
  console.log(x);
}

單純從上面的代碼塊,根本無法判斷x到底是全局變量傻挂,還是對象obj的一個屬性乘碑。這非常不利于代碼的除錯和模塊化,編譯器也無法對這段代碼進(jìn)行優(yōu)化金拒,只能留到運(yùn)行時判斷兽肤,這就拖慢了運(yùn)行速度。因此绪抛,建議不要使用with語句资铡,可以考慮用一個臨時變量代替with

with(obj1.obj2.obj3) {
  console.log(p1 + p2);
}

// 可以寫成
var temp = obj1.obj2.obj3;
console.log(temp.p1 + temp.p2);

4.序列化幢码、其它對象方法

  • 序列化
var obj = {x : 1, y : true, z : [1, 2, 3], nullVal : null};
JSON.stringify(obj); // "{"x":1,"y":true,"z":[1,2,3],"nullVal":null}"

obj = {val : undefined, a : NaN, b : Infinity, c : new Date()};
JSON.stringify(obj); // "{"a":null,"b":null,"c":"2015-01-20T14:15:43.910Z"}"

obj = JSON.parse('{"x" : 1}');
obj.x; // 1
  • 序列化-自定義
var obj = {
    x : 1,
    y : 2,
    o : {
        o1 : 1,
        o2 : 2,
        toJSON : function () {
            return this.o1 + this.o2;
        }
    }
};
JSON.stringify(obj); // "{"x":1,"y":2,"o":3}"
  • 其它對象方法
var obj = {x : 1, y : 2};
obj.toString(); // "[object Object]"
obj.toString = function() {return this.x + this.y};
"Result " + obj; // "Result 3", by toString

+obj; // 3, from toString

obj.valueOf = function() {return this.x + this.y + 100;};
+obj; // 103, from valueOf

"Result " + obj; // still "Result 3"

valueof返回對象的基本類型笤休。最后的"Result " + obj,求obj的值症副,先執(zhí)行valueof方法店雅,返回基本類型。如果valueof不存在贞铣,或返回的是不合法的值底洗,則再去找tostring方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末咕娄,一起剝皮案震驚了整個濱河市亥揖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖费变,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摧扇,死亡現(xiàn)場離奇詭異,居然都是意外死亡挚歧,警方通過查閱死者的電腦和手機(jī)扛稽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滑负,“玉大人在张,你說我怎么就攤上這事“剑” “怎么了帮匾?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長痴鳄。 經(jīng)常有香客問我瘟斜,道長,這世上最難降的妖魔是什么痪寻? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任螺句,我火速辦了婚禮,結(jié)果婚禮上橡类,老公的妹妹穿的比我還像新娘蛇尚。我一直安慰自己,他們只是感情好顾画,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布培慌。 她就那樣靜靜地躺著握侧,像睡著了一般榨为。 火紅的嫁衣襯著肌膚如雪锅睛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天义辕,我揣著相機(jī)與錄音虾标,去河邊找鬼。 笑死灌砖,一個胖子當(dāng)著我的面吹牛璧函,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播基显,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蘸吓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了撩幽?” 一聲冷哼從身側(cè)響起库继,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤箩艺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宪萄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艺谆,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年拜英,在試婚紗的時候發(fā)現(xiàn)自己被綠了静汤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡居凶,死狀恐怖虫给,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侠碧,我是刑警寧澤抹估,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站舆床,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嫁佳。R本人自食惡果不足惜挨队,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒿往。 院中可真熱鬧盛垦,春花似錦、人聲如沸瓤漏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔬充。三九已至蝶俱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饥漫,已是汗流浹背榨呆。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庸队,地道東北人积蜻。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像彻消,于是被迫代替她去往敵國和親竿拆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容