ECMAScript new features 3

Article description: This article is the notes and experience of the front-end training camp of Regao. If there is something wrong, I hope you can point out and teach, thank you!

One, Symbol

  • Symbol data type represents a unique value, which can be used to avoid the problem of object attribute name duplication, and can also use this feature to simulate the private members of the object

console.log(Symbol() === Symbol()) //false
//================================================
const obj = {}
obj[Symbol()] = '123'
obj[Symbol()] = '456'
console.log(obj) //{[Symbol()]:'123',[Symbol()]:'456}//作为对象唯一属性

//============================================================
const obj = {
    [Symbol()]:123
}
console.log(obj)//{[Symbol]:'123'}
//===================================================
const name = Symbol()
const person = {
    [name]:'zce',
    say(){
        console.log(this[name])
    }
}

person[Symbol()]// 无法访问 外部因为无法创建完全相同的Symbol,所以就无法直接访问到这个成员,这样该对象便实现了私有成员
person.say() //zce 内部可以拿到Symbol属性值的成员

Symbol supplement

// Symbol 补充

console.log(
    //Symbol() === Symbol() false
    // Symbol('foo') === Symbol('foo')  false
)

const s1 = Symbol.for('foo') //该方法提供了字符串和Symbol一一对应的关系, 方法里维护了字符串和Symbol之间的对应关系
const s2 = Symbol.for('foo')
console.log(s1 === s2)// true

console.log(
    Symbol.for(true) === Symbol.for('true') //true 如果传入的不是字符串,方法里会转为字符串
)
// Symbol 提供了很多内置的Symbol常量,用来作为内部方法的标识,这些标识符可以让自定义对象实现一些js当中内置的接口
console.log(Symbol.iterator) 
console.log(Symbol.hasInstance)

const obj = {
    [Symbol.toStringTag]:'XObject' 
}
console.log(obj.toString())// [object Object]  把这样的字符串叫做对象的字符串标签,若想要对象的字符串标签

const obj = {
    [Symbol()]:'symbol value',
    foo:'normal value'
}

for(var key in obj){
    console.log(key)
}
console.log(Object.keys(obj))//['foo] 获取不到Symbol这样的一个属性名
console.log(JSON.stringify(obj)) //{"foo":"normal value"}  序列化obj为json字符串,Symbol属性也会被忽略掉

console.log(Object.getOwnPropertySymbols(obj))// 这个方法类似于Object.keys方法,Object.keys方法只能够获取对象中字符串属性名,而这个方法获取到的全是Symbol属性名

For more details, please visit: https://developer.mozilla.org/zh-CN/docs/Glossary/Symbol

Two, for...of loop

  •  The for loop traverses ordinary arrays, the for...in loop is suitable for traversing key-value pairs, and foreach is suitable for traversing array objects. The new for...of loop can be used as a unified way to traverse all data structures.
const arr = [100,200,300,400]

for(const item of arr){
    console.log(item) //100 200 300 400
}

for(const item of arr){// for of 可以用break关键词随时终结循环
    console.log(item)
    if(item > 100){
        break
    }
}

arr.forEach() //forEach无法终止遍历
arr.some() //返回true终止遍历
arr.every()// 返回false终止遍历
  • Pseudo-array objects can also be traversed by for..of, such as arguments object, list of element nodes during dom operation

const s = new Set(['foo','bar'])

for(const item of s){// 可用for of循环set
    console.log(item)//foo bar
}
  • Traverse the Map object
const m = new Map()
m.set('foo','123')
m.set('bar','456')
for(const item of m){
    console.log(item)// ['foo','123]  ['bar','456'] 键和值放在数组中
}

for(const [key,value] of m){
    console.log(key,value)// foo 123  bar 456
}
  • However, ordinary objects cannot be recycled, the reason is as follows
const obj = {foo:123,bar:456}

for(const item of obj){// obj不可被迭代
    console.log(item)// obj is not iterable
}

Iterator

There are more and more structured array types in ES. Set and Map are now added. In order to provide a unified traversal method for a variety of data structures, ES2015 provides the Iterable interface, which is understood as a specification standard, and achieves uniformity. interface. Implementing the Iterable interface can be traversed by for...of. [],Set,Map There is such a Symbol(Symbol.iterator) method among the three objects that can be traversed by for...of, and the iterator method must be mounted on the objects that can be traversed by loop

 

