### Symbol 数据类型
> 1.基本用法
> 2.作为属性名的 Symbol
> 3.属性名的遍历
> 4.Symbol.for(),Symbol.keyFor()
> 5.内置的 Symbol 值
> ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
1.基本用法
~~~
let s = Symbol();
typeof s
// "symbol"
~~~
注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
参数是字符串
~~~
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
~~~
参数是对象
~~~
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
~~~
Symbol 值不能与其他类型的值进行运算,会报错
~~~
let sym = Symbol('My symbol');
"your symbol is " + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string
~~~
Symbol 值可以显式转为字符串。
~~~
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
~~~
Symbol 值也可以转为布尔值,但是不能转为数值
~~~
let sym = Symbol();
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
~~~
2.作为属性名的 Symbol
~~~
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
~~~
Symbol 值作为对象属性名时,不能用点运算符
~~~
const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"
~~~
在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中
~~~
let s = Symbol();
let obj = {
[s]: function (arg) { ... }
};
obj[s](123);
~~~
3.属性名的遍历
Symbol 作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
~~~
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]
~~~
Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名
~~~
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
~~~
4.Symbol.for(),Symbol.keyFor()
我们希望重新使用同一个 Symbol 值,Symbol.for方法可以做到这一点
~~~
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
~~~
Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key
~~~
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
~~~
由于Symbol()写法没有登记机制,所以每次调用都会返回一个不同的值。
Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key
5.内置的 Symbol 值
* Symbol.hasInstance
* Symbol.isConcatSpreadable
* Symbol.species
* Symbol.match
* Symbol.replace
* Symbol.search
* Symbol.split
* Symbol.iterator
* Symbol.toPrimitive
* Symbol.toStringTag
* Symbol.unscopables
重点讲解:
Symbol.iterator
## Iterator遍历器
> Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
> 一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内
Iterator 的遍历过程是这样的。
* 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
* 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
* 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
* 不断调用指针对象的next方法,直到它指向数据结构的结束位置。
~~~
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++]} :
{done: true};
}
};
}
~~~
### 课后习题
1.下面代码运行结果是什么?
~~~
let s = Symbol(1);
let f = Symbol(1);
console.log(s===f);
~~~
~~~
let s = Symbol.for('a');
let f = Symbol.for('b');
console.log(s===f);
~~~
~~~
var sym = Symbol('k');
var obj = {
sym:1
}
console.log(obj[sym])
~~~
~~~
var sym = Symbol();
obj.sym =1;
console.log(obj[sym]);
~~~
~~~
var sym = Symbol();
obj[sym] =1;
console.log(obj[sym]);
~~~
- Less
- 课程规划
- Less概述
- 变量
- 混合
- 嵌套
- 继承
- 导入
- 函数
- 其他
- 实战
- ES6
- 课程规划
- ES6概述
- let和const命令
- 变量的解构赋值
- 字符串扩展
- 函数扩展
- 数组扩展
- Set和Map数据结构
- Symbol
- Generator 函数
- Promise对象
- Class语法
- Module 的语法
- ES7和ES8
- 实战
- VUE
- 课程规划
- vue概述
- vue实例
- 模版语法
- 计算属性和侦听器
- Class和Style的绑定
- 条件渲染
- 列表渲染
- 事件处理
- 表单输入绑定
- 组件基础
- 过渡和动画
- 自定义指令
- 过滤器
- 响应式原理
- 实战课程
- Node
- 课程规划
- 课程概述
- node入门实例
- 模块系统
- 回调函数
- 全局对象
- 常用模块介绍
- 常用模块介绍-1
- 常用模块介绍-2
- 常用模块介绍-3
- npm使用
- express的使用
- express的使用-1
- webpack基础
- 实战
- 微信小程序
- 课程规划
- 课程概述
- 基本配置和生命周期
- wxml模版
- wxss
- wxs
- 组件
- 微信API
- 自定义组件开发
- 实战小程序
- Element
- 课程规划
- 课程概述
- 特性介绍
- 组件介绍-基础组件
- 组件介绍-表单组件
- 组件介绍-数据展示组件
- 组件介绍-提示组件
- 组件介绍-导航组件
- 组件介绍-其他组件
- 综合案例