Symbol 是一種解決命名衝突的工具。試想咱們之前定義一個對象方法的時候老是要檢查是否已存在同名變量:數組
if(String && String.prototype && String.prototype.getCodeWith){ String.prototype.getCodeWith = function(){}; }
但是這樣寫,即使已存在同名方法,但他們實現的功能不必定同樣,並且函數的接口也不必定適合本身。這樣咱們就不得再也不給本身的函數起個其餘的名字,能夠萬一又存在呢?app
因而引入了 Symol,用來產生一個全局惟一的標識符,你能夠放心的使用它。
它接受一個字符串參數,做爲該標識符的描述:函數
var sym = Symbol("Discription"); var temp = Symbol("Discription"); console.log(sym); //Symbol(Discription) console.log(sym.valueOf()); //Symbol(Discription) console.log(sym.toString()); //"Symbol(Discription)" console.log(sym == temp); //false
描述符是用來幫助開發人員區別不一樣是 symbol,不具有其餘意義, 因此 symbol 值只有toString()
和valueOf()
方法。
Symbol 做爲一個基本類型存在於 js 中。這樣,js 就有了6個基本類型: null
, undefined
, Boolean
, Number
, String
, Symbol
和1個複雜類型: Object
使用 Symbol 須要注意如下幾點:工具
這個應該不陌生了,和普通標識符用法相似,只是不能使用.
訪問和定義,必須使用[]
:this
var sym = Symbol("abc"); var fun = Symbol("getSym"); var a = {}; a[sym] = 1; var b = { [sym]: 1, [fun](){ console.log(this[sym]); } }; var c = Object.defineProperty({}, sym, {value: 1}); a[sym]; //1 b[sym]; //1 c[sym]; //1 b[fun](); //1
固然也能夠定義一些常量,就像英語中 Symbol 表明一種象徵,一個符號:prototype
var log = { DEBUG: Symbol('debug'), ERROR: Symbol('error'), WARNING: Symbol('warning'), }
須要注意,Symbol 屬性只有Object.getOwnPropertySymbols(obj)
和 Reflect.ownKey(obj)
能夠遍歷到:debug
var sym = Symbol("pro"); var o = { a: 1, b: 2, [sym]: 3 } Object.getOwnPropertySymbols(o); //[Symbol(pro)] Reflect.ownKeys(o); //["a", "b", Symbol(pro)]
咱們能夠利用這個方法,構造一些非私有的內部變量:code
var size = Symbol('size'); class Collection{ constructor(){ this[size] = 0; } add(num){ this[this[size]] = item; this[size]++; } static sizeOf(instance){ return instance[size]; } } var x = new Collection(); console.log(Collection.sizeOf(x)); //0 x.add("foo"); console.log(Collection.sizeOf(x)); //1 console.log(Object.keys(x)); //['0'] console.log(Object.getOwnPropertyNames(x)); //['0'] console.log(Object.getOwnPropertySymbols(x)); //[Symbol(size)]
Symbol.for("aa") === Symbol.for("aa"); //true Symbol("aa") === Symbol("aa"); //false
var s1 = Symbol.for("aa"); var s2 = Symbol("aa"); Symbol.keyFor(s1); //"aa" Symbol.keyFor(s2); //undefined
注意 Symbol 的登記是全局的:對象
iframe = document.createElement('iframe'); iframe.src = String(window.location); document.body.appendChild(iframe); iframe.contentWindow.Symbol.for("aa") === Symbol.for("aa"); //true
ES6 提供了12個內置的 Symbol 值,這12個值,都是對象的,且都不可枚舉、不可配置、不可修改。由於它們具備其特殊意義:接口
var arr = [3,4]; [1,2].concat(arr); //[1,2,3,4] arr[Symbol.isConcatSpreadable] = false; [1,2].concat(arr); //[1,2,[3,4]]
對於一個類而言,該屬性必須返回 boolean 類型
class A1 extends Array{ [Symbol.isConcatSpreadable](){ return true; } } class A2 extends Array{ [Symbol.isConcatSpreadable](){ return false; } } let a1 = new A1(); a1[0] = 3; a1[1] = 4; let a2 = new A2(); a2[0] = 5; a2[1] = 6; [1,2].concat(a1).concat(a2); //[1, 2, 3, 4, 5, 6]
str.match(obj)
的時候, 若是 obj 存在該屬性,調用該方法並返回該方法的返回值String.prototype.match(searchValue); //至關於 SearchValue[Symbol.match](this); //實例 class myMatch{ constructor(str){ this.content = str; } [Symbol.match](str){ return this.content.indexOf(str); } } 'e'.match(new myMatch("Hello")); //1
str.replace(obj,replaceValue)
的時候, 若是 obj 存在該屬性,調用該方法並返回該方法的返回值String.prototype.replace(searchValue, replaceValue); //至關於 SearchValue[Symbol.replace](this, replaceValue);
str.search(obj)
的時候, 若是 obj 存在該屬性,調用該方法並返回該方法的返回值String.prototype.search(searchValue); //至關於 SearchValue[Symbol.search](this);
str.split(obj,limit)
的時候, 若是 obj 存在該屬性,調用該方法並返回該方法的返回值String.prototype.split(seperator,limit); //至關於 seperator[Symbol.split](this,limit);
class Collector{ constructor(...vals){ this.nums = vals; } *[Symbol.iterator](){ let i = this.nums.length; while(i){ i--; yield this.nums[i]; } } } var collector = new Collector(1,2,3,4,5); for(let value of collector){ console.log(value); //依次輸出 5 4 3 2 1 }
var obj = { [Symbol.toPrimitive](hint){ switch(hint){ case 'number': return 1234; case 'string': return 'hello'; case 'default': return 'default'; default: throw new Error(); } } }; console.log(obj.toString()); //[object Object] console.log(obj.valueOf()); //{ console.log(2 * obj); //2468 console.log(2 + obj); //2default console.log(obj === "hello"); //false console.log(String(obj)); //hello
//例1 console.log(Array.prototype[Symbol.unscopables]); //輸出以下,數組對象在 with 中不能訪問這些屬性方法 //{ //copyWithin: true, //entries: true, //fill: true, //find: true, //findIndex: true, //includes: true, //keys: true //}
//例2 //沒有 unscopables 時 class MyClass{ foo(){return 1} } var foo = () => 2; with(MyClass.prototype){ foo(); //1 } //有 unscopable 時 var foo = () => 2; class MyClass{ foo(){return 1;} get [Symbol.unscopables](){ return {foo:true}; } } with(MyClass.prototype){ foo(); //2 }
[object Array]
中 Array
部分。var b = { [Symbol.toStringTag]:"Hello" }; console.log(b.toString()); //"[object Hello]"
ES6 新增的 Symbol.toStringTag 以下: