ES6 經過字面量語法擴展、新增方法、改進原型等多種方式增強對象的使用,並經過解構簡化對象的數據提取過程。
在 ES6 模式下使用字面量建立對象更加簡潔,對於對象屬性來講,屬性初始值能夠簡寫,並可使用可計算的屬性名稱。對象方法的定義消除了冒號和 function 關鍵字,示例以下:git
// Demo1 var value = "name", age = 18 var person = { age, // age: age ['my' + value]: 'Jenny', // myname sayName () { // sayName: function() console.log(this.myname) } } console.log(person.age) // 18 console.log(person.myname) // Jenny person.sayName(); // Jenny
針對重複定義的對象字面量屬性,ES5嚴格模式下會進行重複屬性檢查從而拋出錯誤,而ES6移除了這個機制,不管嚴格模式仍是非嚴格模式,同名屬性都會取最後一個值。數組
// demo2 var person = { ['my' + value]: 'Jenny', myname: 'Tom', myname: 'Lee', } console.log(person.myname) // Lee
從 ES5 開始遵循的一個設計目標是,避免建立新的全局函數,也不在object.prototype
上建立新的方法。
爲了是某些任務更容易實現,ES6 在全局 Object 對象上引入一些新的方法。
ES6 引入Object.is()
方法來彌補全等運算符的不許確計算。瀏覽器
全等運算符在比較時不會觸發強制轉換類型,Object.is()
運行結果也相似,但對於 +0 和 -0(在 JS 引擎中爲兩個不一樣實體)以及特殊值NaN
的比較結果不一樣,示例來看:安全
// demo3 console.log(5 == '5') // true console.log(5 === '5') // false console.log(Object.is(5, '5')) // false console.log(+0 == -0) // true console.log(+0 === -0) // true console.log(Object.is(+0, -0)) // false console.log(NaN == NaN) // false console.log(NaN === NaN) // false console.log(Object.is(NaN, NaN)) // true
總結來講,Object.is()
對全部值進行了更嚴格等價判斷。固然,是否使用Object.is()
代替全等操做符(===)取決於這些特殊狀況是否影響代碼。函數
ES6 添加Object.assign()
來實現混合(Mixin)模式,即一個對象接收另外一個對象的屬性和方法。注意是接收而不是繼承,例如接收 demo1 中的對象:this
// demo4 var friend = {} Object.assign(friend, person) friend.sayName() // Jenny console.log(friend.age) // 18 console.log(Object.getPrototypeOf(friend) === person) // false
在Object.assign()
以前,許多 JS 庫自定義了混合方法 mixin( ) 來實現對象組合,代碼相似於:spa
function mixin(receiver, supplier) { Object.keys(supplier).forEach(function (key) { receiver[key] = supplier[key] }) return receiver }
能夠看出 mixin( ) 方法使用「=」賦值操做,並不能複製訪問器屬性,同理Object.assign()
也不能複製訪問器屬性,只是執行了賦值操做,訪問器屬性最終會轉變爲接收對象的數據屬性。示例以下:prototype
// demo5 var animal = { name: 'lili', get type () { return this.name + type }, set type (news) { type = news } } animal.type = 'cat' console.log(animal.type) // lilicat var pet = {} Object.assign(pet, animal) console.log(animal) // { name: 'lili', type: [Getter/Setter] } console.log(pet) // { name: 'lili', type: 'lilicat' }
正常狀況下對經過構造函數或Object.create()
建立時,原型是被指定的。ES6 添加Object.setPrototypeOf()
方法來改變對象的原型。設計
例如建立一個繼承 person 對象的 coder 對象,而後改變 coder 對象的原型:code
// demo6 let person = { myname: 'Jenny', sayName () { console.log(this.myname) } } // 建立原型爲 person 的 coder 對象 let coder = Object.create(person) coder.sayName() // Jenny console.log(Object.getPrototypeOf(coder) === person) // true let hero = { myname: 'lee', sayName () { console.log(this.myname) } } // 改變 coder 對象的原型爲 hero Object.setPrototypeOf(coder, hero) coder.sayName() // lee console.log(Object.getPrototypeOf(coder) === hero) // true
對象原型被存儲在內部專有屬性[[Prototype]],調用Object.getPrototypeOf()
返回存儲在其中的值,調用Object.setPrototypeOf()
改變其值。這個方法增強了對對象原型的操做,下一節重點講解其它操做原型的方式。
原型是 JS 繼承的基礎,ES6 針對原型作了不少改進,目的是更靈活地方式使用原型。除了新增的Object.setPrototypeOf()
改變原型外,還引入Super
關鍵字簡化對原型的訪問,
ES6 引入Super
來更便捷的訪問對象原型,上一節介紹 ES5 可使用Object.getPrototypeOf()
返回對象原型。舉例說明Super
的便捷,當對象須要複用原型方法,從新定義本身的方法時,兩種實現方式以下:
// demo7 let coder1 = { getName () { console.log("coder1 name: ") Object.getPrototypeOf(this).sayName.call(this) } } // 設置 coder1 對象的原型爲 hero(demo6) Object.setPrototypeOf(coder1, hero) coder1.getName() // coder1 name: lee let coder2 = { getName () { console.log("coder2 name: ") super.sayName() } } Object.setPrototypeOf(coder2, hero) coder2.getName() // coder2 name: lee
在 coder1 對象的 getName 方法還須要call(this)
保證使用的是原型方法的 this,比較複雜,而且在多重繼承會出現遞歸調用棧溢出錯誤,而直接使用Super
就很簡單安全。
注意必須在簡寫方法中使用Super
,要否則會報錯,例如如下代碼運行語法錯誤:
let coder4= { getName: function () { // getName () 正確 super.sayName() // SyntaxError: 'super' keyword unexpected here }
由於在例子中 getName 成爲了匿名 function 定義的屬性,在當前上下問調用Super
引用是非法的。若是不理解,能夠進一步看下方法的從屬對象。
ES6 以前「方法」是具備功能而非數據的對象屬性,ES6 正式將方法定義爲有 [[HomeObject]]
內部屬性的函數。
[[HomeObject]]
屬性存儲當前方法的從屬對象,例如:
let coder5 = { sayName () { console.log("I have HomeObject") } } function shareName () { console.log("No HomeObject") }
coder5 對象的 sayName( ) 方法的[[HomeObject]]
屬性值爲 coder5,而 function 定義的 shareName( ) 沒有將其賦值給對象,因此沒有定義其[[HomeObject]]
屬性,這在使用Super
時很重要。
Super
就是在[[HomeObject]]
屬性上調用Object.getPrototypeOf()
得到原型的引用,而後搜索原型獲得同名函數,最後設置 this 綁定調用相應方法。
ES6 爲數組和對象字面量提供了新特性——解構,能夠簡化數據提取的過程,減小同質化的代碼。解構的基本語法示例以下:
let user = { name: 'jenny', id: 18 } let {name, id} = user console.log(name, id) // jenny 18
注意在這段代碼中,user.name 存儲在與對象屬性名同名的 name 變量中。
若是解構時變量名稱與對象屬性名不一樣,即在對象中不存在,那麼這個變量會默認爲undefined
:
let user = { name: 'jenny', id: 18 } let {name, id, job} = user console.log(name, id, job) // jenny 18 undefined
非同名變量的默認值爲undefined
,但更多時候是須要爲其賦值的,而且會將對象屬性值賦值給非同名變量。ES6 爲此提供了擴展語法,與對象字面量屬性初始化程序很像:
let user = { name: 'jenny', id: 18 } let {name, id = 16, job = 'engineer'} = user console.log(name, id, job) // jenny 18 engineer let {name: localName, id: localId} = user console.log(localName, localId) // jenny 18 let {name: otherName = 'lee', job: otherJob = 'teacher'} = user console.log(otherName, otherJob) // jenny teacher
能夠看出這種語法實際與對象字面量相反,賦值名在冒號左,變量名在右,而且解構賦值時,只是更新了默認值,不能覆蓋對象原有的屬性值。
解構嵌套對象的語法仍然相似對象字面量,使用花括號繼續查找下層結構:
let user = { name: 'jenny', id: 18, desc: { pos: { lng: 111, lat: 333 } } } let {desc: {pos}} = user console.log(pos) // { lng: 111, lat: 333 } let {desc: {pos: {lng}}} = user console.log(lng) // 111 let {desc: {pos: {lng: longitude}}} = user console.log(longitude) // 111
ES6 規範定義了對象的類別,特別是針對瀏覽器這樣的執行環境。
推薦閱讀《深刻理解ES6》