ES6重点-1

2020-02-19 23:01:4810/1/2021, 3:34:43 AM

字符串新增方法

  • padStart

    用于字符串长度补全,如果某个字符串长度不够指定长度会在头部或尾部补全

    console.log('xxx'.padStart(4, 'ab'));
    console.log('x'.padStart(4, 'ab')); //补全位数,有需要会重复或截取
    console.log('x'.padStart(4)); // 不传第二个参数默认使用空格补全
    console.log('xxx'.padStart(2)); // 补全后的长度小于源字符串长度则不做任何改变
    
    // abax
    // axxx
    //    x
    // xxx
    
  • padEnd

    padStart效果相反,从尾部开始补全

    console.log('x'.padEnd(5, 'abc'));
    console.log('x'.padEnd(4));
    console.log('xxx'.padEnd(2));
    console.log('xxx'.padEnd(4, 'ab'));
    
    // xabca
    // x   
    // xxx
    // xxxa
    

对象新增扩展

  • 链判断运算符

    在ES5中,取对象属性时,往往需要判断以下该对象是否存在。如下

    const name = (store 
        && store.state 
        && store.state.user 
        && store.state.user.name) || "tom"
    

    这种层层判断过于麻烦,因此ES2020引入链判断运算符?.

    const name = store?.state?.user?.name
    

    如果左侧的对象为nullundefined则直接返回undefined,不再往下运算

  • null判断运算符

    独去对象属性时,如果某个属性的值时nullundefined,有时需要为它们指定默认值。常见做法是通过||运算符指定默认值

    const name = user.name || "tom"
    const age = user.age || 20
    

    原意是属性值为nullundefined时默认值就生效,但当user.name为空串或user.age为0时默认值也会生效

    为此ES2020引入新的null判断运算符??

    const name = user.name ?? "tom"
    const age = user.age ?? 20
    

对象新增方法

  • Object.is

    用来替代 =====

    == 会进行自动类型转换,=== 在比较+0和-0时返回trueNaN不等于自身

  • Object.assign

    用于对象合并

    • 只拷贝源对象的自身、可枚举属性(含Symbol)
    • 浅拷贝
    • 同名属性会被覆盖
    • 除首参数外(nullundefined会报错),非对象会被转换为对象
  • Object.keys

    返回对象自身的可遍历的属性的键名数组

  • Object.fromEntries/Object.entries

    Object.fromEntries将一个键值对数组转换为一个对象,适合将Map转换为Object

    Object.entries逆操作,用于将Object转换为键值对数组

Array扩展

  • Array.of

    弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异

    Array() //[]
    Array(3) //[ , , ]
    Array(3, 4, 5) //[3, 4, 5]
    
    Array.of() // []
    Array.of(3) //[3]
    Array.of(3, 4, 5) //[3, 4, 5]
    
  • Array.prototype.copyWithin()

    在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员)

    Array.prototype.copyWithin(target, start = 0, end = this.length)
    
    [1, 2, 3, 4, 5].copyWithin(0, 3)
    // [4, 5, 3, 4, 5]
    [1, 2, 3, 4, 5].copyWithin(0, 3, 4)
    // [4, 2, 3, 4, 5]
    
  • Array.prototype.flat() && Array.prototype.flatMap()

    flat()用于将数据降维,参数为降低的维数(默认为1),如果不管有多少层维,都要转为一维数组,可使用Infinity关键字作为参数

    如果原数组有空位flat()会跳过

    [1, 2, [1, 2]].flat()
    // [1, 2, 1, 2]
    
    [1, 2, [1, 2], [1, [2]]].flat()
    // [1, 2, 1, 2, 1, [2]]
    
    [1, 2, [1, 2], [1, [2]]].flat(2)
    // [1, 2, 1, 2, 1, 2]
    
    [1, 2, [1, 2], [1, [2]]].flat(Infinity)
    // [1, 2, 1, 2, 1, 2]
    

    flatMap()相当于Array.prorotype.Map + Array.prorotype.flat

    [1, 2, 3].flatMap(x => [x, x * 2])
    // [1, 2, 2, 4, 3, 6]
    [1, 2, 3].flatMap(x => x * 2)
    // [2, 4, 6]
    

iterator

WHAT

遍历器(iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署了iterator接口,就可以完成遍历操作

WHY

JavaScript原有的表示集合的数据结构主要是数组(Array)和对象(Object),ES6又添加了MapSet。这样就有了四种数据集合,用户可以组合使用它们,定义自己的数据结构,比如数组的成员是MapMap的成员是对象。这样需要一种统一的接口机制来处理不同的数据结构

主要作用

  • 为各种数据结构提供一个统一的、简便的访问接口

  • 使得数据结构的成员能够按某种次序排列

  • for...of所使用

    适合遍历Array,既有forEach的简洁又有forbreakreturncontinue

HOW

iterator的遍历过程

  1. 创建一个指针对象,指向当前的数据结构的起始位置。也就是说遍历器对象本质上就是一个指针对象
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
  3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
  4. 不断调用指针对象的next方法,直到它指向数据结构的结束位置

每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含valuedone两个属性的对象,其中value属性是当前成员的值,done属性是一个布尔值,表示是否遍历结束

ES6规定,默认的iterator接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是可遍历的(iterable

const obj = {
    data: ['hello', 'world'],
    [Symbol.iterator](): {
        const self = this
        let index = 0
        return {
            next() {
                if (index < self.data.length) {
                    return {
                        value: self.data[index++]
                        done: false
                    }
                }
                return {
                    value: undefined,
                    done: true
                }
            }
        }
    }
}

原生具备iterator接口的数据结构:Map、Array、Set、String、TypedArray、arguments、NodeList对象

let VS const

在let和const之间,建议优先使用const,尤其是在全局环境。const优于let的几个原因:

  • const可以提醒阅读程序的人,这个变量不应该改变
  • const比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式计算
  • JavaScript编译器会对const进行优化
  • 长远来看,JavaScript可能会有多线程的实现,这时let表示的变量只应出现在单线程运行的代码中,不是多线程共享的,这样有利于线程安全
// bad
var a = 1, b = 2, c = 3
// good
const a = 1;
const b = 2;
const c = 3;
// best
const [a, b, c] = [1, 2, 3]

generator

ES6提供的一种异步编程解决方案

形式上,generator函数是一个状态机,封装了多个内部状态。执行generator函数会返回一个遍历器对象

语法上,generator函数是一个普通函数。function关键字与函数名之间有一个*;函数体内部使用yield表达式定义不同的内部状态

与普通函数不同,generator函数被调用后并不执行,返回的是一个指向内部状态的指针对象,也就是遍历器对象。下一步,必须调用遍历器对象的next方法使得指针移向下一个状态。也就是说每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)

function* gen() {
  const str1 = yield "hello"
  // str1 = 222
  const str2 = yield "world"
  // str2 = 333
  return str2
}

const iter = gen()
console.log(iter.next())
console.log(iter.next(222))
console.log(iter.next(333))

第一次调用,generator函数开始执行,直到遇到第一个yield表达式为止。next方法返回一个对象,它的value值就是当前yield表达式的值,done的值为false

第二次调用,generator从上次yield表达式停下来的地方一直执行到下一个yield表达式 👆 ……

第三次调用,generator函数从上次yield表达式停下来的地方一直执行到return语句,next返回的value值就是return后面表达式的值,done为true(如果是yield则为false

yield表达式本身没有返回值(或者说总是返回undefined)。next方法可以带一个参数,该参数会被当作上一个yield表达式的返回值