- Symbol类型持有特性
- 1-类型是symbol,可通过typeof关键字去取的
- 2-不能使用new执行,所以instanceof 结果是false
- 3-Symbol函数接受一个字符串作为参数,表示对Symbol实例的描述
- 4-如果Symbol的参数是对象,就调用该对象的toString(),转为字符串后,才生成一个Symbol值
- 5-值是唯一的,无论是传相同的参数还是不传参
- 6-不能与其他类型进行运算,会报错
- 7-显示可以转为字符串
- 8-Symbol 值可以作为标识符,用于对象的属性名,可以保证不会出现同名的属性
- 9-Symbol作为属性名,不会出现在for…in,for…of,Object.keys(),Object.getOwnPropertyNames(),JSON.stringify()返回,只有Object.getOwnPropertySymbols方法可以返回
- 10-如果我们希望使用同一个Symbol值,可以用Symbol.for(),接受一个字符串作为参数,搜索有没有该参数做为名称的Symbol值,有就返回这个值,否则就新建
- 11-Symbol.keyFor()返回一个已登记的Symbol类型值的key
- 实现
Symbol类型持有特性
1-类型是symbol,可通过typeof关键字去取的
let s = Symbol();typeof s; // "symbol"
2-不能使用new执行,所以instanceof 结果是false
因为生成的Symbol是个原始类型的值,不是对象
let s = Symbol();s instanceof Symbol; // false
3-Symbol函数接受一个字符串作为参数,表示对Symbol实例的描述
let s = Symbol("str");console.log(s); // Symbol(str)
4-如果Symbol的参数是对象,就调用该对象的toString(),转为字符串后,才生成一个Symbol值
const obj = {toString() {return "abc";}}let s = Symbol(obj);console.log(s); // Symbol(abc)
5-值是唯一的,无论是传相同的参数还是不传参
// 没有参数let s1 = Symbol();let s2 = Symbol();s1 === s2; // false// 相同参数let s3 = Symbol("str");let s4 = Symbol("str");s3 === s4; // false
6-不能与其他类型进行运算,会报错
let s = Symbol("str");"my" + s; // Uncaught TypeError:Cannot convert a Symbol value to a string
7-显示可以转为字符串
let s = Symbol("str");String(s); // Symbol(str)s.toString(s); // Symbol(str)
8-Symbol 值可以作为标识符,用于对象的属性名,可以保证不会出现同名的属性
let s = Symbol();// 第一种写法let a = {};a[s] = "hello";// 第二种写法let a = {[s]: "hello"};// 第三种写法let a = {};Object.defineProperty(a, s, {value: "hello"});// 以上都是同样的结果a[s]; // "hello"
9-Symbol作为属性名,不会出现在for…in,for…of,Object.keys(),Object.getOwnPropertyNames(),JSON.stringify()返回,只有Object.getOwnPropertySymbols方法可以返回
let obj = {};let a1 = Symbol("a");let b1 = Symbol("b");obj[a1] = "hello";obj[b1] = "world";console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(a), Symbol(b)]
10-如果我们希望使用同一个Symbol值,可以用Symbol.for(),接受一个字符串作为参数,搜索有没有该参数做为名称的Symbol值,有就返回这个值,否则就新建
let s1 = Symbol.for("str");let s2 = Symbol.for("str");s1 === s2; // true
11-Symbol.keyFor()返回一个已登记的Symbol类型值的key
let s1 = Symbol.for("str");console.log(Symbol.keyFor(s1)); // "foo"let s2 = Symbol("str");console.log(Symbol.keyFor(s2)); // undefined
实现
(function() {var root = this;// 9-作为标识符,可用于对象属性名,而且唯一性var generateName = (function(){var postfix = 0;return function(descString) {postfix++;return "@@" + descString + "_" + postfix}})();var SymbolPolyfill = function Symbol(description) {// 2-不能调用new命令// 3-instanceof结果为false,因为不能通过new的方式实现if(this instanceof SymbolPolyfill) throw new TypeError("Symbol is not a constructor");// 5-参数是个对象就转成字符串var descString = description === undefined? undefined : String(description);var symbol = Object.create({toString: function() {return this._Name_;},// 6-不能与其它类型的值进行运算// 以+操作符为例,当进行隐式类型转换的时候,会先调用对象的valueOf方法,如果没有返回基本值,// 就会再调用toString方法,所以要在valueOf方法中进行报错valueOf: function() {throw new Error("Cannot convert a Symbol value");}});Object.definedProperties(symbol, {'_Description_' : {value: descString,writable: false,enumerable: false,configurable: false},'_Name_': {value: generateName(descString),writable: false,enumerable: false,configurable: false}});// 6-返回一个新对象,只要引用不同,就不会相同return symbol;}var forMap = {};Object.defineProperties(SymbolPolyfill, {// 10-希望重新使用相同一个Symbol值,利用Symbol.for()传入一个参数,有就返回,否则新建// 类似函数记忆,建立一个对象,用来存储已经创建的Symbol值'for': {value: function(description) {var descString = description === undefined ? undefined : String(description)return forMap[descString] ? forMap[descString] : forMap[descString] = SymbolPolyfill(descString);},writable: true,enumerable: false,configurable: true},// 11-Symbol.keyFor()方法返回一个已登记的Symbol类型的key// 遍历forMap,查找该值对应的键值即可'keyFor': {value: function(symbol) {for (var key in forMap) {if (forMap[key] === symbol) return key;}},writable: true,enumerable: false,configurable: true}});root.SymbolPolyfill = SymbolPolyfill;}())
1-typeof,结果为”symbol”
不能实现,并不能修改typeof操作符4-在控制台显示Symbol实例的时候,显示字符串
不能实现,模拟的是对象,无法通过调用原生console.log()打印出字符串7-Symbol值显式转为字符串
不能实现,因为在实现上存在第8点冲突了,模拟的所谓Symbol值其实是一个有着toString方法的对象,当对象作为对象属性名的时候,进行了隐式类型转换,还是会调用toString方法,出现相同的属性名;为了不会出现相同的属性名,要返回的是一个唯一值,需要修改toString方法,就命名为 generateName,我们将该唯一值添加到返回对象的 Name 属性中保存下来9-里面的遍历属性的方法
不能实现
微信公众号:**游戏机室
**
