其他章节请看:

es6 快速入门 系列

Symbol

es6新增的一种原始类型

试图解决的问题

唯一的属性名

给对象新增一个属性,如何保证这个属性名是独一无二的?

更改 instanceof 的运行方式

function People(){

}
let p1 = new People();
console.log(p1 instanceof People) // true

如何让上面例子中的 instanceof 返回false?

解决的方法

唯一的属性名

es6引入 Symbol 来解决对象新增属性名唯一性的问题,可以通过全局的 Sysbol 函数创建一个 Symbol,就像这样:

let key1 = Symbol()
let person = {}
// 给person对象新增了一个唯一的属性名key1
person[key1] = '11'
console.log(person[key1]) // 11

注:现在,对象的属性有两种,字符串类型和 Symbol 类型

Symbol 接受一个可选参数,用于描述即将创建的 Symbol,建议你在每次创建 Symbol 都添加这样一段描述,以便于阅读和调试。就像这样:

let fullName = Symbol('full name')
let person = {}
person[fullName] = 'aaron' console.log('full name' in person) // false
console.log(person[fullName]) // aaron
console.log(fullName) // Symbol(full name)

Symbol是一种新的原始类型(typeof 是最准确也是你最应首选的检测方式),调用 new Symbol() 会报错。

console.log(typeof Symbol()) // symbol

new Symbol() // 报错。Symbole不是构造函数

对于类型转换,Symbol 使用起来不是很灵活,因为其他类型没有与Symbol逻辑等价的值

let id = Symbol()

id + '' // 报错:不能将Symbol转换为字符串
id + 1 // 报错:不能将Symbol转换为数字
console.log(Boolean(id)) // true: Symbol与非空值类似,等价布尔值为true

更改 instanceof 的运行方式

可以通过 Symbol.hasInstance 来更改 instanceof 的运行方式,就像这样:

function People(){

}
Object.defineProperty(People, Symbol.hasInstance, {
value: function(v){
console.log(v) // People {}
return false
}
})
let p1 = new People();
console.log(p1 instanceof People) // false

es6提供了11个内置的 Symbol 值(Symbol.hasInstance就是其一),用于开放以前javascript常见的内部操作,让开发者拥有更多的权限。

补充

全局共享的 Symbol

上面使用 Symbol() 函数的语法,不会在你的整个代码库中创建一个全局的 Symbol 类型;有时我们希望在不同的代码中共享同一个 Symbol;通常,在很大的代码库或跨文档追踪 Symbol 非常困难而且容易出错,出于这些原因,es6 提供了一个可以随时访问的全局 Symnbol 注册表

创建一个全局的Symbol,要使用 Symbol.for() 方法。它只接受一个参数,也就是即将创建的 Symbol 的标识符,这个参数同样也被用作 Symbol 的描述符,就像这样:

// 首先在全局 Symbol 注册表中搜索键为"id"的Symbol是否存在
// 存在则直接返回
// 不存在则创建,然后注册到全局 Symbol 表中,最后返回
let id = Symbol.for('id')
let id2 = Symbol.for('id')
let obj = {};
obj[id] = '111' console.log(obj[id2]) // 111
console.log(id) // Symbol(id)
console.log(id === id2) // true

可以使用 Symbol.keyFor() 在全局 Symbol 注册表中检索与 Symbol 有关的键。举个例子:

let id1 = Symbol.for('id')
let id2 = Symbol.for('id')
let id3 = Symbol('id') console.log(Symbol.keyFor(id1)) // id - 全局注册表中有键 id1
console.log(Symbol.keyFor(id2)) // id
console.log(Symbol.keyFor(id3)) // undefined 全局注册表中没有键 id3

注:全局 Symbol 注册表类似全局作用域,尽量使用命名空间以减少命名冲突,例如 jQuery 的代码可以为所有键添加 "jquery" 前缀,就像 jquery.element

内置的Symbol

Symbol.hasInstance

一个执行 instanceof 时调用的内部方法,用于改变 instanceof 的运行方式

每个函数都有一个 Symbol.hasInstance 方法,用于确定对象是否为函数的实例。Symbol.hasInstance 方法只接受一个参数,即要检查的值。

