ES6系列 Symbol

256 阅读2分钟

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内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。

往期内容

希望大家能一块分享一些文章,在公众号里面私信我吧!