JavaScript 對(duì)象
對(duì)象 指包含數(shù)據(jù)和用于處理數(shù)據(jù)的指令的數(shù)據(jù)結(jié)構(gòu). 對(duì)象有時(shí)也指現(xiàn)實(shí)世界中的一些事, 例如在賽車游戲當(dāng)中一輛車或者一幅地圖都可以是一個(gè)對(duì)象?!?MDN
JavaScript 中的對(duì)象由屬性
和方法
組成。
屬性可以是任意 JavaScript 中的數(shù)據(jù)類型,方法則是一個(gè)函數(shù)。
1. 創(chuàng)建對(duì)象
對(duì)象的格式如下:
{
prop1: 'value1',
prop2: 666,
prop3: {},
method1: function() {
},
}
其中 prop1
、prop2
、prop3
都是屬性,method1
是方法,屬性是任意的數(shù)據(jù)類型,方法則是一個(gè)函數(shù)。
可以看到一個(gè)屬性或者方法,在其名字與值中間采用冒號(hào) :
分隔,屬性和方法之間采用逗號(hào) ,
分隔。
通常屬性和方法的名字會(huì)被稱為屬性名
與方法名
,屬性的值稱為屬性值
,方法的值則直接叫做 方法
。
對(duì)象符合 key/value
的結(jié)構(gòu),一個(gè) key
對(duì)應(yīng)一個(gè) value
,這種結(jié)構(gòu)也被稱為鍵值對(duì),屬性名和方法名都是 key
,他們的值都是 value
。
注意:在 JavaScript 的對(duì)象中,方法和屬性的表示其實(shí)是一樣的。
一個(gè)屬性的值如果是一個(gè)函數(shù),則就把這個(gè)屬性稱之為方法,只是稱呼上的不同。
對(duì)象最簡(jiǎn)單的創(chuàng)建方式就是使用對(duì)象字面量
。
var person = {};
以上創(chuàng)建了一個(gè)最簡(jiǎn)單的空對(duì)象。
對(duì)象在 JavaScript 中的應(yīng)用范圍非常廣。
可以試想一下,如果需要用變量描述一個(gè)人的信息,包括名字、性別、年齡、雙親信息,同時(shí)就要表示這個(gè)人的一些行為,如說(shuō)話。
顯然數(shù)值、字符串、布爾類型這些數(shù)據(jù)類型是不太適合描述這樣一個(gè)人的。
這個(gè)時(shí)候就可以考慮使用對(duì)象,也就是說(shuō)當(dāng)需要描述的事物變得復(fù)合(無(wú)法使用單一的數(shù)據(jù)類型描述的時(shí)候),就可以考慮使用對(duì)象存儲(chǔ)數(shù)據(jù)。
var person = {
'name': '小明',
'age': 17,
isAdult: false,
sex: 'man',
hobby: ['eat', 'sleep', 'play doudou'],
parents: {
mather: {
name: '大紅',
},
father: {
name: '大明',
},
},
say: function() {
console.log('我叫' + this.name + ',我今年' + this.age + '歲了。');
},
};
console.log(person); // 在控制臺(tái)可以觀察 person 對(duì)象
上面這個(gè) person
變量就是一個(gè)對(duì)象,用于描述一個(gè)人,這個(gè)人具有 name
、age
等屬性與方法。
在控制臺(tái)輸出對(duì)象后,可以對(duì)其展開(kāi),觀察他的內(nèi)容。
其中部分屬性在聲明的時(shí)候,屬性名上加上了引號(hào),這在 JavaScript 中是被允許的,但一般情況下不會(huì)加上引號(hào),原因之一是沒(méi)有必要加,不應(yīng)該與字符串混淆,另外一點(diǎn)就是可以消除初學(xué)者對(duì) JSON 和 JavaScript 對(duì)象在理解上的歧義。
2. 操作對(duì)象
創(chuàng)建對(duì)象主要是為了設(shè)置、訪問(wèn)對(duì)象的屬性值,調(diào)用對(duì)象的方法等。
2.1 訪問(wèn)對(duì)象的屬性值
訪問(wèn)屬性有 2 種方式:
對(duì)象.屬性名
對(duì)象['屬性名']
var obj = {
key: 'value',
say: function() {
console.log('never 996');
},
};
console.log(obj.key); // 輸出:"value"
console.log(obj['key']); // 輸出:"value"
obj.say(); // 輸出:"never 996"
obj['say'](); // 輸出:"never 996"
這兩種方式都很常用。第二種通常會(huì)應(yīng)用在需要用變量確定屬性名的時(shí)候去使用。
var person = {
age: 27,
name: '鴿手',
};
Object.keys(person).forEach(function(key) {
console.log(person[key]);
});
以上就是使用第二種方式的場(chǎng)景之一,使用 Object.keys()
獲取到 person 的所有屬性名組成的數(shù)組,對(duì)數(shù)組做遍歷拿到每一個(gè)屬性名并放在一個(gè)變量中,再通過(guò)變量訪問(wèn)到對(duì)應(yīng)的屬性值。
當(dāng)試圖訪問(wèn)一個(gè)不存在的屬性的時(shí)候,則會(huì)返回 undefined
。
var obj = {};
console.log(obj.value); // 輸出:undefined
2.2 設(shè)置對(duì)象的屬性值
設(shè)置屬性值也有 2 種方式:
對(duì)象.屬性名 = 屬性值
對(duì)象['屬性名'] = 屬性值
設(shè)置屬性值的方式與訪問(wèn)值很相似,只是多了一個(gè)賦值操作。
設(shè)置屬性值按照如下規(guī)則進(jìn)行:
- 如果對(duì)象中不存在這個(gè)屬性,則創(chuàng)建這個(gè)屬性并賦值
- 如果對(duì)象中存在這個(gè)屬性,則直接賦值
var person = {
age: 22,
};
person.name = '阿花';
person['hobby'] = ['eat', 'play doudou'];
console.log(person);
person.age = 33;
console.log(person);
3. 使用特殊的屬性名
對(duì)象的屬性名是可以用任意字符串表示的。
上面有提到,聲明屬性的時(shí)候可以帶上引號(hào)。
如果不帶引號(hào),那屬性名必須要符合變量命名的規(guī)則,使用引號(hào)包裹屬性名,則可以使用任意字符串作為屬性名。
var obj = {
--^$@@@age: 16,
};
上面這樣寫是會(huì)報(bào)錯(cuò)的,如果非要使用這樣的屬性名,就可以加上一對(duì)引號(hào),可以雙引號(hào),也可以是單引號(hào),使用引號(hào)的規(guī)則和字符串一致。
var obj = {
'--^$@@@age': 16,
};
這種特殊的屬性名無(wú)法通過(guò) 對(duì)象.屬性名
的形式訪問(wèn)。
var obj = {
'--^$@@@age': 16,
};
var val = obj.--^$@@@age;
JavaScript 無(wú)法解析這種特殊的語(yǔ)法,所以要使用 對(duì)象['屬性名']
的形式訪問(wèn)。
var obj = {
'--^$@@@age': 16,
};
var val = obj['--^$@@@age'];
console.log(val); // 輸出:16
特殊的屬性名場(chǎng)景比較少,如統(tǒng)計(jì)字符串的場(chǎng)景。
var counter = {};
var strs = [
'#@T%TGFDSgfdsgsf',
'#@T%TGFDSgfdsgsf',
'123fdafeafewa',
'123fdafeafewa',
'#@T%TGFDSgfdsgsf',
];
strs.forEach(function(item) {
if (item in counter) {
counter[item]++;
} else {
counter[item] = 0;
}
});
console.log(counter);
strs 是由字符串組成的數(shù)組,即需要統(tǒng)計(jì)的一組數(shù)據(jù)。
利用對(duì)象的特性來(lái)對(duì)字符串分類計(jì)數(shù)。
4. 其他創(chuàng)建對(duì)象的方法
除了字面量的方式,還有許多創(chuàng)建對(duì)象的方式。
4.1 使用 Object 對(duì)象
使用 new Object()
或者 Object()
的方式也可以創(chuàng)建一個(gè)對(duì)象
var obj1 = new Object();
var obj2 = new Object; // 如果沒(méi)有參數(shù) 可以不帶括號(hào)
var obj3 = Object();
上面的方式都可以創(chuàng)建一個(gè)空對(duì)象。
比較有趣的是可以給 Object
傳遞一個(gè)對(duì)象字面量作為參數(shù),返回的對(duì)象的屬性與傳入的對(duì)象字面量的屬性一致。
var obj1 = new Object({
age: 11,
name: '長(zhǎng)睫毛',
});
var obj2 = Object({
age: 12,
name: '小酒窩',
});
console.log(obj1, obj2);
4.2 構(gòu)造函數(shù)
使用構(gòu)造函數(shù),也可以創(chuàng)建對(duì)象。
function Car(color, maxSpeed) {
this.color = color;
this.maxSpeed = maxSpeed;
}
Car.prototype.bibi = function() {
console.log('嗶嗶!');
};
var car = new Car('red', 9999999);
console.log(car);
以上例子使用構(gòu)造函數(shù)創(chuàng)建了一個(gè)速度超級(jí)快的車
對(duì)象。
4.3 Object.create
使用 Object.create
也可以創(chuàng)建一個(gè)新對(duì)象,但是必須傳遞一個(gè)對(duì)象作為參數(shù)。
var parent = {
walk: function() {
console.log('走路');
},
};
var son = Object.create(parent);
console.log(parent === son);
son.walk();
Object.create
會(huì)根據(jù)傳遞過(guò)去的對(duì)象生成一個(gè)新的對(duì)象,作為參數(shù)傳遞的對(duì)象會(huì)作為新對(duì)象的原型。
5. 遍歷對(duì)象
5.1 for … in
var me = {height: 180, weight: 70};
var i;
for (i in me) {
console.log(i);
console.log(me[i]);
}
使用 for ... in
可以遍歷對(duì)象的所有 key 值,也就是屬性名,取到所有的屬性就可以訪問(wèn)到所有的屬性值。
需要注意的是 for ... in
循環(huán)只遍歷可枚舉屬性,同時(shí)對(duì)象原型上的也會(huì)被訪問(wèn)到。
var me = {height: 180, weight: 70};
var you = Object.create(me);
you.age = 11;
var i;
for (i in you) {
console.log(i);
}
上面這個(gè)例子就把 me
和 you
中的所有屬性都遍歷出來(lái)了。
可以使用 Object.prototype.hasOwnProperty
來(lái)判斷一個(gè)屬性是否只處于其本身而不在原型上。
var me = {height: 180, weight: 70};
var you = Object.create(me);
you.age = 11;
var i;
for (i in you) {
if (you.hasOwnProperty(i)) {
console.log(i);
}
}
這樣就只會(huì)輸出 age
了。
5.2 Object.keys
Object.keys
會(huì)返回對(duì)象上的所有可枚舉屬性組成的數(shù)組。
var gugugu = {
name: '?王',
hobby: '放鴿子',
};
var keys = Object.keys(gugugu);
console.log(keys);
keys.forEach(function(key) {
console.log(gugugu[key])
});
通過(guò)遍歷屬性組成的數(shù)組來(lái)遍歷對(duì)象。
5.3 Object.getOwnPropertyNames
使用 Object.getOwnPropertyNames
也可以獲取到由屬性組成的數(shù)組,但數(shù)組會(huì)包括不可枚舉的屬性。
var gugugu = {
name: '?王',
hobby: '放鴿子',
};
var desc = Object.create(null);
desc.enumerable = false; // 是否可枚舉 默認(rèn)就是false
desc.value = '最強(qiáng)鴿手';
Object.defineProperty(gugugu, 'nickname', desc);
console.log(Object.keys(gugugu));
console.log(Object.getOwnPropertyNames(gugugu));
使用 getOwnPropertyNames
比使用 keys
多出一個(gè)不可枚舉的 nickname
屬性。
注意:ES6 還提供了
Object.values
、Object.entries
、for ... of
、Reflect.ownKeys
等特性,結(jié)合這些特性也能遍歷一個(gè)對(duì)象。
6. 創(chuàng)建絕對(duì)純凈的對(duì)象
純凈對(duì)象僅為本篇中的稱呼方式,這種特殊的對(duì)象沒(méi)有特定的稱呼。
純凈對(duì)象即原型為 null 的對(duì)象。
使用 Object.create(null)
來(lái)創(chuàng)建純凈對(duì)象。
var obj1 = Object.create(null);
console.log(obj1);
var obj2 = {};
console.log(obj2);
可以嘗試在控制臺(tái)中對(duì)比這兩個(gè)對(duì)象,純凈對(duì)象是沒(méi)有原型的,無(wú)法調(diào)用 toString
、hasOwnProperty
、valueOf
這些原型上的方法。
大部分使用純凈對(duì)象的場(chǎng)景是使用 Object.defineProperty
為對(duì)象創(chuàng)建屬性的時(shí)候,屬性的描述需要一個(gè)絕對(duì)干凈的對(duì)象,防止特殊的屬性對(duì)描述造成影響。
另外的使用場(chǎng)景就是當(dāng)作一個(gè)字典使用,防止原型上的內(nèi)容對(duì)字典產(chǎn)生干擾。
7. 小結(jié)
對(duì)象最常用的兩種創(chuàng)建方式,就是使用字面量和構(gòu)造函數(shù)。
創(chuàng)建對(duì)象的時(shí)候應(yīng)合理規(guī)劃屬性名和方法名,根據(jù)業(yè)務(wù)來(lái)確定如何使用對(duì)象。