JavaScript Symbol对象
Symbol
Symbol
对象是es6
中新引进的一种数据类型,它的作用非常简单,就是用于防止属性名冲突而产生。
Symbol
的最大特点就是值是具有唯一性,这代表使用Symbol
类型的值能做独一无二的一些事情。
此外,Symbol
没有构造函数,这使得我们不能new
它,直接使用即可。
基础知识
声明Symbol
使用Symbol()
声明一个独一无二的值。
<script>
"use strict";
let Sym1 = Symbol(); // 独一无二的值
let Sym2 = Symbol();
console.log(typeof Sym1); // symbol
console.log(Sym1 == Sym2); // false
</script>
描述信息
为Symbol
的值在声明时添加一段描述信息。
使用description
属性可查看描述信息。
注意:即使两个
Symbol
的描述信息是一样的也不会有什么问题,因为它仅仅是描述信息而已。
<script>
"use strict";
let Sym1 = Symbol("这是Sym1的描述信息"); // 独一无二的值
let Sym2 = Symbol("这是Sym2的描述信息");
console.log(Sym1.description); // 这是Sym1的描述信息
console.log(Sym2.description); // 这是Sym2的描述信息
</script>
Symbol.for
使用Symbol()
来创建值不会进行记录,所以无论值看起来是否一样都不会引用同一份内存地址。
而使用Symbol.for()
来创建值则会进行记录,下次再创建相同的值时会直接引用记录的内存地址。
<script>
"use strict";
let Sym1 = Symbol("测试"); // 独一无二的值
let Sym2 = Symbol("测试");
console.log(Sym1 == Sym2); // false
</script>
<script>
"use strict";
let Sym1 = Symbol.for("测试"); // 将这个值的内存地址记录,下次再创建时直接引用内存地址
let Sym2 = Symbol.for("测试");
console.log(Sym1 == Sym2); // true
</script>
Symbol.keyFor
用于返回由Symbol.for()
创建的值的描述信息。
如果值没有描述信息则返回undefined
。
当然,我们也可以使用description
属性来获取描述信息,二者皆可。
<script>
"use strict";
let Sym1 = Symbol.for("测试"); // 将这个值的内存地址记录,下次再创建时直接引用内存地址
let Sym2 = Symbol.for();
console.log(Symbol.keyFor(Sym1)); // 测试
console.log(Symbol.keyFor(Sym2)); // undefined
console.log(Sym1.description); // 测试
console.log(Sym2.description); // undefined
</script>
实际应用
对象属性
Js
中的对象(键)如果直接声明就会变成String
类型,这在某些程度上可能会引起对象属性冲突问题。
对象的键最好是唯一的,Symbol
类型的值无疑是最好的选择。
当我们给想对象的键设置为Symbol
类型的值的时候需要注意2点问题。
Symbol
声明和访问使用[]
(变量)形式操作不能使用
.
语法因为.
语法是操作字符串属性的
<script>
"use strict";
let username = Symbol();
let age = Symbol();
let dic = { // 声明时加上 [] 否则会变成String类型 --> "username"
[username]:"云崖",
[age]:18,
};
// 不能使用 . 语法获取值(属性)
console.log(dic[username]); // 云崖
console.log(dic[age]); // 18
</script>
对象遍历
Symbol
类型值不能被 for/in
、for/of
遍历操作找到。
以下示例可以看出,找不到两个Symbol
类型的键。
<script>
"use strict";
let username = Symbol();
let age = Symbol();
let dic = { // 声明时加上 [] 否则会变成String类型 --> "username"
[username]: "云崖",
[age]: 18,
"gender": "男",
};
for (let i in dic) {
console.log(i); // gender
}
// for/of 只能遍历一个迭代对象,不能直接遍历对象。所以我们使用Object.keys(dic)将dic转换为一个迭代对象。
for (let i of Object.keys(dic)) {
console.log(i); // gender
}
</script>
可以使用 Object.getOwnPropertySymbols
获取所有Symbol
属性(键)。
注意,这是仅仅获取Symbol
的属性(键)。
<script>
"use strict";
let username = Symbol();
let age = Symbol();
let dic = { // 声明时加上 [] 否则会变成String类型 --> "username"
[username]: "云崖",
[age]: 18,
"gender": "男",
};
for (let i in Object.getOwnPropertySymbols(dic)) {
console.log(i); // 0 1
}
// for/of 只能遍历一个迭代对象,不能直接遍历对象。所以我们使用Object.keys(dic)将dic转换为一个迭代对象。
for (let i of Object.getOwnPropertySymbols(dic)) {
console.log(i); // (2) Symbol()
}
</script>
也可以使用 Reflect.ownKeys(obj)
获取所有属性(键)包括Symbol
类型的属性。
<script>
"use strict";
let username = Symbol();
let age = Symbol();
let dic = { // 声明时加上 [] 否则会变成String类型 --> "username"
[username]: "云崖",
[age]: 18,
"gender": "男",
};
for (let i in Reflect.ownKeys(dic)) {
console.log(i); // 0 1 2
}
console.log("*".repeat(20));
// for/of 只能遍历一个迭代对象,不能直接遍历对象。所以我们使用Object.keys(dic)将dic转换为一个迭代对象。
for (let i of Reflect.ownKeys(dic)) {
console.log(i); // gender (2) Symbol()
}
</script>
私有属性
我们可以使用Symbol
不能被for/in
以及for/of
访问的特性,为类制作私有属性以及提供访问接口。
<script>
"use strict";
const sex = Symbol("性别");
class User {
constructor(name, age, gender) {
this[sex] = gender; // 存入类对象中
this.name = name;
this.age = age;
}
getMsg() {
// 我们希望通过提供的API接口来让用户调出gender属性
return `姓名:${this.name},年龄:${this.age},性别:${this[sex]}`
}
}
let u1 = new User("云崖", 18, "男");
console.log(u1.getMsg()); // 只能通过接口来拿到性别 姓名:云崖,年龄:18,性别:男
// 如果循环不管是for/in还是for/of都是拿不到性别的
for (const i in u1) {
console.log(i);
// name
// age
}
</script>
来源:oschina
链接:https://my.oschina.net/u/4360480/blog/4454679