1. 程式人生 > 實用技巧 >ECMAScript 6-Symbol

ECMAScript 6-Symbol

Symbol

背景:ES5的物件屬性名都是字串,這容易造成屬性名的衝突。ES6引入了一種新的原始資料型別Symbol,表示獨一無二的值,它就是Symbol資料型別

特性

1. Symbol值通過Symbol函式生成,它是一種類似於字串的資料型別
-----
let s = Symbol();
2. Symbol函式可以接受一個字串作為引數,表示對Symbol例項的描述。即使引數相同,Symbol函式的返回值依舊是不相等的
-----
var s = Symbol('foo');
s//Symbol(foo)

var s1 = Symbol('foo');
var s2 = Symbol('foo');
s1 === s2 // false
3. Symbol值不能與其他型別的值進行運算
-----
var sym = Symbol('My symbol');
"your symbol is " + sym	 //error
`your symbol is ${sym}`	 //error
4. Symbol值可以轉為字串、布林值,但不能轉為數值
-----
var s = Symbol();
s.toString() // "Symbol()"
Boolean(s) // true
Number(s) // TypeError

如何作為屬性名

由於每一個Symbol值都是不相等的,這意味著Symbol值可以作為識別符號,用於物件的屬性名,就能保證不會出現同名的屬性

  • 將Symbol作為屬性名的三種寫法

    var mySymbol = Symbol();
    
    // 第一種寫法
    var a = {};
    a[mySymbol] = 'Hello!';
    
    // 第二種寫法
    var a = {
      [mySymbol]: 'Hello!'
    };
    
    // 第三種寫法
    var a = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });
    
    // 以上寫法都得到同樣結果
    a[mySymbol] // "Hello!"
    
  • Symbol值作為物件屬性名時,不能用點運算子

    var mySymbol = Symbol();
    var a = {};
    a.mySymbol = 'Hello!';	//不可以這樣寫
    
    //解析:因為點運算子後面總是字串,所以不會讀取mySymbol作為標識名所指代的那個值,導致a的屬性名實際上是一個字串,而不是一個Symbol值。
    //結果:
    a[mySymbol] // undefined
    a['mySymbol'] // "Hello!"
    

屬性名的遍歷

  • Object.getOwnPropertySymbols():返回一個數組,成員是當前物件的所有用作屬性名的 Symbol 值

    var obj = {};			
    var a = Symbol('a');	//建立symbol
    var b = Symbol('b');	//建立symbol
    
    obj[a] = 'Hello';	//symbol作為屬性名
    obj[b] = 'World';	//symbol作為屬性名
    
    var objectSymbols = Object.getOwnPropertySymbols(obj);	//遍歷屬性名
    
    objectSymbols	// [Symbol(a), Symbol(b)]
    
  • Reflect.ownKeys():可以返回所有型別的鍵名,包括常規鍵名和 Symbol 鍵名

    let obj = {
      [Symbol('my_key')]: 1,
      enum: 2,
      nonEnum: 3
    };
    
    Reflect.ownKeys(obj)
    //  ["enum", "nonEnum", Symbol(my_key)]
    

一些方法

  • Symbol.for():接受一個字串作為引數,搜尋有沒有以該引數作為名稱的Symbol值。如果有,就返回這個Symbol值,否則就新建並返回一個以該字串為名稱的Symbol值

    var s1 = Symbol.for('foo');
    var s2 = Symbol.for('foo');
    s1 === s2 // true
    
  • Symbol.keyFor():返回一個用Symbol.for建立的 Symbol值的key

    var s1 = Symbol.for("foo");
    Symbol.keyFor(s1) // "foo"
    
    var s2 = Symbol("foo");
    Symbol.keyFor(s2) // undefined
    

內建的Symbol值

  • Symbol.hasInstance:當其他物件使用instanceof運算子,判斷是否為該物件的例項時,會呼叫這個方法。比如,foo instanceof Foo在語言內部,實際呼叫的是Foo[Symbol.hasInstance](foo)

  • Symbol.hasInstance:等於一個布林值,表示該物件使用Array.prototype.concat()時,是否可以展開 。預設等於undefined,表示可以展開,true也表示可展開;當如果為false,表示需要手動展開

    let arr1 = ['c', 'd'];
    arr1[Symbol.isConcatSpreadable] // undefined		//預設是undefined,可展開
    ['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
    
    let arr1 = ['c', 'd'];
    arr1[Symbol.isConcatSpreadable] = false;
    ['a', 'b'].concat(arr1, 'e') // ['a', 'b', ['c','d'], 'e']
    
  • Symbol.species:指向當前物件的建構函式。創造例項時,預設會呼叫這個方法,即使用這個屬性返回的函式當作建構函式,來創造新的例項物件

  • Symbol.match:指向一個函式。當執行str.match(myObject)時,如果該屬性存在,會呼叫它,返回該方法的返回值

  • Symbol.replace:指向一個方法,當該物件被String.prototype.replace方法呼叫時,會返回該方法的返回值

  • Symbol.search:指向一個方法,當該物件被String.prototype.search方法呼叫時,會返回該方法的返回值

  • Symbol.split:指向一個方法,當該物件被String.prototype.split方法呼叫時,會返回該方法的返回值

  • Symbol.iterator:指向該物件的預設遍歷器方法

  • Symbol.toPrimitive:指向一個方法。該物件被轉為原始型別的值時,會呼叫這個方法,返回該物件對應的原始型別值

  • Symbol.toStringTag:指向一個方法。在該物件上面呼叫Object.prototype.toString方法時,如果這個屬性存在,它的返回值會出現在toString方法返回的字串之中,表示物件的型別。也就是說,這個屬性可以用來定製[object Object][object Array]object後面的那個字串

    ES6新增內建物件的Symbol.toStringTag屬性值如下:

    • JSON[Symbol.toStringTag]:'JSON'
    • Math[Symbol.toStringTag]:'Math'
    • Module物件M[Symbol.toStringTag]:'Module'
    • ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer'
    • DataView.prototype[Symbol.toStringTag]:'DataView'
    • Map.prototype[Symbol.toStringTag]:'Map'
    • Promise.prototype[Symbol.toStringTag]:'Promise'
    • Set.prototype[Symbol.toStringTag]:'Set'
    • %TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等
    • WeakMap.prototype[Symbol.toStringTag]:'WeakMap'
    • WeakSet.prototype[Symbol.toStringTag]:'WeakSet'
    • %MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator'
    • %SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator'
    • %StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator'
    • Symbol.prototype[Symbol.toStringTag]:'Symbol'
    • Generator.prototype[Symbol.toStringTag]:'Generator'
    • GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'
  • Symbol.unscopables:指向一個物件。該物件指定了使用with關鍵字時,哪些屬性會被with環境排除。