0%

Symbol

Symbol

Symbol用于防止属性名冲突而产生的,比如向第三方对象中添加属性时。

Symbol 的值是唯一的,独一无二的不会重复的

基础知识

Symbol是一个基本类型,没有构造函数所以也就不能通过new关键字来进行实例化。而是直接使用Symbol()声明。既然其没有构造函数,所以不能够使用instanceof判断类型。可以使用typeof判断类型。

1
2
3
4
5
6
let as = Symbol();
let edu = Symbol();
console.log(as); //Symbol()
console.log(as == edu); //false

console.log(typeof as); //symbol

Symbol 不可以添加属性

1
2
3
let as = Symbol();
as.name = "ashun";
console.log(as.name); //undefined

描述参数

可传入字符串用于描述Symbol,方便在控制台分辨Symbol

1
2
3
4
5
let as = Symbol("ashun");
let sy = Symbol("Ashuntefannao");

console.log(as); //Symbol(ashun)
console.log(sy.toString()); //Symbol(Ashuntefannao)

传入相同参数Symbol也是独立唯一的,因为参数只是描述而已,但使用 Symbol.for则不会

1
2
3
let symbol1 = Symbol("ashun");
let symbol2 = Symbol("ashun");
console.log(symbol1 == symbol2); //false

使用description可以获取传入的描述参数

1
2
let as = Symbol("阿顺");
console.log(as.description); //阿顺

Symbol.for

根据描述获取Symbol,如果不存在则新建一个Symbol

  • 使用Symbol.for会在系统中将Symbol登记
  • 使用Symbol则不会登记

由于Symbol.for会使得系统对Symbol做记录,所以只要描述相同,引用的就是同一个内存地址,即恒等。

1
2
3
let as = Symbol.for("ashun");
let zs = Symbol.for("ashun");
console.log(as === zs); //true
1
2
3
let as = Symbol.for();
let zs = Symbol.for();
console.log(as === zs); //true

Symbol.keyFor

Symbol.keyFor(Symbol.for()) 根据使用Symbol.for登记的Symbol返回描述,如果找不到返回undefined 。

1
2
3
4
5
6
let as = Symbol.for("ashun");
console.log(Symbol.keyFor(as));//ashun
console.log(Symbol.keyFor(Symbol.for()));//undefined

let symbol=Symbol("Ashun");
console.log(Symbol.keyFor(symbol))//undefined

设置obj属性

Symbol 是独一无二的所以可以保证对象属性的唯一。

  • Symbol 变量在作为对象属性声明和访问时,使用 [](变量)形式操作
  • 也不能使用 . 语法因为 .语法是操作字符串属性的。

下面写法是错误的,会将symbol 当成字符串symbol处理

1
2
3
4
5
let symbol = Symbol("ashun");
let obj = {
symbol: "Ashuntefannao.com",
};
console.log(obj);//{symbol: "Ashuntefannao.com"}

正确写法是以[] 变量形式声明和访问

1
2
3
4
5
6
let symbol = Symbol("ashun");
let obj = {
[symbol]: "Ashuntefannao.com"
};
console.log(obj);//{Symbol(ashun): "Ashuntefannao.com"}
console.log(obj[symbol]); //Ashuntefannao.com

实例操作

缓存操作

使用Symbol可以解决在保存数据时由于名称相同造成的耦合覆盖问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Cache {
static data = {};

static get(key) {
return data[key];
}

static set(val, key) {
this.data[key] = val;
}
}

let user = {
name: "Ashun",
type: "Controller",
key: Symbol("用户"),
};
let cart = {
name: "ShoppingCart",
type: "store",
key: Symbol("购物车"),
};

Cache.set(user, user.key);
Cache.set(cart, cart.key);
console.log(Cache.data[Symbol("用户")]); //undefined
console.log(Cache.data[user.key]); //{name: "Ashun", type: "Controller", key: Symbol(用户)}
遍历属性

Symbol作为属性名称:不能使用 for/infor/of 遍历操作

1
2
3
4
5
6
7
8
9
10
11
12
13
let symbol = Symbol("ashun");
let obj = {
name: "Ashun",
type: "Controller",
[symbol]: "Ashuntedannao.com",
};

for (let key in obj) {
console.log(key); //name type
}
for (let val of Object.values(obj)) {
console.log(val); //Ashun Controller
}

可以使用 Object.getOwnPropertySymbols 获取所有Symbol属性

  • Object.getOwnPropertySymbols返回的是一个包含所有Symbol类型属性名的Array
1
2
3
4
5
6
...
for (const key of Object.getOwnPropertySymbols(obj)) {
console.log(key);
}

console.log(Object.getOwnPropertySymbols(obj));

也可以使用 Reflect.ownKeys(obj) 获取所有属性包括Symbol

  • Reflect.ownKeys(obj)能够映射obj中的所有属性,包括Symbol
1
2
3
4
5
...
for (const key of Reflect.ownKeys(obj)) {
console.log(key);
}
...

如果对象属性不想被遍历,可以使用Symbol类型进行保护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const site = Symbol("网站名称");

class User {
constructor(name) {
this[site] = "阿顺";
this.name = name;
}
getName() {
return `${this[site]}--${this.name}`;
}
}

let user = new User("Ashuntefannao.com");
console.log(user.getName());

for (let key in user) {
console.log(key); //name
}