Symbol
Symbol是es6新引入的一种数据类型,表示一个独一无二的值,Symbol 值通过Symbol函数生成。当创建对象时,可以使用symbol类型作为属性。
symbol的属性是独一无二的,可以保证不会与其他属性名产生冲突。
var dabao = Symbol()
此时dabao就是独一无二的,当然,Symbol函数可以接受一个字符串作为函数,表示对Symbol实例的描述;
var dabao = Symbol('dabao');
console.log(dabao) //symbol(dabao)
其实即使不加参数使用Symbol()生成的数据都不是相等的,加上参数是为了便于区分。
console.log(Symbol() == Symbol())
console.log(Symbol() === Symbol())
Symbol()产生的值不能做运算。
var dabao = Symbol('abc')
console.log('zheshi'+dabao)
Symbol却可以调用toString转换成字符串
var dabao = Symbol('abc')
console.log(typeof dabao)
console.log(typeof dabao.toString())
Symbol也可以转化成boolean值,但是不能转化为数值。
var dabao = Symbol('abc')
console.log(Boolean(dabao))
Symbol可以作为属性名使用
var dabao = Symbol()
var a = {}
a[dabao] = 'aaa'
console.log(a[dabao])
注意这里dabao不是字符串,所以不能用.运算的。
var dabao = {
ly : 'red',
jj : 'pink'
}
function (color){
switch(color){
case dabao.ly:
return dabao.ly
case dabao.jj:
return dabao.jj
default:
return 'hh'
}
}
我们可以将代码换成
var dabao = {
Symbol('ly') : 'red',
Symbol('jj'): 'pink'
}
属性名的遍历
1.使用for in
var dabao = Symbol()
var xiaobao = Symbol()
var cxh = {}
cxh[dabao] = 'yy'
cxh[xiaobao] = 'jj'
for(var i in cxh){
console.log(i)
}
所以for in 是拿不到symbol的
2.使用for of
var dabao = Symbol()
var xiaobao = Symbol()
var cxh = []
cxh[dabao] = 'yy'
cxh[xiaobao] = 'jj'
for(var i of cxh){
console.log(i)
}
所以for of 是拿不到symbol的
3.至于其他的Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()等方法都拿不到。
4.Object.getOwnPropertySymbols(),方法可以拿到一个数组,数组的内容是当前对象所有做属性的Symbol值
var dabao = Symbol()
var xiaobao = Symbol()
var cxh = []
cxh[dabao] = 'yy'
cxh[xiaobao] = 'jj'
cxh.nihao = 'nihao'
console.log(Object.getOwnPropertySymbols(cxh))
另外,Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
var dabao = Symbol()
var xiaobao = Symbol()
var cxh = []
cxh[dabao] = 'yy'
cxh[xiaobao] = 'jj'
cxh.nihao = 'nihao'
console.log(Reflect.ownKeys(cxh))
5.symbol.for
如果,我们想重新使用同一个Symbol,symbol.for就可以
var s1 = Symbol.for('dabao');
var s2 = Symbol.for('dabao');
console.log(s1)
console.log(s2 == s1)
当调用symbol.for时,它会检查key是否存在,如果不存在才会新建一个symbol。
6.symbol.keyFor
返回一个已登记的 Symbol 类型值的key。
var dabao = Symbol('dabao')
console.log(Symbol.keyFor(dabao))
var dabao = Symbol.for('dabao')
console.log(Symbol.keyFor(dabao))
在调用一个类的时候如何才能始终返回同一个实例呢
其实思路很简单,将创建的实例保存到全局变量中,只需要创建实例的时候,我们做一个判断,如果全局变量里面有这个实例,就直接导出,如果没有,就创建一个并保存到全局变量中。
function Dabao() {
this.name= 'yy';
}
if (!global._dabao) {
global._dabao= new Dabao();
}
module.exports = global._dabao;
为了防止对global._dabao的操作所以我们使用一下代码
var dabao = Symbol('dabao')
function Dabao() {
this.name= 'yy';
}
if (!global.dabao ) {
global.dabao .= new Dabao();
}
module.exports = global.dabao ;
只有使用Symbol.for(dabao)才可以改写 global.dabao
global[Symbol.for('dabao')] = ''
在Symbol里还有很多方法,在这里就不一一陈述了,不过作者还是要讲一下Symbol.iterator ,关于Symbol.iterator作者要和Iterator一起说。
为什么要说这个方法呢。主要是为了下一篇作者要写 Typescript中的Interface。作者觉得,在ES6中Symbol的这些方法的使用和interface是一样的职责。
Iterator(遍历器)
在es6中,提供了for...of..循环,Iterator主要提供接口供其消费。Iterator接口其实就是提供一种统一的访问机制,这种访问机制就是for...of,当使用for..of时,该循环就会自动寻找Iterator接口。只要这种数据结构部署了Iterator,具体说就是只要这种数据结构有Symbol.iterator这个属性那么就可以遍历了。
默认的含有Symbol.iterator属性的数据结构包含:
Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象
Iterator 的遍历过程是这样的。
创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成
第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
不断调用指针对象的next方法,直到它指向数据结构的结束位置。
假如有一个数组,我们可以使用Symbol.iterator这样遍历:
var dabao = [1,2,3]
//因为数组本身就有symbol.iterator属性
//调用Symbol.iterator这个方法 返回该数组默认的 遍历器
var sym = dabao[Symbol.iterator]()
console.log(sym.next())
console.log(sym.next())
console.log(sym.next())
console.log(sym.next())
假如是一个对象呢?
var dabao = {
name : 'yy'
}
var sym = dabao[Symbol.iterator]()
console.log(sym)
console.log(sym.next())
console.log(sym.next())
一个对象如果要具备可被for...of循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法
class Dabao {
constructor(start,ends){
this.value = start
this.ends = ends
}
[Symbol.iterator] (){
return this;
}
next () {
var value = this.value;
if (value < this.ends) {
var obj = {done: false, value: value}
this.value++;
return obj;
}
return {done: true, value: undefined};
}
}
var dabao = new Dabao(0,4);
for(var value of dabao){
console.log(value)
}
对于类似数组的对象(存在数值键名和length属性),部署 Iterator 接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的 Iterator 接口。
var dabao = {
0 : 'nihao',
1 : 'hollow',
2 : 'miss',
length : 3,
[Symbol.iterator] : [][Symbol.iterator]
}
for(var value of dabao){
console.log(value);
}
Iterator与Generator 函数
Generator 函数是两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。
function* dabao() {
yield 'hello';
yield 'world';
return 'ending';
}
console.log( dabao() )
console.log( dabao().next() )
执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
上面代码一共调用了4次next方法。
第一次调用,Generator 函数开始执行,直到遇到第一个yield表达式为止。next方法返回一个对象,它的value属性就是当前yield表达式的值hello,done属性的值false,表示遍历还没有结束。
第二次调用,Generator 函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。next方法返回的对象的value属性就是当前yield表达式的值world,done属性的值false,表示遍历还没有结束。
第三次调用,Generator 函数从上次yield表达式停下的地方,一直执行到return语句。next方法返回的对象的value属性,就是紧跟在return语句后面的表达式的值。
第四次调用,此时 Generator 函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true。以后再调用next方法,返回的都是这个值。
为了让大家看的更明显。
function* dabao() {
console.log(1)
yield 'hello';
console.log(2)
yield 'world';
console.log(3)
return 'ending';
}
var a = dabao()
console.log(a)
console.log( a.next() )
console.log( a.next() )
console.log( a.next() )
console.log( a.next() )
结果
是不是觉得遍历器使其就是一种interface,只要部署该接口的数据类型都可以使用for...of访问。
至此,es6就不做另外详述了,还有其他一些关键的比如:Promise ,async,decorator,小编也写过一些文章,如果想看一下可以访问以下链接:
Promise async 、decorator
还有作者其他文章,es6暂时不多介绍了。写得不好,请多指教