In this iterator, a data pointer should be maintained internally. Each time next is called, the pointer will move back one bit. The function of the done attribute is to indicate that all the internal attributes have been traversed.

To be able to be for...of loops, you must implement the iterator interface, and an iterator method must be mounted internally. This method must return an object with the next() method. Calling this method continuously can achieve all the internal data. Traverse.

const Set = new Set(['foo','bar','baz'])

const iterator = Set[Symbol.iterator]()// 获取Set里面的迭代器

console.log(iterator.next()) // {value:'foo',done:false}
console.log(iterator.next()) // {value:'bar',done:false}
console.log(iterator.next()) //{value:'baz',done:false}
console.log(iterator.next())//{value:undefined,done:true}
console.log(iterator.next())//{value:undefined,done:true}

Three, realize the above-mentioned iterable interface

  • If the object implements the Iterable interface, you can use the for...of loop

const obj = {//外层为自定义对象,实现了可迭代接口,称为Iterable
    [Symbol.iterator]:function(){//内部必须有一个用于返回迭代器的iterator方法
        return{// iterator 方法返回的这个对象实现了迭代器接口,这个接口约定了必须要有一个用于迭代的next方法
            next:function (){
                return{// next方法当中返回的对象,这个对象实现的是迭代结果接口,称为IterationResult,这个对象内部必须要有value属性,表示当前被迭代的数据,它的值可以使任意类型,
//除此之外还必须要有个done的布尔值用来表示 迭代是否结束
                    value:'zce',
                    done:true
                }
            }
        }
    }
}

for(const item of obj){
    console.log('循环体') //未报错
}
  • Ordinary objects can be looped out with for...of after adding an iterative interface and putting in data

const obj = {
    store:['foo','bar','baz'],
    [Symbol.iterator]:function(){
        let index = 0
        const self = this
        return{
            next:function (){
                const result = {
                    value:self.store[index],
                    done:index >= self.store.length
                }
                index++
                return result
            }
        }
    }
}

for(const item of obj){
    console.log('循环体',item) //循环体  foo    循环体 bar  循环体  baz
}

Four, iterator design pattern

  • The core of the iterator pattern is to provide a unified traversal interface to the outside, so that the outside does not need to care about the internal structure.

// 场景:你我协同开发一个任务清单应用

// 我的代码 =================================
const todos ={
    life:['吃饭','睡觉','打豆豆'],
    learn:['语文','数学','外语'],
    work:['喝茶'],

    each:function(callback){ // 对外提供了统一遍历的接口
        const all = [].concat(this.life,this.learn,this.work)
        for(const item of all){
            callback(item)
        }
    },
/*迭代器模式核心就是对外提供统一遍历接口,让外部不用再去关心内部的结构是怎样的,只不过上面的each方法只适用于当前对象结构.
ES2015中的迭代器,它是语言层面实现的迭代器模式,适用于任何数据结构,只需要通过代码实现iterator方法实现它的迭代逻辑就可以了 */
    [Symbol.iterator]:function(){
        const all = [...this.life,...this.learn,...this.work]
        let index = 0
        return{
            next:function(){
                return{
                    value:all[index],
                    done:index++ >= all.length
                }
            }
        }
    }
}

// 你的代码====================================

// for(const item of todos.life){
//     console.log(item)
// }

// for(const item of todos.learn){
//     console.log(item)
// }
// for(const item of todos.work){
//     console.log(item)
// }
//当前对象的统一对外遍历方法
todos.each(function(item){
    console.log(item)
})

console.log('---------------------')

for(const item of todos){
    console.log(item)
}

 Five, ES2015 generator 

  • The ES2015 generator is introduced to avoid too deep nesting of callbacks in asynchronous programming, and to provide better asynchronous programming solutions

Generator function

//Generator 函数
function * foo(){
    console.log('zce')
    return 100
}

const result = foo()
console.log(result)// Object [Generator] {} 打印了一个生成器对象
console.log(result.next()) // zce {value:100,done:true} 该返回值和迭代器的返回值一样,放到value当中
  •  The yield statement is very similar to return, but does not end the execution of the method
  • Calling the next method of this object will start the execution of the function body of this function. During the execution, it will be paused when it encounters yield. The value after yield will be returned as the structure of next. If you continue to call, it will continue at the paused position. Execute, and so on, finally done becomes true

