微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

【读书笔记】ES6 第10章 Symbol

第十章 Symbol

参考资料:《ES6标准入门第3版》

10.1 概述

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

1. Symbol 值通过 Symbol 函数生成,数据类型是 Symbol。

let s = Symbol();

console.log(typeof s) // "symbol"

2. Symbol 函数不能使用 new 命令,否则会报错。

let s = new Symbol();
// TypeError: Symbol is not a constructor

3. Symbol 函数可以接受一个字符串参数,表示对变量的描述,输出的时候可以区分是哪一个变量。

let s = Symbol('s');
let q = Symbol('q');
console.log(s,q)
// Symbol(s) Symbol(q)

4. 每一个通过Symbol函数生成的值都是唯一的,无论参数是否相同,它们都不相等。

通过Symbol方法生成的值,无论生成多少次,无论参数是否相同,它们都不相等

let s = Symbol();
let q = Symbol();
console.log(s === q) // false

let s = Symbol('q');
let q = Symbol('q');
console.log(s === q) // false

但是通过Symbol.for() 方法可以生成一个Symbol值。有时,我们希望重新使用同一个 Symbol 值,Symbol.for() 方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

console.log(s1 === s2); // true

上面代码中,s1s2都是 Symbol 值,但是它们都是同样参数的Symbol.for方法生成的,所以实际上是同一个值。

5.Symbol值不参与其他类型值的运算,否则会报错,但是可以显式地转为字符串

let sym = Symbol('My symbol');

"your symbol is " + sym
// TypeError: can't convert symbol to string


String(sym) // 'Symbol(My symbol)'

10.2 Symbol的使用-作为对象的属性

由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

Symbol作为对象属性名的时候不能通过点运算符来访问。

let mySymbol = Symbol();

let a = {};
a[mySymbol] = 'Hello!';

console.log(a[mySymbol]) // Hello!

console.log(a.mySymbol)  // undefined

在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。

let s = Symbol();

let obj = {
  [s]: function (a) { console.log(a+2) }
};

obj[s](3);  // 5

因为对象点运算符后面总是字符串,而不会读取Symbol边量作为标识名所指代的值。在对象内部把Symbol值放在方括号中也是为了避免被认为是字符串类型的方法名。

10.3 Symbol的使用-消除魔术字符串

魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。

function getType(type){
	switch(type){
		case "square":console.log("正方形");break;
		case "triangle":console.log("三角形");break;
	}
}
getType("square") // 正方形

上面代码中,字符串square就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。

常用的消除魔术字符串的方法,就是把它写成一个变量。

const shapeType = {
  square: 'square',
  triangle:'triangle'
};


function getType(type){
	switch(type){
		case shapeType.square:console.log("正方形");break;
		case shapeType.triangle:console.log("三角形");break;
	}
}
getType(shapeType.triangle) // 三角形

如果仔细分析,可以发现shapeType.triangle等于哪个值并不重要,只要确保不会跟其他shapeType属性的值冲突即可。因此,这里就很适合改用 Symbol 值。

const shapeType = {
  square: Symbol(),
  triangle:Symbol()
};


function getType(type){
	switch(type){
		case shapeType.square:console.log("正方形");break;
		case shapeType.triangle:console.log("三角形");break;
	}
}
getType(shapeType.triangle) // 三角形

10.4 属性名的遍历

Symbol 作为属性名,该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getownPropertyNames()JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getownPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。

const obj = {};

let foo = Symbol("foo");

obj[foo] = "foo"

for (let i in obj) {
  console.log(i); // 无输出
}

console.log(JSON.stringify(obj));
// {}

console.log(Object.keys(obj));
// []

console.log(Object.getownPropertyNames(obj));
// []

console.log(Object.getownPropertySymbols(obj));
// [Symbol(foo)]

从上面的例子可以得知,使用常规的遍历方法无法得到Symbol属性名,只有使用一些特定的遍历方法才能得到 Symbol 定义的属性名。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