// 创建一个特殊数字类,只有1~10的数字才是它的实例
function SpecialNumber(){ } Object.defineProperty(SpecialNumber, Symbol.hasInstance, {
value: function(v){
return (v instanceof Number) && (v >=1) && (v <= 10)
}
})
let eleven = new Number(11)
let one = new Number(1) console.log(eleven instanceof SpecialNumber) // false - 11 不在 1~10 的范围内
console.log(one instanceof SpecialNumber) // true - 1 在 1~10 的范围
Symbol.isConcatSpreadable

一个布尔值,表明一个对象是否应该 flattened 为它的数组元素。被 Array.prototype.concat() 使用

传给concat的参数被逐一添加到数组末尾,但数组被区别对待,因为js规范声明,传给concat的数组参数,会自动将它们分解为独立的元素

let arr1 = ['bb', 'cc']
let arr2 = ['aa'].concat(arr1, 'dd')
console.log(arr2) // [ 'aa', 'bb', 'cc', 'dd' ]

禁止区别对待,请看:

let arr1 = ['bb', 'cc']
Object.defineProperty(arr1, Symbol.isConcatSpreadable, {
// 默认是 true
value: false
})
let arr2 = ['aa'].concat(arr1, 'dd')
console.log(arr2) // [ 'aa', [ 'bb', 'cc' ], 'dd' ]

定义了一个类数组对象 obj2,Symbol.isConcatSpreadable 为 true 表明属性值应该被当作独立的元素添加到数组中。请看示例:

let obj = {
0: 'hello',
1: 'aaron',
length: 2
}
let obj2 = {
0: 'hello',
1: 'aaron',
length: 2,
[Symbol.isConcatSpreadable]: true
}
let arr = ['jack'].concat(obj)
let arr2 = ['jack'].concat(obj2) console.log(arr) // [ 'jack', { '0': 'hello', '1': 'aaron', length: 2 } ]
console.log(arr2) // [ 'jack', 'hello', 'aaron' ]
其他

由于本系列是快速入门,而内置的Symbole值有点对程序编程的味道,剩余的就不在详细介绍。

  • 正则表达式 symbols

    • Symbol.match : 被String.prototype.match()使用
    • Symbol.replace : 被String.prototype.replace()使用
    • Symbol.search : 被String.prototype.search()使用
    • Symbol.split : 被String.prototype.split()使用
  • Symbol.toPrimitive : 对象转为原始值,调用此方法
  • Symbol.toStringTag : 被Object.prototype.toString()调用
  • Symbol.unscopables : 与 with 相关。如果你不使用with,可以忽略它
  • Symbol.iterator : 一个返回迭代器的方法
  • Symbol.species : 用于创建派生对象的构造函数

Object.getOwnPropertySymbols()

像 Object.keys()、Object.getOwnPropertyNames()这样的方法不返回任何 Symbol,所以 es6 添加了一个新方法 Object.getOwnPropertySymbols(),用于检索 Symbol 属性。

此方法返回一个给定对象自身的所有 Symbol 属性的数组。请看示例:

let obj = {c: 'c1', d: 'd1'};
let a = Symbol("a");
let b = Symbol.for("b"); obj[a] = "localSymbol";
obj[b] = "globalSymbol"; let objectSymbols = Object.getOwnPropertySymbols(obj);
// 返回Symbol属性的数组
console.log(objectSymbols.length); // 2
console.log(objectSymbols) // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0]) // Symbol(a) // 不包括Symbol属性
console.log(Object.keys(obj)) // ['c', 'd']
console.log(Object.getOwnPropertyNames(obj)) // ['c', 'd']

其他章节请看:

es6 快速入门 系列