function *  foo(){
    console.log('1111')
    yield 100 //yield 语句跟return非常类似,但是不会结束掉方法的执行
    console.log('2222')
    yield 200
    console.log('3333')
    yield 300
}

const generator = foo()
//调用这个对象的next方法才会让这个函数的函数体开始执行,执行过程中遇到yield就会被暂停下来,yield后面的值会作为next的结构返回,继续调用的话,就会暂停的位置继续执行,如此下去,最后done变为true
console.log(generator.next()) // 1111 {value:100,done:false}
console.log(generator.next()) // 1111 {value:100,done:false} 222 {value:200,done:false} 
console.log(generator.next()) // 1111 {value:100,done:false} 222 {value:200,done:false} 333 {value:300,done:false} 
console.log(generator.next()) // 1111 {value:100,done:false} 222 {value:200,done:false} 333 {value:300,done:false} {value:undefined,done:true}

Generator app

The following are two cases:

/案例1:发号器

function * createIdMaker(){
    let id = 1
    while(true){
        yield id++
    }
}

const idMaker = createIdMaker()

console.log(idMaker.next().value)//1
console.log(idMaker.next().value)//2
console.log(idMaker.next().value)//3
console.log(idMaker.next().value)//4

// 案例2 使用Generator 函数实现 iterator 方法

const todos = {
    life:['吃饭','睡觉','打豆豆'],
    learn:['语文','数学','外语'],
    life:['喝茶'],
    [Symbol.iterator]:function * (){
        const all = [...this.life,...this.learn,...this.work]
        // let index = 0 //不再需要手动返回一个迭代器对象,直接在iterator方法内部遍历所有的成员,通过yield去返回每一个被遍历到的对象
        // return {
        //     next:function(){
        //         return{
        //             value:all[index],
        //             done:index ++ >= all.length
        //         }
        //     }
        // }
        for(const item of all){
            yield item
        }
    }
}

for(const item of todos){
    console.log(item)
}

Six, ES2016

//ECMAScript 2016  相对于2015只是一个小版本,仅包含两个小功能

//Array.prototype.includes -------------------------------
const arr =['foo',1,NaN,false]

console.log(arr.indexOf('foo'))//0 找到元素对应的下标
console.log(arr.indexOf('bar'))//没有找到指定元素则返回-1 
console.log(arr.indexOf(NaN))//这种方式判断会存在一个问题,不能够查找数组当中的NaN

console.log(arr.includes('foo')) //这种能直接返回布尔值,存在或者不存在

// 指数运算符 ---------------------------------------

console.log(Math.pow(2,10)) //1024 指数运算借助于Math.pow,2是底数,10是指数

console.log(2 ** 10) //1024

Seven, ES2017

console.log(Object.values(obj)) //['value1','value2'] 将对象的所有值放到数组里
console.log(Object.entries(obj)) // [['foo','value1'],['bar','value2']]  以数组的形式返回对象当中的所有的键值对

for(const [key,value] of Object.entries(obj)){
    console.log(key,value) //foo value1 //bar value2
}

console.log(new Map(Object.entries(obj))) //用entries方法转化为Map对象   Map{ 'foo' => 'value1','bar' => 'value2' }
const p1 = {
    firstName:'Lei',
    LastName:'Wang',
    get fullName(){
        return this.firstName + '' +this.LastName
    }
}

console.log(p1.fullName)

const p2 = Object.assign({},p1)
p2.firstName = 'zce'
console.log(p2.fullName) // Lei Wang  Object.assign 复制时只是把fullName当作一个普通的属性去复制,才会出现这种情况

const descriptors = Object.getOwnPropertyDescriptors(p1)
// console.log(descriptors)
const p2 = Object.defineProperties({},descriptors)
p2.firstName = 'zce'
console.log(p2.fullName) // zce Wang
const books ={
    html:5,
    css:6,
    javascript:128
}

for(const [name,count] of Object.entries(books)){
    console.log(name,count) // name 5 //css 16 //javaScript 128
}

for(const [name,count] of Object.entries(books)){
    console.log(`${name.pad}`) // html------------|005 //css-------------|016 //javascript------|128
}
  • Add a trailing comma in the function parameters

function foo(
    bar,
    baz,
){

}

 

Guess you like

Origin blog.csdn.net/weixin_41962912/article/details/109763774