深刻理解ES6之《擴展對象》

屬性初始值的簡寫

當對象字面量只有一個屬性的名稱時,JS引擎會在可訪問做用域中查找其同名變量;若是找到則該變量的值被賦給對象字面量裏的同名屬性函數

function createPerson(name, age) {
  return {
    name,
    age
  }
}

對象方法的簡寫

var person = {
  name: 'angela',
  sayName() {
    console.log(this.name)
  }
}

可計算屬性名

在ES5中若是屬性名中包含空格或者是動態的字符串變量做爲屬性名,則須要用[]方括號來訪問,以下所示this

var person = {},
  lastName = 'last name';
person["first name"] = 'Li'
person[lastName] = 'yun hua'

這種方式適用於屬性名提早已經或可被字符串字面量表示的狀況,若是屬性名「first name」被包含在一個變量中或者須要經過計算才獲得該變量的值
ES6支持了可計算屬性名
比方說上面的代碼ES6可簡化寫成以下:code

let lastName = 'last name';
var person = {
  "first name": 'Li',
  [lastName]: 'yun hua'
}

甚至方括號中內容一樣可使用表達式做爲屬性的可計算名稱對象

var suffix = 'name'
var person = {
  ['first ' + suffix]: 'Li',
  ['last ' + suffix]: 'yun hua'
}

也就是說任何可用於對象實例括號記法的屬性名一樣能夠做爲對象字面量中計算屬性名排序

Object.is

因爲全等===有一些特例:一、+0和-0相等 二、NaN和NaN不徹底相等
故ES6引用了Object.is方法來彌補全等運算符的不許備運算
對Object.is方法來講,其運算結果大部分狀況與===運算符相同,惟一區別在於+0和-0被識別爲不相等,NaN和NaN被識別爲相等繼承

Object.assign

Object.assign方法接受任意數量的源對象,並按指定的順序將屬性複製到接收對象中,因此若是多個源對象具備同名屬性,則排位靠後的源對象會覆蓋排位靠前的
有一個須要特別注意的點是Object.assign方法不能將提供者的訪問器屬性複製到接收對象中,因爲Object.assign執行了賦值操做,所以提供者的訪問器屬性最終會被轉變爲接收對象中的一個數據屬性ip

var receiver = {},
  supplier = {
    get name() {
      return "file.js"
    }
  }
Object.assign(receiver, supplier)
var desc = Object.getOwnPropertyDescriptor(receiver, "name")
console.log(desc.value)//file.js
console.log(desc.get)//undefined

重複的對象字面量屬性

在ES5嚴格模式下,對於對象字面量重複屬性則會拋出錯誤
但在ES6嚴格模式下,不會報錯,取值會選取最後一個作用域

'use strict'
var person = {
  name: 'lisa',
  name: 'angela'
}
console.log(person.name)//angela

自有屬性的枚舉順序

  1. 全部數字鍵按升序排序字符串

  2. 全部字符串按照它們被加入對象的順序排序get

  3. 全部symbol鍵按照它們被加入對象的順序排序

var obj = {
  a: 1,
  0: 1,
  c: 1,
  2: 1,
  b: 1,
  1: 1
}
obj.d = 1
console.log(Object.getOwnPropertyNames(obj).join(''))//012acbd

改變對象的原型

ES5中能夠經過Object.getPrototypeOf來返回任意指定對象的原型
ES6中添加了Object.setPrototypeOf來改變任意指定對象的原型

var person = {
  getGreeting() {
    return 'hello'
  }
}
var dog = {
  getGreeting() {
    return 'woof'
  }
}
let friend = Object.create(person)
console.log(friend.getGreeting())//hello
console.log(Object.getPrototypeOf(friend) === person)//true
Object.setPrototypeOf(friend, dog)
console.log(friend.getGreeting())//woof
console.log(Object.getPrototypeOf(friend) === dog)//true

簡化了原型訪問的Super引用

在ES5中若是要調用父類的方法,則通常是經過若是這種方式,也就是得到原型對象再經過call來調用
Object.getPrototypeOf(this).getGreeting.call(this)

var person = {
  getGreeting() {
    return 'hello'
  }
}
var dog = {
  getGreeting() {
    return 'woof'
  }
}
var friend = {
  getGreeting() {
    return Object.getPrototypeOf(this).getGreeting.call(this) + ",hi!";
  }
}
Object.setPrototypeOf(friend, person)
console.log(friend.getGreeting())//hello,hi!
console.log(Object.getPrototypeOf(friend) === person)//true
Object.setPrototypeOf(friend,dog)
console.log(friend.getGreeting())//woof,hi!
console.log(Object.getPrototypeOf(friend) === dog)//true

可是在多重繼承的狀況下,上述方法則會出錯,舉例來講

var person = {
  getGreeting() {
    return 'hello'
  }
}
var friend = {
  getGreeting() {
    return Object.getPrototypeOf(this).getGreeting.call(this) + ",hi!";
  }
}
Object.setPrototypeOf(friend, person)
var relative = Object.create(friend)
console.log(person.getGreeting())//hello
console.log(friend.getGreeting())//hello,hi!
console.log(relative.getGreeting())// 報錯 Uncaught RangeError: Maximum call stack size exceeded

ES6中經過super關鍵字可輕鬆解決問題

var person = {
  getGreeting() {
    return 'hello'
  }
}
var friend = {
  getGreeting() {
    return super.getGreeting.call(this) + ",hi!";
  }
}
Object.setPrototypeOf(friend, person)
var relative = Object.create(friend)
console.log(person.getGreeting())//hello
console.log(friend.getGreeting())//hello,hi!
console.log(relative.getGreeting())// hello,hi

你們可能會疑惑super是怎麼作到知道真正的調用對象是哪一個
這實際上是由於ES6中正式將方法定義爲一個函數,它會有一個內部的[[HomeObject]]屬性來容納這個方法從屬的對象

var person = {
  // 是方法
  getGreeting() {
    return 'hello'
  }
}
function shareGreeting(params) {
  return 'Hi!'
}

person.getGreeting方法的[[HomeObject]]屬性爲person,而shareGreeting函數未將其賦值給一個對象,於是沒有明肯定義其[[HomeObject]]屬性

super的全部引用都經過[[HomeObject]]屬性來肯定後續的運行過程

  1. 在[[HomeObject]]屬性上調用Object.getPrototypeOf方法來檢索原型的引用

  2. 搜索原型找以同名函數

  3. 設置this綁定並調用相應的方法

相關文章
相關標籤/搜索