文章目录
前言
此系列文章用于记录小萌新的ES6的学习经历如有什么错误或者不好的地方请各位大佬多多指教
一、Symbol概述
ES5的对象属性名都是字符串,容易造成属性名冲突。
- 如,当为一个已有的对象,通过mixin(混合)模式添加新方法或属性时,可能与现有的方法或属性发生名称冲突。
- ES6引入新类型Symbol,表示独一无二的值,作为JavaScript语言的第7种类型。
- Symbol值通过Symbol()函数生成。
- Symbol函数前不能使用new命令,因为生成的Symbol是一个原始类型的值,不是对象。
代码如下(示例):
{
let s = Symbol();
console.log(typeof s); //symbol
let s1 = Symbol('foo');
let s2 = Symbol('bar');
console.log(s1, s1.toString()); //Symbol(foo) Symbol(foo)
console.log(s2, s2.toString()); //Symbol(bar) Symbol(bar)
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
console.log(sym); //Symbol(abc)
}
Symbol
类型在创建的时候可以传入一个字符串来当作此Symbol
类型的描述字符串
,方便再控制台输出的时候区分不同的Symbol
值。
如果再创建Symbol
的时候传入的是一个对象那么在输出的时候则会直接调用该对象的toString()
方法.
需要注意的是
Symbol
括号中传入的是一个对该Symbol
的描述
,相同的参数的Symbol值
也是不同的。
代码如下(示例):
{
let s1 = Symbol();
let s2 = Symbol();
console.log('s1==s2', s1 == s2); //s1==s2 false
let s3 = Symbol('foo');
let s4 = Symbol('foo');
console.log('s3==s4', s3 == s4); //s3==s4 false
}
二、Symbol的使用
2.1.Symbol作为属性名
Symbol
作为对象属性名保证不会出现同名的属性。对一个对象由多个模块构成的情况非常有用,能防止一个键被不小心改写或覆盖。
代码如下(示例):
{
let proSym = Symbol();
let a = {};
a[proSym] = 'hello';
console.log(a[proSym]); //hello
console.log(a); //{ [Symbol()]: 'hello' }
let b = {
[proSym]: 'world'
};
console.log(b[proSym]); //world
console.log(b); //{ [Symbol()]: 'world' }
let c = {};
Object.defineProperty(c, proSym, { value: 'here' });
console.log(c); //{Symbol(): "here"}
let d = {
[proSym](name) {
console.log('hello' + name);
}
};
d[proSym]('xiaohua'); //hello xiaohua
}
需要注意的是
- 当Symbol值作为属性名的时候不能使用
.
运算符,只能使用[]
来进行运用。 - 在使用Symbol值当属性名定义的时候,必须在方括号
[]
中来进行属性的定义。
如果Symbol值给到一个常量的化那么Symbol值将既不能修改也不可能相等,则这个常量将是非常安全的。
代码如下(示例):
{
const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol(); function getComplements(color) {
switch (color) {
case COLOR_RED:
console.log('red');
break;
case COLOR_GREEN:
console.log('green');
break;
default:
throw new Error('Undefined color');
}
}
getComplements(COLOR_GREEN); //green
}
2.2.Symbol消除魔术字符串
- 魔术字符串,指在代码中多次出现且与代码形成强耦合的某一个具体的字符串或数值。
- 风格良好的代码,应该尽量消除魔术字符串,而由含义清晰的变量代替。
代码如下(示例):
{
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle':
area = 0.5 * options.width * options.height;
break;
case 'Square':
area = options.height ** 2;
break;
default:
throw new Error('undefined shape');
}
return area;
}//'Triangle'与'Square'都是魔术字符串
let r = getArea('Triangle', { width: 100, height: 100 });
console.log(r);
}
可以看到这里的'Triangle'
和'Square'
都是魔术字符串,这里就可以使用Symbol来进行改进。改进方法如下:
代码如下(示例):
{
let shapeType = {
triangle: Symbol("triangle"),
square: Symbol("square")
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
console.log(shapeType.triangle); //Symbol(triangle)
area = 0.5 * options.width * options.height;
break;
case shapeType.square:
console.log(shapeType.square); //Symbol(square)
area = options.height ** 2;
break;
default:
throw new Error('undefined shape');
}
return area;
}
let trianglearea = getArea(shapeType.triangle, { width: 100, height: 20 });
console.log(trianglearea); //1000
let squarearea = getArea(shapeType.square, { height: 20 });
console.log(squarearea); //400
}
这里就使用了Symbol值来对魔术字符串进行了替换,这样的代码对表述来说更加清晰,并且也较规范。
2.3.Symbol属性名的遍历
- Symbol作为属性名时,该属性不会出现在
for…in
和for…of
循环中。 - 也不会被
Object.keys()
、Object.getOwnPropertyNames()
返回。 - 可以使用
Object.getOwnPropertySymbols()
方法获取指定对象的所有Symbol属性名
。
该方法返回一个数组,包含了当前对象的所有用作属性名的Symbol值
。
代码如下(示例):
{
let obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
let objectSymbols = Object.getOwnPropertySymbols(obj);
let foo = Symbol('foo');
Object.defineProperty(obj, foo, {
value: 'foobar'
});
for (let i in obj) {
console.log(i); //没有任何输出
}
let r1 = Object.getOwnPropertyNames(obj);
console.log(r1); //[]
let r2 = Object.getOwnPropertySymbols(obj);
console.log(r2); //[ Symbol(a), Symbol(b), Symbol(foo) ]
}
Reflect.ownKeys
方法可以返回所有类型的键名,包括常规键名
和Symbol键名
。
代码如下(示例):
{
let o = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
let r3 = Reflect.ownKeys(o);
console.log(r3); //[ 'enum', 'nonEnum', Symbol(my_key) ]
}
2.4.Symbol.for()与Symbol.keyFor()
- Symbol函数即使对相同字符串生成值都不相同,但有时希望重新使用同一个 Symbol值。
Symbol.for
方法接受一个字符串,然后搜索有没有以该参数作为名称的Symbol值,若有,则返回这个Symbol值,否则新建并返回一个以该字符串为名称的Symbol值。Symbol.keyFor
方法返回一个已登记
的Symbol类型值的key。
代码如下(示例):
{
//此定义的Symbol不会再全局进行登记
let s1 = Symbol('foo');
console.log(Symbol.keyFor(s1)); //undefined
//此定义的Symbol会再全局进行登记,从而可以让keyFor进行查询
s3 = Symbol.for('foo');
//keyFor是从登记的Symbol中进行查找
console.log(Symbol.keyFor(s3)); //foo
}
Symbol.for()
与Symbol()
这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。
三、JavaScript内置的Symbol值
如有兴趣了解的可以去这博主的帖子去看看
————————————————
版权声明:本文为CSDN博主「c-Tomorrow」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/c__dreamer/article/details/81873087
内置Symbol值 | 描述 |
---|---|
Symbol.hasInstance属性 | 指向一个内部方法,对象使用instanceof运算符时会调用这个方法,判断该对象是否为某个构造函数的实例。如,foo instanceof Foo则是在内部调用了FooSymbol.hasInstance。 |
Symbol. isConcatSpreadable属性 | 表示该对象使用Array.prototype.concat()时是否可以展开。该对象只能是数组或类似数组的对象。 |
Symbol. species属性 | 指向当前对象的构造函数。创建实例时默认会调用这个方法,即使用这个属性返回的函数当作构造函数来创建新的实例对象。 |
Symbol.match属性 | 指向一个函数,当执行str.match(myObject)时,如果该属性存在,会调用它返回该方法的返回值。 |
Symbol.replace属性 | 指向一个方法,当对象被String.prototype.replace方法调用时返回该方法的返回值。 |
Symbol.search属性 | 指向一个方法,当对象被String.prototype.seach方法调用时返回该方法的返回值。 |
Symbol.split属性 | 指向一个方法,当对象被String.prototype.split方法调用时返回该方法的返回值。 |
Symbol.iterator属性 | 指向该对象的默认遍历器方法。 |
Symbol.toPrimitive属性 | 指向一个方法,对象被转换为原始类型的值时会调用这个方法,返回该方法对应的原始类型值。 |
Symbol.toStringTag属性 | 指向一个方法,在对象调用Object.prototype.toString方法时,如果这个属性存在,则返回值会出现在toString方法返回的字符串中,表示对象的类型。如[object Object]、[object Array] |
Symbol.unscopables属性 | 指向一个对象,指定了使用with关键字时哪些属性会被with环境排除。 |
总结
本文主要讲述了ES6中的Symbol方面的知识,如果又不好的地方希望大家多多提意见。