深入理解ES6 004【學習筆記】

擴展對象的功能

  • 普通對象 具有js對象所有默認內部行為的
  • 特異對象 具有某些與默認行為不符的內部行為
  • 標準對象 es6規範中定義的對象,Array/Date等
  • 內建對象 腳本開始執行時存在於javascript執行環境的對象,所有標準對象都是內建對象

對象字面量語法擴展

  • 屬性初始值的簡寫,當一個對象的屬性與本地變量同名時,不必再寫冒號和值
  • 對象方法的簡寫語法
  • 可計算屬性名
// javascript 引擎會在可訪問作用域中查找其同名變量;找到,則該量變的值被賦給對象字面量里的同名屬性,在現在的js開發中,為對象字面量的屬性賦同名局部變量的值是一種常見的做法,這種簡寫方法有助於消除命名錯誤
function createPerson(name,age){
   return {
      name,
   age
   }
}
// 對象方法的簡寫 消除冒號和function關鍵字。如下
var person = {
  name:"Nicholas",
  sayName(){
     console.log(this.name)
  }
}
// 通過對象方法簡寫語法創建的方法有一個name屬性,其值為小括號前的名稱,上例中person.sayName()方法的name屬性的值為"sayName"

es5有些屬性名要通過[]方括號來設置和訪問其值,如

var person = {},lastName = "last name"
person["first name"] = "Nicholas"
person[lastName] = "Zakas"

console.log(person["first name"]); // Nicholas
console.log(person[lastName]); //Zakas

因為屬性名稱中都含有空格,因而不可使用點的方式引用,卻可以使用方括號,因為它支持通過任何字符串值作為名稱訪問屬性值。

在對象字面量中,可以直接使用字符串字面量作為屬性名稱,如下

var person = {
  "first name": "Nicholas"
}
console.log(person["first name"]); // "Nicholas"
// Es5 無法為通過計算得到的變量值,作為對象的字面量定義該屬性
// es6 通過中括號方式可以定義這樣的字面量
let lastName = "last name";
let person  = {
  "first name": "Nicholas",
  [lastName]:"Zakas"
}
console.log(person["first name"]); // Nicholas
console.log(person[lastName]); // Zakas
console.log(person["last name"]) // Zakas

Object.is()

該方法來彌補全等運算的不準確運算。這個方法接受兩個參數,如果這兩個參數類型相同有相同的值,則返回true。

Object.is(NaN,NaN) // true
NaN === Nan //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) //true
console.log(Object.is(NaN,Nan)) //true

console.log(Object.is(5,5)) //true
console.log(Object.is(5,"5")) //false

Object.assign()

混合(Mixin)是javascript中實現對象組合最流行的一種模式。在一個mixin方法中,一個對象接收來自另一個對象的屬性和方法,許多javascript庫中都有類似的mixin方法:

// 淺複製
function minxin(receiver, supplier){
  Object.keys(supplier).forEach(function(key){
    receiver[key] = supplier[key]
  })
  return receiver
}

Object.assign()方法來實現相同的功能,這個方法接受一個接收對象和任意數量的源對象,mixin()方法使用賦值操作符=來複製相關屬性,卻不能複製訪問器屬性到接收對象中,因此最終添加的方法棄用mixin而改用assign作為方法名。

Object.assign()方法可以接受任意數量的源對象,並按指定順序將屬性複製到接收對象中。如果多個源對象具有同名屬性,則排位靠後的源對象會覆蓋排位靠前的。

Object.assign()方法不能將提供者的訪問器屬性複製到接收對象中。由於Object.assign()方法執行了賦值操作,因此提供者的訪問器屬性終會轉變為接收對象中的一個數據屬性。

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

重復的對象字面量屬性

es5 屬性重名 會報錯,es6不再做這樣強制的約束,對於每一組重復屬性,都會取最後一個取值。

自有屬性枚舉順序

es6嚴格規定了對象的自有屬性被枚舉時的返回順序,這會影響到Object.getOwnPropertyName()方法及Reflect.ownKeys返回屬性的方式,Object.assign()方法處理屬性的順序也將隨之改變,規則如下:

  • 所有數字鍵按升序排序
  • 所有字符串鍵按照它們被加入對象的順序排序
  • 所有symbol鍵,按照它們被加入對象的順序排序。

