Symbol And Iterator

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())
Paste_Image.png

Symbol()产生的值不能做运算。

var dabao = Symbol('abc')
console.log('zheshi'+dabao)
Paste_Image.png

Symbol却可以调用toString转换成字符串

var dabao = Symbol('abc')
console.log(typeof dabao)
console.log(typeof dabao.toString())
Paste_Image.png

Symbol也可以转化成boolean值,但是不能转化为数值。

var dabao = Symbol('abc')
console.log(Boolean(dabao))

Paste_Image.png

Symbol可以作为属性名使用

var dabao = Symbol()
var a = {}
a[dabao] = 'aaa'
console.log(a[dabao])
Paste_Image.png

注意这里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)
}
Paste_Image.png

所以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))
Paste_Image.png

另外,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))
Paste_Image.png

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))
Paste_Image.png
var dabao = Symbol.for('dabao')
console.log(Symbol.keyFor(dabao))

Paste_Image.png

在调用一个类的时候如何才能始终返回同一个实例呢
其实思路很简单,将创建的实例保存到全局变量中,只需要创建实例的时候,我们做一个判断,如果全局变量里面有这个实例,就直接导出,如果没有,就创建一个并保存到全局变量中。

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())
Paste_Image.png

假如是一个对象呢?

var dabao = {
    name : 'yy'
}
var sym = dabao[Symbol.iterator]()
console.log(sym)
console.log(sym.next())
console.log(sym.next())
Paste_Image.png

一个对象如果要具备可被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)
}
Paste_Image.png

对于类似数组的对象(存在数值键名和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);
}
Paste_Image.png
Iterator与Generator 函数

Generator 函数是两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。

function* dabao() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
console.log( dabao() )
console.log( dabao().next() )

执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。


Paste_Image.png

上面代码一共调用了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() )

结果

Paste_Image.png

是不是觉得遍历器使其就是一种interface,只要部署该接口的数据类型都可以使用for...of访问。
至此,es6就不做另外详述了,还有其他一些关键的比如:Promise ,async,decorator,小编也写过一些文章,如果想看一下可以访问以下链接:
Promise asyncdecorator
还有作者其他文章,es6暂时不多介绍了。写得不好,请多指教

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容

  • 在此处先列下本篇文章的主要内容 简介 next方法的参数 for...of循环 Generator.prototy...
    醉生夢死阅读 1,440评论 3 8
  • 简介 基本概念 Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍...
    呼呼哥阅读 1,075评论 0 4
  • 一、let 和 constlet:变量声明, const:只读常量声明(声明的时候赋值)。 let 与 var 的...
    dadage456阅读 762评论 0 0
  • 异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本...
    呼呼哥阅读 7,309评论 5 22
  • 曾几何时 认为自己还是年轻 然而 那一抹匆匆的光阴 却早已 走过心中的每一个角落 如果 那时 镜子中的自己 不再熟...
    陈筱一儿阅读 109评论 0 0