在JavaScript中性置,幾乎每一個(gè)值都是某種特定類(lèi)型的對(duì)象吨枉,所以ES6加強(qiáng)了對(duì)象的功能性。
對(duì)象類(lèi)別
·普通對(duì)象:具有JavaScript對(duì)象所有默認(rèn)內(nèi)部行為誓酒。
·特異對(duì)象:具有某些與默認(rèn)行為不符的內(nèi)部行為惨缆。
·標(biāo)準(zhǔn)對(duì)象:ECMAScript6規(guī)范中定義的對(duì)象,例如:Array丰捷,Date等坯墨。標(biāo)準(zhǔn)對(duì)象既可以是普通對(duì)象,也可以是特異對(duì)象病往。
·內(nèi)建對(duì)象:腳本開(kāi)始執(zhí)行時(shí)存在于JavaScript執(zhí)行環(huán)境中的對(duì)象捣染,所有標(biāo)準(zhǔn)對(duì)象都是內(nèi)建對(duì)象。
對(duì)象字面量語(yǔ)法擴(kuò)展
屬性初始值的簡(jiǎn)寫(xiě)
在ES5中停巷,對(duì)象字面量只是簡(jiǎn)單的鍵值對(duì)集合耍攘,這意味著初始化屬性值時(shí)會(huì)有一些重復(fù)。
function createPerson(name,age){
return {
name:name,
age:age
};
}
這段代碼中這個(gè)函數(shù)屬性名稱(chēng)與函數(shù)的參數(shù)相同畔勤,在ES6中蕾各,通過(guò)使用屬性初始化的簡(jiǎn)寫(xiě)語(yǔ)法,就可以消除這種屬性名稱(chēng)與局部變量之間的重復(fù)書(shū)寫(xiě)庆揪。
//這是簡(jiǎn)寫(xiě)
function createPerson(name,age){
return {
name,
age
};
}
當(dāng)對(duì)象字面量里只有一個(gè)屬性的名稱(chēng)時(shí)式曲,JavaScript引擎會(huì)在可訪問(wèn)作用域中查找其同名變量;如果找到,就會(huì)把變量的值賦值給對(duì)象字面量的同名屬性吝羞。這樣做的好處是:有助于消除命名錯(cuò)誤兰伤。
對(duì)象方法的簡(jiǎn)寫(xiě)語(yǔ)法
ES6也改進(jìn)了為對(duì)象字面量定義方法的語(yǔ)法。
// ES6之前
var persoon={
name:"cc",
sayName:function(){
console.log(this.name);
}
};
//ES6中消除了冒號(hào)和function關(guān)鍵字
var person={
name:"cc",
sayName(){
console.log(this.name);
}
}
簡(jiǎn)寫(xiě)方法和之前的定義方法唯一不同的是簡(jiǎn)寫(xiě)方法可以使用super關(guān)鍵字(稍后討論)钧排。
可計(jì)算屬性名
在ES6之前敦腔,如果屬性名稱(chēng)被包含在變量里或者通過(guò)計(jì)算獲得該變量的值,那么ES5并不能為一個(gè)對(duì)象字面量定義該屬性的恨溜。
而在ES6中符衔,可在對(duì)象字面量中使用可計(jì)算屬性名稱(chēng),其語(yǔ)法與引用對(duì)象實(shí)例的可計(jì)算屬性名稱(chēng)相同糟袁,也是使用方括號(hào)判族。
//例子一
let lastName="last name";
let person={
"first name":"Nicholas",
[lastName]:"Zakes"
};
console.log(person["first name"]);//"Nicholas"
console.log(person[lastName]);//"Zakes"
//例子二
var suffix="name";
var person={
["first"+suffix]:"Nicholas",
["last"+suffix]:"Zakes"
};
console.log(person["firstname"]);//"Nicholas"
console.log(person["lastname"]);//"Zakes"
新增方法
ES6為了讓某些任務(wù)也更容易完成,在全局對(duì)象Object對(duì)象中引入了新的方法系吭。
Object.is()方法
ES5前五嫂,開(kāi)發(fā)者習(xí)慣用===確定比較值颗品,但是+0和-0在JavaScript中是是不同實(shí)體肯尺,然后+0===-0,同樣躯枢,NaN===NaN會(huì)返回false则吟,而ES6中引入Object.is()彌補(bǔ)全等運(yùn)算符的不準(zhǔn)確性。
console.log(+0===-0);//true
console.log(NaN===NaN);//false
console.log(Object.is(+0,-0));//false
console.log(Object.is(NaN,NaN));//true
Object.assign()方法
混合(Mixin)是JavaScript中實(shí)現(xiàn)對(duì)象組合最流行的模式锄蹂,它可以實(shí)現(xiàn)一個(gè)對(duì)象接收來(lái)自另一個(gè)對(duì)象的屬性和方法氓仲。
function mixin(receiver,supplier){
Object.keys(supplier).forEach(function(key){//遍歷自身屬性,并添加到新對(duì)象中
receiver[key]=supplier[key];
});
return receiver;
}
這樣一來(lái)利用這個(gè)函數(shù)不通過(guò)繼承就可以獲得新屬性得糜。
function EventTarget(){/*...*/}
EventTarget.prototype={
constructor:EventTarget,
emit:function(){return "cc";},
on:function(){/*...*/}
};
var myObject={};
mixin(myObject,EventTarget.prototype);
myObject.emit("somethingChanged");//"cc"
這種混合模式非常流行敬扛,所以在ES6中添加了Object.assign()方法實(shí)現(xiàn)了相同的功能,這個(gè)方法接收對(duì)象和任意數(shù)量的源對(duì)象朝抖,最終返回對(duì)象啥箭。值得注意的是不能復(fù)制訪問(wèn)器屬性。
任何使用mixin()的方法都可以直接使用這個(gè)方法治宣。
function EventTarget(){/*...*/}
EventTarget.prototype={
constructor:EventTarget,
emit:function(){return "cc";},
on:function(){/*...*/}
};
var myObject={};
Object.assign(myObject,EventTarget.prototype);
myObject.emit("somethingChanged");//"cc"
Object.assign()可以接收任意數(shù)量的源對(duì)象急侥,并按指定順序?qū)傩詮?fù)制到接收對(duì)象中,但是排位靠后的優(yōu)先侮邀。
function first(){/*...*/}
first.prototype={
constructor:"first",
emit:function(){return "first";},
on:function(){/*...*/}
};
function second(){/*...*/}
first.prototype={
constructor:"second",
emit:function(){return "second";},
on:function(){/*...*/}
};
var myObject={};
mixin(myObject,first.prototype,second.prototype);
myObject.emit("somethingChanged");//"second"
重復(fù)的對(duì)象字面量屬性
ES5嚴(yán)格模式中中坏怪,對(duì)象加入了對(duì)象字面量重復(fù)性的校檢,當(dāng)多個(gè)命名屬性時(shí)會(huì)拋出錯(cuò)誤绊茧。
而ES6中不會(huì)铝宵,ES6中會(huì)選取最后一個(gè)值。
//ES6
var person={
name:"cc",
name:"ccg"
}
console.log(person.name);//"ccg"
自有屬性枚舉順序
ES5中未定義對(duì)象屬性的枚舉順序华畏,由JavaScript引擎廠商自行決定捉超,然而ES6中嚴(yán)格規(guī)定了對(duì)象的自有屬性被枚舉的返回順序胧卤。
自有屬性的枚舉順序的基本規(guī)則是:
- 所有的數(shù)字鍵按升序排序。
- 所有的字符串鍵按照它們被加入對(duì)象的順序排序拼岳。
- 所有symbol鍵按照它們被加入對(duì)象的順序排序枝誊。
var obj={
a:1,
0:1,
c:1,
2:1,
b:1,
1:1
};
obj.d=1;
console.log(Object.getOwnPropertyNames(obj).join(""));//012acbd
增強(qiáng)對(duì)象原型
ES6對(duì)原型進(jìn)行了改進(jìn)。
改變對(duì)象的原型
正常情況下惜纸,對(duì)象原型在實(shí)例化后就無(wú)法改變了叶撒,但是ES6中添加了Object.setPrototypeOf()方法來(lái)改變這一現(xiàn)狀。
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
簡(jiǎn)化原型訪問(wèn)的Super引用
Super可以更快捷的訪問(wèn)原型耐版,請(qǐng)看例子祠够。
let person={
getGreeting(){
return "Hello";
}
};
let dog={
getGreeting(){
return "Woof";
}
};
let friend={
getGreeting(){
return Object.getPrototypeOf(this).getGreeting.call(this)+",hi";
}
};
//將原型設(shè)置為person
Object.setPrototypeOf(friend,person);
console.log(friend.getGreeting());//"Hello,hi"
console.log(Object.getPrototypeOf(friend)===person);//true
//將原型設(shè)置為dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting());//"Woof,hi"
console.log(Object.getPrototypeOf(friend)===dog);//true
//用super可以準(zhǔn)確找到指向當(dāng)前對(duì)象的原型
let friend={
getGreeting(){
return super().getGreeting()",hi";
}
};
Super在多重繼承非常有用,請(qǐng)看例子
let person={
getGreeting(){
return "Hello";
}
};
//以person對(duì)象為原型
let friend={
getGreeting(){
return Object.getPrototypeOf(this).getGreeting.call(this)+",hi";
}
};
Object.setPrototypeOf(friend,person)
//原型是friend
let relative=Object.create(friend);
console.log(person.getGreeting());//"Hello"
console.log(friend.getGreeting());//"Hello,hi"
console.log(relative.getGreeting());//error!
//call(this)的定位會(huì)使程序進(jìn)入遞歸調(diào)用粪牲,直到觸發(fā)棧溢出報(bào)錯(cuò)
如果不使用call(this)古瓤,程序會(huì)一級(jí)一級(jí)向上找,直到找到最大的構(gòu)造函數(shù)Object腺阳。
let person={
getGreeting(){
return "Hello";
}
};
//以person對(duì)象為原型
let friend={
getGreeting(){
return Object.getPrototypeOf(this).getGreeting()+",hi";
}
};
Object.setPrototypeOf(friend,person)落君;
//原型是friend
let relative=Object.create(friend);
console.log(person.getGreeting());//"Hello"
console.log(friend.getGreeting());//"Hello,hi"
console.log(relative.getGreeting());//"Hello,hi,hi"
最佳實(shí)踐是使用Super,因?yàn)樗皇莿?dòng)態(tài)變化的亭引,總會(huì)指向正確的對(duì)象绎速。
let person={
getGreeting(){
return "Hello";
}
};
//以person對(duì)象為原型
let friend={
getGreeting(){
return super.getGreeting()+",hi";
}
};
Object.setPrototypeOf(friend,person);
//原型是friend
let relative=Object.create(friend);
console.log(person.getGreeting());//"Hello"
console.log(friend.getGreeting());//"Hello,hi"
console.log(relative.getGreeting());//"Hello,hi"
正式的定義方法
ES6以前從未正式定義“方法”的概念,而在ES6中被正式定義為一個(gè)函數(shù)焙蚓,這個(gè)函數(shù)內(nèi)部包含[HomeObject]屬性容納這個(gè)方法從屬的對(duì)象纹冤。
let person={
//是方法
getGreenting(){
return "Hello";//明確賦值person,[HomeObject]的屬性值為person
}
};
//不是方法
function shareGreeting(){
return "Hi";//沒(méi)有明確賦值給一個(gè)對(duì)象购公,[HomeObject]無(wú)法定義
}
值得注意的點(diǎn)是萌京,Super的所有引用都是要通過(guò)[HomeObject]屬性來(lái)確定后續(xù)的進(jìn)程。第一步是在[HomeObject]屬性值上調(diào)用Object.getPrototypeOf()來(lái)檢索原型的引用率宏浩;然后搜索原型尋找同名函數(shù)知残;最后,設(shè)置this值并且調(diào)用相應(yīng)的方法绘闷。
let person={
getGreenting(){
return "Hello";
}
};
let friend={
getGreenting(){
return super.getGreenting()+",hi!";
}
};
//以person對(duì)象為原型
Object.setPrototypeOf(friend,person);
console.log(friend.getGreenting());//Hello,hi!