增強對象原型

es5都是javascript編程最重要的設定之一,雖然在es5中添加了Object.getPrototypeOf()方法來返回任意對象的原型,但仍缺少對象在實例化後改變原型的標準方法。es6中添加了Object.setPrototypeOf()方法來改變這一現狀,通過這一方法可以改變任意指定對象的原型,它接受兩個參數:被改變原型的對象及替代第一個參數原型對象。

let person={
  getGreeting(){
    return "Hello";
  }
}
let dog = {
  getGreeting(){
    return "Woof";
  }
}

// 以person對象為原型
let friend = Ojbect.create(person);
console.log(friend.getGreeting()); // Hello
console.log(Object.getPrototypeOf(friend) === person) // true

// 將原型設置為dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting()) // Woof
console.log(Object.getPrototypeOf(friend)===dog) // true

對象原型的真實值被儲存在內部專用屬性[[Prototype]]中,調用Object.getPrototypeOf()方法返回儲存在其中的值,調用Ojbect.setPrototypeOf()方法改變其中的值。然而,這不是操作[[Prototype]]值的唯一方法。

prototype

  1. 我們需要牢記兩點:①__proto__constructor屬性是對象所獨有的;② prototype屬性是函數所獨有的,因為函數也是一種對象,所以函數也擁有__proto__constructor屬性。
  2. __proto__屬性的作用就是當訪問一個對象的屬性時,如果該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象(父對象)里找,一直找,直到__proto__屬性的終點null,再往上找就相當於在null上取值,會報錯。通過__proto__屬性將對象連接起來的這條鏈路即我們所謂的原型鏈。
  3. prototype屬性的作用就是讓該函數所實例化的對象們都可以找到公用的屬性和方法,即f1.__proto__ === Foo.prototype
  4. constructor屬性的含義就是指向該對象的構造函數,所有函數(此時看成對象了)最終的構造函數都指向Function。

簡化原型訪問的Super作用

子類方法覆寫父類方法,還要調用傳參給父類方法; ECMAScript 6引入了Super引用的特性,使用它可以更便捷地訪問對象原型

let person={
  getGreeting(){
    return "Hello";
  }
}
let dog = {
  getGreeting(){
    return "Woof";
  }
}
let friend = {
  getGreeting(){
    return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
  }
}

// 以person對象為原型
Object.setPrototypeOf(friend,person)
console.log(friend.getGreeting()); // Hello,hi!
console.log(Object.getPrototypeOf(friend) === person) // true

// 將原型設置為dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting()) // Woof,hi!
console.log(Object.getPrototypeOf(friend)===dog) // true

es6簡化了這種寫法:

let friend = {
  getGreeting(){
    // return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
    return super.getGreeting()+", hi~"
  }
}
// 注意要使用簡寫方法對象中使用super引用,如下會報錯
let friend = {
  getGreeting:function(){
    // return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
    return super.getGreeting()+", hi~"
  }
}

super引用不是動態變化的,它總是指向正確的對象,在這個示例中,無論有多少其他方法繼承了getGreeting方法,super.getGreeting()始終指向

正式的方法定義

es6中正式將方法定義為一個函數,它會有一個內部的[[HomeObject]]屬性來容納這個方法從屬性的對象。如下:

let person = {
  // 這是方法
  getGreeting(){
    return "Hello"
  }
};

// 不是方法
function shareGreeting(){
  return "Hi~";
}

理解:這示例中定義了person對象,它有一個getGreeting()方法,由於直接把函數賦值給了person對象,因而getGreeting()方法的[[HomeObject]]屬性值為person。而下面的方法shareGreeting創建時未將其賦值給一個對象,因而該方法沒有明確定義[[HomeObject]]屬性。在大多數情況下這點小差別無關緊要,但是當使用Super引用時就變得非常重要了。

super的所有引入都是通過[[HomeObject]]屬性來確定後續運行過程。第一步在[[HomeObject]]屬性上調用Object.getPrototypeOf()方法來檢索原型引用;然後搜尋原型找到同名函數,最後,設置this綁定並且調用相應的方法。

