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

Symbol與Symbol屬性

6種原始資料型別(Primitive Data Type):Symbol。私有名稱原本是為了讓開發者們建立非字串屬性名稱而設計的,但是一般的技術無法偵測這些屬性(Property)的私有名稱。

建立Symbol

let firstName = Symbol();
let person = {}
person[firstName] = "Nicholas";
console.log(person[firstName]); // Nicholas 

new Symbol() 會報錯,Symbol函式(Function)接受一個可選參數,其可以讓你新增一段文字描述即將建立的Symbol,這段描述不可用於屬性存取,但是建議你在每次建立Symbol時都新增一段描述,以便於閱讀程式碼和偵錯Symbol程式。

let firstName = Symbol('first name');
let person = {}
person[firstName] = "Nicholas"
console.log("first name" in person); // false
console.log(person[firstName]); //Nicholas
console.log(firstName) // "Symbol(first name)"

Symbol的描述被儲存在內部的[[Description]]屬性(Property)中,只有當呼叫Symbol的toString()方法才可以讀取這個屬性,在執行console.log時,隱式呼叫了firstName的toString()方法,所以它的描述會被印到日誌中,但是不能直接在程式碼裡存取[[Description]]

使用typeof symbol 如果是會回傳'symbol',所有使用計算屬性名(Computed Property Name)的地方,都可以使用Symbol。

Symbol的使用方法

我們之前都是在括號中使用Symbol,事實上,Symbol也可以用於可計算物件(Object)字面值屬性(Literal Property)、Object.defineProperty()方法和Object.defineProperties()方法的呼叫過程。

let fristName = Symbol("first name");
// 使用一個可計算物件這字面量屬性
let person = {
  [firstName]:"Nicholas"
}
// 將屬性設定為唯讀
Object.defineProperty(person,firstName,{writable:false})

let lastName = Symbol('last name');

Object.defineProperties(person,{
  [lastName]:{
    value:"Zakas",
    writable:false
  }
})
console.log(person[firstName]) //Nicholas
console.log(person[lastName]) //Zakas

雖然在所有使用計算屬性名(Computed Property Name)的地方,都可以使用Symbol來替代,但是為了在不同的程式碼片段間有效地共享這些Symbol,需要建立一個體系。

Symbol共享體系

例如我們想在不同的物件(Object)型別,想使用同一個Symbol屬性(Property)來表示一個獨特的識別符號。在很大的程式碼庫或跨檔案追蹤Symbol非常困難且容易出錯,出於這些原因,ES6提供了一個可以隨時存取全域Symbol註冊表。使用Symbol.for(xxx) 只接受一個參數。要建立Symbol的字串描述類似Symbol('xxx')Symbol.for(xxx)會去全域註冊表中找有沒有註冊這個Symbol,有就回傳,沒有就建立一個並註冊到全域表中,下次不用再新建一個了。

Symbol與型別轉換

我上面的範例使用console.log()方法來輸出Symbol的內容,它會呼叫Symbol的String()方法輸出有用資訊,如果你試圖將一個Symbol和一個字串拼接,會導致程式拋出錯誤。

let uid = Symbol.for("uid"),
desc = String(uid);
console.log(desc); // Symbol(uid)

Symbol的屬性檢索

Object.keys()Object.getOwnPropertyNames()方法可以檢索物件(Object)中所有的屬性名(Property Name),後一個方法不考慮屬性(Property)的可列舉性(Enumerable)一律回傳。這兩個方法都支援Symbol屬性。所以又推出了一個Object.getOwnPropertySymbols()方法回傳一個包含所有Symbol自有屬性(Own Property)的值。

let uid = Symbol.for("uid");
let object = {
  [uid]:"12345"
}
let symbols = Object.getOwnPropertySymbols(object);
console.log(symbols.length) // 1
console.log(symbols[0]) // "Symbol(uid)"
console.log(object[symbols[0]]) //12345

