ES6-ES11新特性(迭代器,生成器)-最新版(二)

目录

· ES6-Symbol属性

· ES6-迭代器

· ES6-生成器


· ES6-Symbol属性

        ES6中引入了一种新的原始数据类型Symbol,表示独一无二的值,我们可以将其理解为一个独一无二的字符串,它是JavaScript的第七种数据类型(Number,String,Boolean,Undefined,Null,Object,Symbol),是一种类似于字符串的数据类型。Symbol的特点如下:

  1. Symbol的值是唯一的,是用来解决命名冲突的问题。
  2. Symbol值不能与其他数据进行运算。
  3. Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。
// 1)创建Symbol类型的值
let s1 = Symbol('为Symbol类型添加的标识')  //一种独一无二的值
let s2 = Symbol('为Symbol类型添加的标识')  //一种独一无二的值

// 标识只是为了区分Symbol类型
// 具有相同的标识的Symbol类型的值仍旧不一样
console.log(s1 === s2 ) //false 
console.log(s1,typeof s1) // Symbol(为Symbol类型添加的标识) 'symbol'

// 2) 使用Symbol.for()创建Symbol类型的值
let s3 = Symbol.for('1024')
let s4 = Symbol.for('1024')
//使用Symbol.for()创建的类型,若标识值一样,则Symbol值也一样
console.log(s3 === s4 ) //true

// 3)使用Symbol属性为对象创建独一无二的属性名

let onlyOne = Symbol("此Symbol类型的标识")

obj = {
    //可以将Symbol类型理解为独一无二的字符串,即onlyOne中可以理解为存储的独一无二的字符串
    //这里注意使用Symbol类型的值作为属性时,因为变量中存储的是值,需要用[]将变量包裹
    [onlyOne]:1024,  
    fun:function(){
        console.log('我是对象中的方法!')
    }
}


// 4)使用for...in遍历对象键名
for (let key in obj)
{
    // Symbol类型的定义属性名不能用for...in遍历
    console.log(key) //fun 
}

//使用Reflect.ownKeys获取对象所有属性名
//Reflect.ownKeys将对象以数组类型返回,使用for...of遍历可迭代对象的值
for (let key of Reflect.ownKeys(obj))
{
    console.log(key) //fun Symbol(此Symbol类型的标识)
}

· ES6-迭代器

        迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署有iterator接口,就可以使用for...of完成遍历操作。原生具备iterator接口的数据结构如下:

  1. Array
  2. Arguments
  3. Map
  4. Set
  5. String
  6. TypedArray
  7. NodeList

       for...of遍历的是当前数据结构中的键值,而for...in遍历的是当前数据结构中的键名,包括设置原型中的方法,所有for...in一般是用来遍历对象的属性名的。

let arr=[1024,200,404]
for(let val of arr)
{
    //for...of遍历的当前数据结构中的键值
    console.log(val)  //1024 200 404
}

我们输出以上代码段定义的arr数据结构如下图,发现包含有Symbol类型的一个迭代器方法,其中标识为Symbol.iterator的预定义值,内部声明为Symbol.iterator = Symobl(Symbol.iterato),该方法调用返回一个迭代器对象,其中包含有next()方法,不断调用next()方法就可以遍历此数据结构。因此,for...of其实就是调用数据结构的iterator对象的next()方法去进行数据遍历的。

ES6-ES11新特性(迭代器,生成器)-最新版(二)_第1张图片

let arr=[1024,200,404]

//for...of其实就是调用数据结构的iterator对象的next()方法
let iterator = arr[Symbol.iterator]() //返回迭代器对象
//使用next()方法遍历数据结构
//next方法返回当前值以及遍历完成状态
console.log(iterator.next()) // {value: 1024, done: false}
console.log(iterator.next()) // {value: 200, done: false}
console.log(iterator.next()) // {value: 404, done: false}
console.log(iterator.next()) // {value: undefined, done: true}

除了使用for...of对原生具有迭代器接口的数据类型进行遍历,有了以上学习,我们还可以自定义迭代器:

  1. 创建一个指针对象,指向当前数据结构的起始位置。
  2. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员。
  3. 接下来不断调用next方法,指针一直后移,直到指向最后一个成员。
  4. 每次调用next方法会返回一个包含value和done属性的对象。

 以下代码段是使用自定义迭代器对obj对象中的lesson属性值进行遍历。

let obj = {
    name:'Web',
    lessons: [
        'Html5',
        'Css3',
        'JavaScript',
        'Ajax',
        'React',
        'Vue'
    ],
    [Symbol.iterator]:function(){

        let index = 0 //初始指针,指向遍历的索引
        let _this = this //_this指向obj对象
        return {
            next:function(){
                if(index < _this.lessons.length){
                    const result = {value:_this.lessons[index],done:false}
                    index++
                    return result
                }
                else{ //遍历完成,返回 undefined true
                    return {value:undefined,done:true}
                }
            }
        }
    }
}
//使用自定义迭代器对obj对象中的lesson属性值进行遍历
for(let lesson of obj)
{
    console.log(lesson) //Html5 Css3 JavaScript Ajax React Vue
}

· ES6-生成器

生成器其实就是一个特殊的函数,它会返回一个迭代器对象,生成器主要是为了解决异步编程(定时器操作、文件操作、网络操作:Ajax,request、数据库操作等)的问题,其中使用关键字yield进行函数代码的分割。

我们先引出这样一个例子:

function fun1(){
    setTimeout(function(){
        console.log('延迟3s')
        setTimeout(function(){
            console.log('延迟2s')
            setTimeout(function(){
                console.log('延迟1s')
            },1000)
        },2000)
    },3000)
}
fun1() //延长3s 延长2s 延迟1s

由于定时器函数是异步执行的,其中使用了时间循环模型。若想先延迟3s,再延迟2s,最后再执行延迟1s的函数,需要 如上代码的嵌套,很容易产生回调地狱的问题,即代码结构混乱,不易维护。接下来我们使用生成器函数解决此问题。

function fun1(){
    setTimeout(function(){
        console.log('延迟3s')
        iterator.next('延迟3s')
    },3000)
}
function fun2(){
    setTimeout(function(){
        console.log('延迟2s')
        iterator.next('延迟2s')

    },2000)
}
function fun3(){
    setTimeout(function(){
        console.log('延迟1s')
        iterator.next('延迟1s')

    },1000)
}
function * gen(){
    let p1 = yield fun1()  //通过next()参数传参得到的返回结果
    console.log(p1) //延迟3s
    let p2 = yield fun2()  //通过next()参数传参得到的返回结果
    console.log(p2)  //延迟2s
    let p3 = yield fun3()  //通过next()参数传参得到的返回结果
    console.log(p3)  //延迟1s
}

let iterator = gen()
iterator.next() //生成器函数返回的迭代器对象使用next()方法进行遍历执行yield后边的方法

上述输出为:延迟3s 延迟2s 延迟1s。使用生成器函数解决了回调地狱的问题,而且由上述代码段可知next()是可以传参的,参数作为上一个yield的返回结果。

既然生成器函数返回的是一个迭代器对象,那么就可以使用for...of遍历。

function * gen(){
    yield '1024'
    yield '200'
    yield '404'
}

for(let v of gen()){
    console.log(v) // 1024 200 404
}

持续更新中......

你可能感兴趣的:(es6,javascript,前端,迭代器模式)