//  自己分析一下
let person={
  getGreeting(){
    return "Hello";
  }
}

let friend = {
  getGreeting(){
    // return Object.getPrototypeOf(this).getGreeting.call(this)+', hi!'
    return super.getGreeting()+", hi~"
  }
}
Object.setPrototypeOf(friend,person)
console.log(friend.getGreeting()) // "Hello hi~"

總結

  • 屬性
  • 簡化屬性定義語法,使將當前作用域中的同名變量賦值給對象的語法變得更加簡潔;
  • 添加可計算屬性名特性,允許為對象指定非字面量屬性名;
  • 添加對象方法簡寫語法,在對象字面量中定義方法時可以省略冒號和function關鍵字
  • es6嚴格模式下對象字面量重復名稱校驗,即使在同一個對象字面量中定義兩個同名屬性也不會拋出錯誤
  • Object.assign()方法可以一次性更改對象中的多個屬性,如果使用混入(mixin)模式這將非常有用
  • Object.is()方法對於所有值進行嚴格等價判斷,當將其用於處理javascript值問題時比===更加安全
  • Object.setPrototypeOf()方法,對象被創建後修改它的原型
  • super關鍵字調用原型上的方法,此時的this綁定會被自動設置為當前作用域的this值

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4329

(0)
Walker的頭像Walker
上一篇 2025年3月8日 12:51
下一篇 2025年3月8日 10:59

相關推薦

  • Go工程師體系課 003【學習筆記】

    grpc grpc grpc-go grpc 無縫集成了 protobuf protobuf 習慣用 Json、XML 數據存儲格式的你們,相信大多都沒聽過 Protocol Buffer。 Protocol Buffer 其實是 Google 出品的一種輕量 & 高效的結構化數據存儲格式,性能比 Json、XML 真的強!太!多! protobuf…

    個人 2025年11月25日
    18500
  • Go工程師體系課 017【學習筆記】

    限流、熔斷與降級入門(含 Sentinel 實戰) 結合課件第 3 章(3-1 ~ 3-9)的視頻要點,整理一套面向初學者的服務保護指南,幫助理解“為甚麼需要限流、熔斷和降級”,以及如何用 Sentinel 快速上手。 學習路線速覽 3-1 理解服務雪崩與限流、熔斷、降級的背景 3-2 Sentinel 與 Hystrix 對比,明確技術選型 3-3 Sen…

    個人 2025年11月25日
    17700
  • Node深入淺出(聖思園教育) 001【學習筆記】

    node 從異步編程範式理解 Node.js Node.js 的定位與核心思想 基於 V8 引擎 + libuv 事件驅動庫,將 JavaScript 從瀏覽器帶到服務器側。 採用單線程事件循環處理 I/O,最大化利用 CPU 等待 I/O 的時間片,特別適合高併發、I/O 密集型場景。 “不要阻塞主線程”是設計哲學:盡量把耗時操作交給內核或線程池,回調結果…

    個人 2025年11月24日
    27800
  • 深入理解ES6 011【學習筆記】

    Promise與異步編程 因為執行引擎是單線程的,所以需要跟蹤即將運行的代碼,那些代碼被放在一個任務隊列中,每當一段代碼準備執行時,都會被添加到任務隊列中,每當引擎中的一段代碼結束執行,事件循環會執行隊列中的一下個任務。 Promise相當於異步操作結果佔位符,它不會去訂閱一個事件,也不會傳遞一個回調函數給目標函數,而是讓函數返回一個Promise,就像這樣…

    個人 2025年3月8日
    1.1K00
  • Node深入淺出(聖思園教育) 002【學習筆記】

    node 的包管理機制和加載機制 npm search xxxnpm view xxxnpm install xxx nodejs 文件系統操作的 api Node.js 的 fs 模塊提供同步(Sync)與基於回調/Promise 的異步 API,可以操作本地文件與目錄。日常開發中常用的能力包括讀取、寫入、追加、刪除、遍歷目錄、監聽變化等。以下示例基於 C…

    個人 2025年11月24日
    22800
簡體中文 繁體中文 English
歡迎🌹 Coding never stops, keep learning! 💡💻 光臨🌹