es6 快速入门 系列 —— Symbol的更多相关文章

  1. es6 快速入门 系列 —— 类 (class)

    其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...

  2. es6 快速入门 系列 —— 对象

    其他章节请看: es6 快速入门 系列 对象 试图解决的问题 写法繁杂 属性初始值需要重复写 function createPeople(name, age){ // name 和 age 都写了 2 ...

  3. es6 快速入门 系列 —— 变量声明:let和const

    其他章节请看: es6 快速入门 系列 变量声明:let和const 试图解决的问题 经典的 var 声明让人迷惑 function demo1(v){ if(v){ var color='red' ...

  4. es6 快速入门 系列 —— promise

    其他章节请看: es6 快速入门 系列 Promise Promise 是一种异步编程的选择 初步认识Promise 用 Promise 来实现这样一个功能:发送一个 ajax,返回后输出 json ...

  5. es6快速入门 系列 - async

    其他章节请看: es6 快速入门 系列 async 前文我们已经知道 promise 是一种异步编程的选择.而 async 是一种用于执行异步任务更简单的语法. Tip:建议学完 Promise 在看 ...

  6. es6 快速入门 系列

    es6 快速入门(未完结,持续更新中...) 前言 为什么要学习es6 es6对于所有javaScript开发者来说,非常重要 未来,es6将构成javaScript应用程序的基础 es6中很多特性, ...

  7. es6 快速入门 —— 函数

    其他章节请看: es6 快速入门 系列 函数 函数是所有编程语言的重要组成部分,es6之前函数语法一直没什么变化,遗留了许多问题,javaScript开发者多年来不断抱怨,es6终于决定大力度更新函数 ...

  8. ES6快速入门(二)数据结构

    ES6快速入门 一.解构 1. 对象解构 let person = { name: 'Tang', age: 28 }; //必须同名,必须初始化 let {name, age} = person; ...

  9. python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)

    BBS项目内容回顾 1. 登陆页面 1. 验证码 1. PIL(Pillow) 2. io 2. ORM 1. 增删改查 3. AJAX $.ajax({ url: '', type: '', dat ...

  10. vue 快速入门 系列 —— 侦测数据的变化 - [基本实现]

    其他章节请看: vue 快速入门 系列 侦测数据的变化 - [基本实现] 在 初步认识 vue 这篇文章的 hello-world 示例中,我们通过修改数据(app.seen = false),页面中 ...

随机推荐

  1. Ubuntu Linux下的PDF阅读器推荐——Okular

    安装方法 在Ubuntu下直接使用sudo apt-get install okular即可,如果中间遇到依赖项的问题,可以通过运行sudo apt --fix-broken install来自动修复 ...

  2. SV 数据类型-3

    联合数组 在内存中分配的空间可以是不连续的 联合数组方法 数组的方法 数组使用推荐 结构体 枚举类型 字符串变量类型String 操作符

  3. Verilog Review

    Agenda 目的 Verilog概述 Verilog建模 模块 模块组成 书写建议 时延 Verilog基本语法 标识符 可读性 注释 空格 数据类型 操作数 运算符 条件语句 循环语句 函数 Ve ...

  4. 16-集电极开路门(OC门)

    集电极开路门(OC门) OC门 两个与非门,要实现非,一般来讲再与一下就可以. 能不能将输出端并在一起?普通的门电路永远不可能输出端并在一起,连在一起的. TTL与非门输出端连在一起 集电极断开之后连 ...

  5. 【TouchGFX 】使用 CubeMX 创建 TouchGFX 工程时 LCD 显示为雪花屏

    经几个晚上折腾,修改大量的LTDC时钟.时序,FMC时序等,结果还是一样,耐心与好使的工程仔细对比,发现是时钟源配置问题,真是冤,聊以此以示纪念 实质上是没有分清有源和无源晶振 无源晶振又被叫做 谐振 ...

  6. 【C++】为什么含有纯虚函数的类无法定义对象

    纯虚函数的地址为空,无法分配内存,纯虚成员函数对类是没有意义的,失去了普通类的数据和方法绑定于同一对象中的意义,因此无法构造对象,只能由其派生类继承这些成员函数并实现,才能构造派生类对象. 纯虚成员函 ...

  7. [转帖]如何使用coredump

    一.coredump 当用户态进程出现异常后,在该进程的执行目录下生成对应的coredump文件,如果我们想将coredump生成的位置做改变,就需要如下设置. echo "/home/co ...

  8. [转帖]TiDB的使用限制

    https://docs.pingcap.com/zh/tidb/stable/tidb-limitations 本文会将详细描述 TiDB 中常见的使用限制,包括:标识符长度,最大支持的数据库.表. ...

  9. [转帖]TiDB 5.1 Write Stalls 应急文档

    https://tidb.net/blog/ac7174dd#4.%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E5%87%BA%E7%8E%B0%E4%BA%86%20w ...

  10. [转帖]dd 自动压测与结果解析脚本

    测试串行.并发.读.写 4类操作,每类操作又可以指定各种bs及count值,循环压测.每种场景一般执行3次,取平均值. 一. 串行写 #!/bin/sh bs_list=(256k 1024k 10M ...