2021.04.28(作为属性名的 Symbol、实例:消除魔术字符串)
作为属性名的 Symbol
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,
就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不
小心改写或覆盖。
1. let mySymbol = Symbol(); 2. 3. // 第一种写法 4. let a = {}; 5. a[mySymbol] = 'Hello!'; 6. 7. // 第二种写法 8. let a = { 9. [mySymbol]: 'Hello!' 10. }; 11. 12. // 第三种写法 13. let a = {}; 14. Object.defineProperty(a, mySymbol, { value: 'Hello!' }); 15. 16. // 以上写法都得到同样结果 17. a[mySymbol] // "Hello!"
上面代码通过方括号结构和 Object.defineProperty ,将对象的属性名指定为一个 Symbol 值。
注意,Symbol 值作为对象属性名时,不能用点运算符。
1. const mySymbol = Symbol(); 2. const a = {}; 3. 4. a.mySymbol = 'Hello!'; 5. a[mySymbol] // undefined 6. a['mySymbol'] // "Hello!"
上面代码中,因为点运算符后面总是字符串,所以不会读取 mySymbol 作为标识名所指代的那个值,
导致 a 的属性名实际上是一个字符串,而不是一个 Symbol 值。
同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
1. let s = Symbol(); 2. 3. let obj = { 4. [s]: function (arg) { ... } 5. }; 6. 7. obj[s](123);
上面代码中,如果 s 不放在方括号中,该属性的键名就是字符串 s ,而不是 s 所代表的那个
Symbol 值。
采用增强的对象写法,上面代码的 obj 对象可以写得更简洁一些。
1. let obj = { 2. [s](arg) { ... } 3. };
Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的。
1. const log = {}; 2. 3. log.levels = { 4. DEBUG: Symbol('debug'), 5. INFO: Symbol('info'), 6. WARN: Symbol('warn') 7. }; 8. console.log(log.levels.DEBUG, 'debug message'); 9. console.log(log.levels.INFO, 'info message');
Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。
实例:消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良
好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
1. function getArea(shape, options) { 2. let area = 0; 3. 4. switch (shape) { 5. case 'Triangle': // 魔术字符串 6. area = .5 * options.width * options.height; 7. break; 8. /* ... more code ... */ 9. } 10. 11. return area; 12. } 13. 14. getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
上面代码中,字符串 Triangle 就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将
来的修改和维护。
常用的消除魔术字符串的方法,就是把它写成一个变量。
1. const shapeType = { 2. triangle: 'Triangle' 3. }; 4. 5. function getArea(shape, options) { 6. let area = 0; 7. switch (shape) { 8. case shapeType.triangle: 9. area = .5 * options.width * options.height; 10. break; 11. } 12. return area; 13. } 14. 15. getArea(shapeType.triangle, { width: 100, height: 100 });
上面代码中,我们把 Triangle 写成 shapeType 对象的 triangle 属性,这样就消除了强耦合。
如果仔细分析,可以发现 shapeType.triangle 等于哪个值并不重要,只要确保不会跟其
他 shapeType 属性的值冲突即可。因此,这里就很适合改用 Symbol 值。
1. const shapeType = { 2. triangle: Symbol() 3. };
上面代码中,除了将 shapeType.triangle 的值设为一个 Symbol,其他地方都不用修改。
2021-04-28 17:36:57