對(duì)象類別
- 普通( Ordinary )對(duì)象:具有JavaScript對(duì)象所有的默認(rèn)內(nèi)部行為;
- 特異( Exotic )對(duì)象:具有某些與默認(rèn)行為不符的內(nèi)部行為弧械;
- 標(biāo)準(zhǔn)( Standard )對(duì)象:ES6規(guī)范中定義的對(duì)象仰挣,例如Array洛二、Date等侨歉。標(biāo)準(zhǔn)對(duì)象既可以是普通對(duì)象溉愁,也可以使特異對(duì)象处铛。
- 內(nèi)建對(duì)象:腳本開始執(zhí)行時(shí)存在于JavaScript執(zhí)行環(huán)境中的對(duì)象,所有標(biāo)準(zhǔn)對(duì)象都是內(nèi)建對(duì)象
對(duì)象字面量語(yǔ)法擴(kuò)展
- 屬性初始值的簡(jiǎn)寫
在我們傳統(tǒng)的JS中拐揭,對(duì)象字面量只是簡(jiǎn)單的鍵值對(duì)集合撤蟆,這意味著初始化屬性時(shí)會(huì)有一些重復(fù),舉個(gè)例子:
function createPerson( name, age ){
return {
name : name, //name寫了兩遍堂污,一遍是屬性名家肯,一遍是變量
age : age //age寫了兩遍,一遍是屬性名盟猖,一遍是變量
}
}
在ES6中我們對(duì)上面的屬性初始化進(jìn)行了簡(jiǎn)化讨衣,當(dāng)一個(gè)對(duì)象的屬性與本地變量同名時(shí)换棚,不必再寫冒號(hào)和值,簡(jiǎn)單地只寫屬性名即可:
function createPerson( name, age ){
return {
name 反镇,
age
}
}
/*
* 當(dāng)對(duì)象字面量里只有一個(gè)屬性的名稱時(shí)固蚤,JS引擎會(huì)在可以訪問(wèn)作用域中查找其同名變量;
* 如果找到歹茶,則該變量的值被賦給對(duì)象字面量里的同名屬性夕玩。
* 在本例中,對(duì)象字面量屬性name被賦予了局部變量name的值惊豺。
*/
- 對(duì)象方法的簡(jiǎn)寫語(yǔ)法
在ES6之前燎孟,我們?yōu)閷?duì)象添加方法,必須通過(guò)制定名稱并完整定義函數(shù):
let person = {
name : '歐陽(yáng)不乖',
sayName : function(){
console.log(this.name)
}
}
而在ES6中尸昧,語(yǔ)法更簡(jiǎn)潔揩页,消除了冒號(hào)和function關(guān)鍵字,讓我們來(lái)重寫上邊的例子:
let person = {
name : '歐陽(yáng)不乖',
sayName(){
console.log(this.name)
}
}
這種簡(jiǎn)潔寫法與傳統(tǒng)的定義對(duì)象方法所具有的特性全部一致彻磁,二者唯一的區(qū)別是碍沐,簡(jiǎn)寫方法可以使用super關(guān)鍵字(稍后討論)
- 可計(jì)算屬性名
在早期函數(shù)中,我們?nèi)绻胍ㄟ^(guò)計(jì)算得到屬性名衷蜓,只能用方括號(hào)代替點(diǎn)的方式:
// 我們想要的效果:
let name = 'unknown';
let person = {};
person[ name ] = '歐陽(yáng)不乖';
console.log(person); // {unknown: "歐陽(yáng)不乖"}
/*
* 這里我們要是換一種寫法累提,就會(huì)是不一樣的結(jié)果了
* let name = 'unknown';
* let person = {
* name : '歐陽(yáng)不乖'
* };
* console.log(person); // {name: "歐陽(yáng)不乖"}
* 當(dāng)屬性被包含在一個(gè)變量中的時(shí)候,這種賦值方式和我們?cè)O(shè)想的就不一樣了
*/
在ES6中磁浇,可在對(duì)象字面中使用可計(jì)算屬性名稱斋陪,其語(yǔ)法與引用對(duì)象實(shí)例的可計(jì)算屬性名稱相同,也是使用方括號(hào):
let name = 'unknown';
let person = {
[ name ] : '歐陽(yáng)不乖'
};
console.log(person); // {unknown: "歐陽(yáng)不乖"}
擴(kuò)展:
let suffix = 'name';
let person = {
['full-'+suffix ] : '歐陽(yáng)不乖',
[`chinese-${suffix}`] : '歐陽(yáng)不乖'
};
console.log(person); //{full-name: "歐陽(yáng)不乖", chinese-name: "歐陽(yáng)不乖"}
新增API方法
- Object.is()方法
Object.is()方法來(lái)彌補(bǔ)全等運(yùn)算符的不準(zhǔn)確運(yùn)算置吓。這個(gè)方法接受兩個(gè)參數(shù)无虚,如果這兩個(gè)參數(shù)類型相同且具有相同的值,則返回true衍锚。
其發(fā)部分運(yùn)行結(jié)果與“===”運(yùn)算符相同友题,唯一的區(qū)別在于+0和-0被識(shí)別為不相等且NaN與NaN等價(jià)。
console.log( '歐陽(yáng)不乖'==='歐陽(yáng)不乖' ); // true
console.log( Object.is('歐陽(yáng)不乖','歐陽(yáng)不乖') ); // true
console.log( +0 === -0 ); // true
console.log( Object.is(+0, -0) ); // false
console.log( NaN === NaN ); // false
console.log( Object.is(NaN,NaN) ); // true
/* 具體使用哪一種比較方法戴质,主要取決于業(yè)務(wù)需要 */
- Object.assign()方法
接受任意數(shù)量的源對(duì)象度宦,并按指定的順序?qū)傩詮?fù)制到接收對(duì)象中。所以如果多個(gè)源對(duì)象局喲樓同名屬性告匠,則排位靠后的源對(duì)象會(huì)覆蓋排位靠前的戈抄。
let receiver = {} ;
Object.assign(receiver,
{
type : 'js' ,
name : 'file.js'
},{
type : 'css'
}
);
console.log( receiver ); //{type: "css", name: "file.js"}
console.log( receiver.type ); //'css'
console.log( receiver.name ); //'file.js'
重復(fù)的對(duì)象字面量屬性
在ES5嚴(yán)格模式下,對(duì)象字面量屬性名重復(fù)時(shí)會(huì)拋出錯(cuò)誤
而在ES6中后专,字面量屬性名稱如果重復(fù)的話划鸽,只會(huì)選取最后一個(gè)取值:
let person = {
name : 'unKnown',
name : '歐陽(yáng)不乖'
}
console.log(person.name); // '歐陽(yáng)不乖'
自由屬性枚舉順序
在ES5中未定義對(duì)象屬性的枚舉順序,由Javascript引擎廠商自行決定。
在ES6中嚴(yán)格規(guī)定了對(duì)象的自由屬性被枚舉時(shí)的返回順序裸诽。
自有屬性枚舉順序的基本規(guī)則是:
- 所有數(shù)字鍵按升序排序
- 所有字符串鍵按照它們被加入對(duì)象的順序排序
- 所有symbol鍵按照它們被加入對(duì)象的順序排序
let obj = {
a:1,
0:1,
c:1,
2:1,
b:1,
1:1
}
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join('')); //012acbd
對(duì)于數(shù)值鍵嫂用,盡管在對(duì)象自綿中的順序是隨意的,但是在枚舉時(shí)會(huì)被重新組合和排序
對(duì)于for-in崭捍、Object.keys和JSON.stringify()方法暫時(shí)仍按照各引擎廠商的自行實(shí)現(xiàn)順序枚舉
增強(qiáng)對(duì)象原型
- 改變對(duì)象的原型
正常情況下尸折,對(duì)象原型是在對(duì)象被創(chuàng)建的時(shí)候指定的啰脚,對(duì)象原型在實(shí)例化之后保持不變殷蛇。
在ES6中添加了Object.setPrototypeOf()方法來(lái)改變對(duì)象原型,它接受兩個(gè)參數(shù):被改變?cè)偷膶?duì)象及替代第一個(gè)參數(shù)原型的對(duì)象:
let person = {
getGreeting(){
return 'Hello';
}
};
let dog = {
getGreeting(){
return 'Woof';
}
}
// 以person對(duì)象為原型
let friend = Object.create(person);
console.log(friend.getGreeting()); // 'Hello'
console.log(Object.getPrototypeOf(friend)===person); // true
// 將原型設(shè)置為dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting()); // 'Woof'
console.log(Object.getPrototypeOf(friend)===dog); // true
對(duì)象原型的真實(shí)值被存儲(chǔ)在內(nèi)部專用屬性[[Prototype]]中橄浓,調(diào)用Object.getPrototypeOf()方法返回存儲(chǔ)在其中的值粒梦,調(diào)用Object.setPrototypeOf()方法改變其中的值
- 簡(jiǎn)化原型訪問(wèn)的Super引用
ES6中引入了Super引用的特性,使用它可以更便捷地訪問(wèn)原型對(duì)象荸实。
let person = {
getGreeting(){
return 'Hello';
}
};
let dog = {
getGreeting(){
return 'Woof';
}
}
let friend = {
getGreeting(){
return super.getGreeting() + ',nice to meet you. '
// 等價(jià)于 Object.getPrototypeOf(this).getGreeting().call(this)
}
}
簡(jiǎn)單來(lái)說(shuō)匀们,Super引用相當(dāng)于指向?qū)ο笤偷闹羔槪瑢?shí)際上也就是Object.getPrototypeOf(this)的值准给。
Super引用不是動(dòng)態(tài)變化的泄朴,它總是指向正確的對(duì)象。
Super方法必須在簡(jiǎn)寫方法的對(duì)象中使用露氮,其他地方引用會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤祖灰。
正式的方法定義
在上邊我們用Super的時(shí)候指明要求只能在簡(jiǎn)寫方法的對(duì)象中使用,下面我們來(lái)解釋一下原因畔规。
在ES6中正式將方法定義為一個(gè)函數(shù)局扶,它會(huì)有一個(gè)內(nèi)部的[[HomeObject]]屬性來(lái)容納這個(gè)而方法從屬的對(duì)象:
let person = {
// 是方法
getGreeting(){
return 'Hello';
}
}
// 不是方法
function shareGreeting(){
return 'Hi !'
}
這個(gè)示例中定義了person對(duì)象,它有一個(gè)getGreeting()方法叁扫,由于直接把函數(shù)賦值給了person對(duì)象三妈,因而getGreeting()方法的[[HomeObject]]屬性值為person。而創(chuàng)建shareGreeting()函數(shù)時(shí)莫绣,由于未將其賦值給一個(gè)對(duì)象畴蒲,因?yàn)樵摲椒](méi)有明確定義[[HomeObject]]屬性。在大多數(shù)情況下這點(diǎn)小差別無(wú)關(guān)緊要对室,但是當(dāng)使用Super引用時(shí)就變得非常重要了模燥。
Super的所有引用都通過(guò)[[HomeObject]]屬性來(lái)確定后續(xù)的運(yùn)行過(guò)程,第一步是在[[HomeObject]]屬性上調(diào)用Object.getPrototypeOf()方法來(lái)檢索原型的引用:然后搜尋原型找到同名函數(shù)软驰;最后涧窒,設(shè)置this綁定并且調(diào)用相應(yīng)的方法。
注意:這里定義的是方法锭亏,而非函數(shù)纠吴,二者都是函數(shù)