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 以下: