js–Symbol 符號基本數據類型

前言

  ECMAScript 6 中新增了 Symbol 符號這一基本數據類型,那麼Symbol 是用來幹什麼的,對開發又有什麼幫助呢?本文來總結記錄一下 Symbol 的相關知識點。

正文

  Symbol (符號)是 ECMAScript 6 新增的一種基本數據類型。符號是原始值,且符號實例是唯一、不可變的。符號的用途是確保對象屬性使用唯一的標識符,不會發生屬性衝突的危險,符號就是用來創建唯一記號,進而用作非字元串形式的對象屬性。

  1、符號的創建

        var firstSymbol = Symbol()
        console.log(firstSymbol); //Symbol()

 

  上面的程式碼直接調用Symbol()方法創建了一個符號類型的變數,也可以在Symbol方法中傳入一個參數對符號變數進行描述將來可以通過這個字元串來調試程式碼。但是,這個字元串參數與符號定義或標識完全無關。如下:

        var secondSymbol = Symbol("foo")
        console.log(secondSymbol); //Symbol("foo")
        var thirdSymbol = Symbol("foo")
        console.log(secondSymbol == thirdSymbol); //false

  

  Symbol 符號類型不像其他數據類型一樣可以通過 new 來創建原始值的包裝對象。若強行使用 new 會報語法錯誤。如果你確實想使用符號包裝對象,可以借用 Object() 函數。如下:

        var myStr = new String("name")
        console.log(typeof myStr);//object
        // var mySymbol =  new Symbol()//Symbol is not a constructor at new Symbol (<anonymous>)
        var mySym = Symbol()
        var myWrapSym = Object(mySym)
        console.log(typeof myWrapSym);//object

 

  2、從全局的 Symbol 註冊表設置和取得 Symbol 

  如果運行時的不同部分需要共享和重用符號實例,那麼可以用一個字元串作為鍵,在全局符號註冊表中創建並重用符號。
  (1)Symbol.for()
  Symbol.for() 對每個字元串鍵都執行冪等操作。第一次使用某個字元串調用時,它會檢查全局運行時註冊表,發現不存在對應的符號,於是就會生成一個新符號實例並添加到註冊表中。後續使用相同字元串的調用同樣會檢查註冊表,發現存在與該字元串對應的符號,然後就會返回該符號實例。
        var fooGlobalSymbol = Symbol.for('foo'); // 創建新符號
        var otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符號
        console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
        // 即使採用相同的符號描述,在全局註冊表中定義的符號跟使用 Symbol() 定義的符號也並不等同:
        var localSymbol = Symbol('foo');
        var globalSymbol = Symbol.for('foo');
        console.log(localSymbol === globalSymbol); // false
        //此外,註冊表中使用的鍵同時也會被用作符號描述。
        console.log(localSymbol);//Symbol(foo)
        var emptyGlobalSymbol = Symbol.for();
        console.log(emptyGlobalSymbol); // Symbol(undefined)

  

  (2)Symbol.keyFor()

  Symbol.keyFor() 來查詢全局註冊表,這個方法接收符號,返回該全局符號對應的字元串鍵。如果查詢的不是全局符號,則返回 undefined 。
        var s = Symbol.for('foo');
        console.log(Symbol.keyFor(s)); // foo
        // 創建普通符號
        var ss = Symbol('bar');
        console.log(Symbol.keyFor(ss)); // undefined
        //如果傳給 Symbol.keyFor() 的不是符號,則該方法拋出 TypeError :
        // Symbol.keyFor(123); // TypeError: 123 is not a symbol

 

  3、使用符號作為屬性

  凡是可以使用字元串或數值作為屬性的地方,都可以使用符號。這就包括了對象字面量屬性和Object.defineProperty() / Object.defineProperties() 定義的屬性。對象字面量只能在計算屬性語法中使用符號作為屬性。後兩者可以用於添加屬性語法。
        var s1 = Symbol("s1");
        var s2 = Symbol("s2");
        var s3 = Symbol("s3");
        var s4 = Symbol("s4");
        var obj = { [s1]: "s1 val" }
        console.log(obj);//{Symbol(s1): "s1 val"}
        Object.defineProperty(obj, s2, { value: "s2 val" });
        console.log(obj);//{Symbol(s1): 's1 val', Symbol(s2): 's2 val'}
        Object.defineProperties(obj, { [s3]: { value: "s3 val" }, [s4]: { value: "s4 val" } })
        console.log(obj);//{Symbol(s1): "s1 val",Symbol(s2): "s2 val",Symbol(s3): "s3 val",Symbol(s4):"s4 val"}
  
  類似於 Object.getOwnPropertyNames() 返回對象實例的常規屬性數組, Object.getOwnProperty-Symbols() 返回對象實例的符號屬性數組。這兩個方法的返回值彼此互斥。 Object.getOwnProperty-Descriptors() 會返回同時包含常規和符號屬性描述符的對象。
        var ss1 = Symbol('foo')
        var info = { name: 123, age: 1232 }
        console.log(Object.getOwnPropertyNames(info));//['name', 'age']
        Object.defineProperty(info, ss1, { value: "ss1 val" })
        console.log(Object.getOwnPropertySymbols(info));//[Symbol(foo)]
        console.log(typeof Object.getOwnPropertySymbols(info)[0]);//'symbol'
        console.log(Object.getOwnPropertyDescriptors(info));//{name: {…}, age: {…}, Symbol(foo): {…}}
        console.log(Reflect.ownKeys(info));// ['name', 'age', Symbol(foo)]
        console.log(info[ss1]);//'ss1 val'

 

  Symbol 作為屬性名,該屬性不會出現在 for…in、for…of 循環中,也不會被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 返回。

        var person = { name: "personName", age: 18 }
        var sym = Symbol("sex")
        Object.defineProperty(person, sym, { value: "sexValue" })
        for (const key in person) {
            console.log(key);
        }// name age
        console.log(Object.keys(person));//["name","age"]

 

寫在最後

  以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長踩坑之路會持續更新一些工作中常見的問題和技術點。最後,祝各位coder,節日快樂。