1.概述
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加属性,新属性的名字就有可能与现有属性名产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。
const classRoom = {
'Lily':{
grade: 80, gender:'female'
},
'Nina':{
grade: 60, gender:'female',
},
}
//假如有两个同学都叫 Nina
classRoom[`Nina`] = {
grade: 90, gender:'female',
}
console.log( classRoom )// 这样就覆盖了 原有属性
那么这样不符合我们的需求,我们想每一个同学的成绩都是唯一的,因此Symbol就是为了做这样的工作的。
首先我们先看怎么声明一个Symbol
//声明一个唯一的标示
const peter = Symbol()
console.log(typeof peter) // "Symbol"
const student = Symbol()
console.log(typeof student) // "Symbol"
console.log(peter === student) // false
//Symbol 声明之后就是唯一的,两者互不相干
//这样我们就能解决对象属性重复
const classRoom = {
[Symbol('Lily')]:{
grade: 80, gender:'female'
},
[Symbol('Nina')]:{
grade: 60, gender:'female',
},
}
classRoom[Symbol('Nina')] = {
grade: 90, gender:'female',
}
// 这样我们就解决了对象属性命名的冲突覆盖问题
2.属性名的遍历
用Symbol 处理过的数据格式,一般的便利方式 如 for in、Object.keys等都便利不到 但是有开始就有结束,肯定有方法能拿到我们想要的数据,
//Object.getOwnPropertySymbols(classRoom) // ES6提供遍历Symbol格式数据的操作方法
const newClassRoom = Object.getOwnPropertySymbols(classRoom).map(stm => classRoom[stm])
console.log(newClassRoom)
3.应用场景
我们知道在JavaScript中,是没有如Java等面向对象语言的访问控制关键字 private 的,类上所有定义的属性或方法都是可公开访问的。因此这对我们进行API的设计时造成了一些困扰。
而有了Symbol 与Module 模块化,类的私有属性和方法才变成可能。例如:
//Login.js
const PASSWORD = Symbol()
class Login {
constructor(username, password) {
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login
//admin.js
import Login from './Login'
const login = new Login('admin', '123456')
login.checkPassword('123456') // true
//测试一下看看能不能获取到
login.PASSWORD
login[PASSWORD]
login["PASSWORD"]
由于Symbol常量 PASSWORD 被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是唯一的),因此这个 PASSWORD 的Symbol只能被限制在Login.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。
往期内容
希望大家能一块分享一些文章,在公众号里面私信我吧!