透過well-known Symbol揭露內部操作

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.match
  • Symbol.replace
  • Symbol.species
  • Symbol.split
  • Symbol.species
  • Symbol.toPrimitive
  • Symbol.toStringTag
  • Symbol.unscopables
obj instanceof Array;
// 等價於
Array[Symbol.hasInstance](obj)
// 本質上,es6只是將instanceof運算子(Operator)重新定義為此方法的簡寫語法,現在引入呼叫後,就可以隨意改變instanceof的執行方式了。
// 假設你想定義一個無實例的函式(Function),就可以將Symbol.hasInstance的回傳值硬編碼為false
function MyObject(){
  // 空函式
}
Object.defindProperty(MyObject,Symbol.hasInstance,{
  value:function(v){
    return false
  }
})
let obj = new MyObject()
console.log(obj instanceof MyObject) // false

Symbol.isConcatSpreadable

JavaScript陣列(Array)的concat方法被設計用於拼接兩個陣列,使用如下方法:

let color1 =["red","green"],
color2 = color1.concat(["blue","black"])
console.log(color2.length) // 4
console.log(color2) // ["red","green","blue","black"]

// color1與一個臨時陣列拼接成兩個陣列
// concat方法也可以接受非陣列(Array)參數,此時該方法只會將這些參數逐一新增到陣列末尾如下。
let color1 =["red","green"],
color2 = color1.concat(["blue","black"],"brown")
console.log(color2.length) // 5
console.log(color2) // ["red","green","blue","black","brown"]
// 這個屬性(Property)可以設定或阻止呼叫concat方法時是否展開。

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

(0)
Walker的頭像Walker
上一篇 2025年11月25日 13:00
下一篇 2025年11月25日 11:00

相關推薦

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

    rocketmq 快速入門 請參考我們的各種配置(podman)以瞭解安裝方式。概念介紹 RocketMQ 是阿里巴巴開源、Apache 頂級專案的分散式訊息中介軟體,核心元件: NameServer:服務發現與路由 Broker:訊息儲存、遞送、拉取 Producer:訊息生產者(傳送訊息) Consumer:訊息消費者(訂閱並消費訊息) Topic/Tag:主題/…

    個人 2025年11月25日
    28800
  • 無畏前行,拳釋力量 🥊💪

    拚搏,是一種態度。生活就像一場比賽,沒有捷徑可走,只有不斷訓練、突破、超越,才能站上屬於自己的舞台。這不僅是一種對抗,更是一種自我的覺醒——敢於迎戰,敢於挑戰,敢於成為更強的自己。 運動中的拚搏精神 無論是拳擊、跑步,還是力量訓練,每一次出拳、每一次揮汗、每一次咬牙堅持,都是對身體與心靈的磨練。拚搏不是單純的對抗,而是一種態度——面對挑戰,不退縮;面對失敗,…

    個人 2025年2月26日
    1.5K00
  • Go工程師體系課 006【學習筆記】

    專案結構說明:user-web 模組 user-web 是 joyshop_api 專案中的使用者服務 Web 層模組,負責處理使用者相關的 HTTP 請求、參數驗證、業務路由以及呼叫後端介面等功能。以下是目錄結構說明: user-web/ ├── api/ # 控制器層,定義業務介面處理邏輯 ├── config/ # 配置模組,包含系統配置結構體及讀取邏輯 …

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

    訂單事務 先扣庫存 後扣庫存 都會對庫存和訂單都會有影響,所以要使用分散式事務 業務(下單不對付)業務問題 支付成功再扣減(下單了,支付時沒庫存了) 訂單扣減,不支付(訂單超時歸還)【常用方式】 事務和分散式事務 1. 什麼是事務? 事務(Transaction)是資料庫管理系統中的一個重要概念,它是一組資料庫操作的集合,這些操作要麼全部成功執行,要麼全部…

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

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

    個人 2025年11月25日
    29900
簡體中文 繁體中文 English