ES6-2015

1. let and const

  • let 变量必须先声明后使用(没有变量提升或者没有与预解析)
  • let 不允许重复声明
  • let 有块级作用域, var 没有(var有全局作用域和函数作用域)
  • const 声明的变量不允许修改,但是如果是对象的话,对象的属性是可以修改的

2. Template Literals

  • 模板字符串: 用反引号包裹, 可以换行, 可以嵌套变量, 可以嵌套表达式

    ;`In JavaScript '\n' is a line-feed.`
    
  • 变量

let name = 'Bob',
  time = 'today'
console(`Hello ${name}, how are you ${time}?`)
// Hello Bob, how are you today?

3. Destructuring

  • 数组解构, 对象解构, 字符串解构, 函数参数解构, 默认值, 解构赋值, 剩余方式运算解构

  • 数组解构

let [a, b, c] = [1, 2, 3]
  • 忽略解构
let [, , a] = [1, 2, 3]
console.log(a) // 3
  • 部分解构
let [a] = [1, 2, 3]
console.log(a) // 1
  • 嵌套解构
let [a, [b, c]] = [1, [2, 3]]
console.log(a, b, c) // 1 2 3
  • 剩余方式运算解构

    let [a, ...b] = [1, 2, 3]
    console.log(a, b) // 1 [2, 3]
    
  • 对象解构

    let { foo, bar } = { foo: 'aaa', bar: 'bbb' }
    
  • 字符串解构

    const [a, b, c, d, e] = 'hello'
    
  • 函数参数解构

    function add([x, y]) {
      return x + y
    }
    add([1, 2]) // 3
    
  • 默认值

    let [foo = true] = []
    foo // true
    
  • 解构赋值

    let x
    {x} = {x: 1}
    x // 1
    

4. Default Parameters

  • 默认参数: 用于函数的参数, 如果没有传递参数, 则使用默认参数

    function log(x, y = 'World') {
      console.log(x, y)
    }
    log('Hello') // Hello World
    log('Hello', 'China') // Hello China
    log('Hello', '') // Hello
    

5. Rest and Spread

  • 剩余参数: 用于函数的参数, 用于获取函数的多余参数, 用于数组的解构赋值

    function add(...values) {
      let sum = 0
      for (var val of values) {
        sum += val
      }
      return sum
    }
    add(2, 5, 3) // 10
    

6. Arrow Functions

  • 箭头函数: 用于函数的简写, 用于数组的遍历

    var f = (v) => v
    // 等同于
    var f = function (v) {
      return v
    }
    

7. Enhanced Object Literals

  • 增强对象字面量: 用于对象的简写, 用于对象的属性名的简写

    function getPoint() {
      var x = 1
      var y = 10
      return { x: x, y: y }
    }
    // 等同于
    function getPoint() {
      var x = 1
      var y = 10
      return { x, y }
    }
    
  • 简洁表示法

    var foo = 'bar'
    var baz = { foo }
    baz // {foo: 'bar'}
    

8. Classes (类)

  • 类的声明

    class Point {
      constructor(x, y) {
        this.x = x
        this.y = y
      }
      toString() {
        return '(' + this.x + ', ' + this.y + ')'
      }
    }
    
    var point = new Point(2, 3)
    point.toString() // (2, 3)
    
  • 类的继承

    class ColorPoint extends Point {
      constructor(x, y, color) {
        super(x, y) // 调用父类的constructor(x, y)
        this.color = color
      }
      toString() {
        return this.color + ' ' + super.toString() // 调用父类的toString()
      }
    }
    
  • 类的静态方法

    class Foo {
      static classMethod() {
        return 'hello'
      }
    }
    Foo.classMethod() // 'hello'
    
  • 类的静态属性

    class Foo {}
    Foo.prop = 1
    Foo.prop // 1
    
  • 类的实例属性

    class MyClass {
      myProp = 42
      constructor() {
        console.log(this.myProp) // 42
      }
    }
    
  • 类的私有方法

    class Widget {
      // 公有方法
      foo(baz) {
        this._bar(baz)
      }
      // 私有方法
      _bar(baz) {
        return (this.snaf = baz)
      }
    }
    
  • 私有属性

    class Point {
      #x
      constructor(x = 0) {
        #x = +x
      }
      get x() {
        return #x
      }
      set x(value) {
        #x = +value
      }
    }
    
  • 私有属性和私有方法

    class Widget {
      #fooValue = 42
      getFoo() {
        return this.#fooValue
      }
      #barValue = 84
      getBar() {
        return this.#barValue
      }
    }
    

9. Modules (模块)

  • 模块的导入

    import { firstName, lastName, year } from './profile'
    
  • 模块的导出

    export var firstName = 'Michael'
    export var lastName = 'Jackson'
    export var year = 1958
    
  • 模块的默认导出

    export default function () {
      console.log('foo')
    }
    
  • 模块的默认导入

    import customName from './export-default'
    customName() // 'foo'
    
  • 模块的整体导入

    import * as circle from './circle'
    console.log('圆周率:' + circle.pi)
    console.log('计算面积:' + circle.area(4))
    
  • 模块的继承

    // profile.js
    export var firstName = 'Michael'
    export var lastName = 'Jackson'
    export var year = 1958
    
    // main.js
    import * as profile from './profile'
    import { lastName as surname } from './profile'
    
    function setName(element) {
      element.textContent = profile.firstName + ' ' + surname
    }
    
    • import * as object 将所有输出接口,放在一个对象上面

10. Promises (异步

  • Promises: 用于异步编程的解决方案, 用于解决回调地狱的问题.

  • Promise 的基本用法

    const promise = new Promise(function (resolve, reject) {
      // ... some code
      if (/* 异步操作成功 */){
        resolve(value)
      } else {
        reject(error)
      }
    })
    
  • Promise 的实例方法

    promise.then(
      function (value) {
        // success
      },
      function (error) {
        // failure
      }
    )
    
    promise.catch(function (error) {
      // failure
    })
    
    promise.finally(function () {
      // ...
    })
    
  • Promise api 的静态方法

    Promise.all([p1, p2, p3]).then(function (results) {
      console.log(results)
    })
    
    Promise.race([p1, p2, p3]).then(function (result) {
      console.log(result)
    })
    

11. Generators

  • Generators: 生成器函数, 可以返回多次的函数, 用于解决异步编程的问题.

  • Generator 函数的语法

    function* helloWorldGenerator() {
      yield 'hello'
      yield 'world'
      return 'ending'
    }
    
    var hw = helloWorldGenerator()
    
    hw.next() // { value: 'hello', done: false }
    hw.next() // { value: 'world', done: false }
    hw.next() // { value: 'ending', done: true }
    hw.next() // { value: undefined, done: true }
    

12. Map/Set/WeakMap/WeakSet

  • Map : 类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键

    const m = new Map()
    const o = { p: 'Hello World' }
    
    console.log(m.set(o, 'content')) // Map(1) { { p: 'Hello World' } => 'content' }
    
    m.set(o, 'content')
    m.get(o) // "content"
    
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false
    
  • Set : 类似于数组,但是成员的值都是唯一的,没有重复的值

    const s = new Set()[(2, 3, 5, 4, 5, 2, 2)].forEach((x) => s.add(x))
    console.log(s) // Set(4) { 2, 3, 5, 4 }
    
    console.log(s.has(2)) // true
    
    s.delete(2) // true
    
    for (let i of s) {
      console.log(i)
    }
    // 3 5 4
    
  • WeakMap : 只接受对象作为键名(null 除外),不接受其他类型的值作为键名

const wm = new WeakMap()
const element = document.getElementById('example')

wm.add(element, 'some information')
wm.get(element) // "some information"
wm.has(element) // true
wm.delete(element) // true
  • WeakSet
const ws = new WeakSet()
const element = document.getElementById('example')

ws.add(element)
ws.has(element) // true
ws.delete(element) // true
ws.has(element) // false

13. Proxies (代理)

  • ES6 原生提供的一种拦截 JavaScript 操作的能力

  • Proxy 的基本用法

    // 用于拦截目标对象的属性访问,可以识别出读取操作(get)、设置操作(set)、
    var proxy = new Proxy(target, handler)
    
    var proxy = new Proxy(
      {},
      {
        get: function (target, property) {
          return 35
        },
      }
    )
    
    var obj = new Proxy(
      {},
      {
        get: function (target, propKey, receiver) {
          console.log(`getting ${propKey}!`)
          return Reflect.get(target, propKey, receiver)
        },
        set: function (target, propKey, value, receiver) {
          console.log(`setting ${propKey}!`)
          return Reflect.set(target, propKey, value, receiver)
        },
      }
    )
    
    obj.count = 1
    // setting count!
    ++obj.count
    // getting count!
    // setting count!
    // 2
    

14. Symbols (符号)

  • Symbol: ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值

  • Symbol 的基本用法

    let s = Symbol()
    typeof s // "symbol"
    
    let s1 = Symbol('foo')
    let s2 = Symbol('bar')
    
    s1 // Symbol(foo)
    s2 // Symbol(bar)
    
    s1.toString() // "Symbol(foo)"
    s2.toString() // "Symbol(bar)"
    
    let s1 = Symbol()
    let s2 = Symbol()
    
    s1 === s2 // false
    

Iterator 和 for...of 循环

  • Iterator 的基本用法 :

  • Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费

    let arr = ['hello', 'world']
    let map = arr[Symbol.iterator]()
    
    map.next() // { value: "hello", done: false }
    map.next() // { value: "world", done: false }
    map.next() // { value: undefined, done: true }
    
  • for...of 循环

    // for...of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。
    let arr = ['hello', 'world']
    for (let v of arr) {
      console.log(v) // hello world
    }
    

    16 String 的扩展

  • 字符的 Unicode 表示法

    '\u0061' // "a"
    '\uD842\uDFB7' // "𠮷"
    '\u20BB7' // " 7"
    '\u{20BB7}' // "𠮷"
    
  • 字符的遍历器接口

    for (let codePoint of 'foo') {
      console.log(codePoint) // "f" "o" "o"
    }
    
  • at()

    'abc'.charAt(0) // "a"
    '𠮷'.charAt(0) // "\uD842"
    '𠮷'.at(0) // "𠮷"
    
  • normalize()

    '\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
    
  • includes(), startsWith(), endsWith()

    'abc'.includes('b') // true
    'abc'.startsWith('a') // true
    'abc'.endsWith('c') // true
    
  • repeat()

    'x'.repeat(3) // "xxx"
    'hello'.repeat(2) // "hellohello"
    'na'.repeat(0) // ""
    
  • padStart(), padEnd()

    'x'.padStart(5, 'ab') // "ababx"
    'x'.padEnd(4, 'ab') // "xaba"
    

17. 正则的扩展

  • RegExp 构造函数

    var regex = new RegExp('xyz', 'i')
    var regex = new RegExp(/xyz/i)
    var regex = new RegExp(/xyz/gi, 'i')
    
  • 字符串的正则方法

    'x'.match(/x/) // ["x"]
    'x'.match(/y/) // null
    'x'.replace('x', 'y') // "y"
    'x'.search(/x/) // 0
    'x'.search(/y/) // -1
    'x'.split('x') // [""]
    'x'.split('y') // ["x"]
    
  • u 修饰符

    /^\uD83D/u.test('\uD83D\uDC2A') // false
    /^\uD83D/.test('\uD83D\uDC2A') // true
    
  • y 修饰符

    var s = 'aaa_aa_a'
    var r1 = /a+/g
    var r2 = /a+/y
    
    r1.exec(s) // ["aaa"]
    r2.exec(s) // ["aaa"]
    
    r1.exec(s) // ["aa"]
    r2.exec(s) // null
    
  • sticky 属性

    var r = /hello\d/y
    r.sticky // true
    
  • flags 属性

    ;/abc/gi.flags // 'gi'
    
  • s 修饰符:dotAll 模式

    ;/foo.bar/.test('foo\nbar') / // false
      foo.bar /
      s.test('foo\nbar') // true
    

18. 数值的扩展

  • Number.isFinite(), Number.isNaN()

    Number.isFinite(15) // true
    Number.isFinite(0.8) // true
    Number.isFinite(NaN) // false
    Number.isFinite(Infinity) // false
    Number.isFinite(-Infinity) // false
    Number.isFinite('foo') // false
    Number.isFinite('15') // false
    Number.isFinite(true) // false
    
    Number.isNaN(NaN) // true
    Number.isNaN(15) // false
    Number.isNaN('15') // false
    Number.isNaN(true) // false
    Number.isNaN(9 / NaN) // true
    Number.isNaN('true' / 0) // true
    Number.isNaN('true' / 'true') // true
    
  • Number.parseInt(), Number.parseFloat()

    Number.parseInt === parseInt // true
    Number.parseFloat === parseFloat // true
    
  • Number.isInteger()

    Number.isInteger(25) // true
    Number.isInteger(25.0) // true
    Number.isInteger(25.1) // false
    Number.isInteger('15') // false
    Number.isInteger(true) // false
    
  • Number.EPSILON 属性: JavaScript 能够准确表示的最小精度

    Number.EPSILON === Math.pow(2, -52) // true
    
  • 安全整数和 Number.isSafeInteger()

    Number.isSafeInteger('a') // false
    Number.isSafeInteger(null) // false
    Number.isSafeInteger(NaN) // false
    Number.isSafeInteger(Infinity) // false
    Number.isSafeInteger(-Infinity) // false
    
    Number.isSafeInteger(3) // true
    Number.isSafeInteger(1.2) // false
    Number.isSafeInteger(9007199254740990) // true
    Number.isSafeInteger(9007199254740992) // false
    
  • Math 对象的扩展

    Math.trunc(4.1) // 4
    Math.trunc(4.9) // 4
    Math.trunc(-4.1) // -4
    Math.trunc(-4.9) // -4
    
    Math.sign(-5) // -1
    Math.sign(5) // +1
    Math.sign(0) // +0
    Math.sign(-0) // -0
    Math.sign(NaN) // NaN
    Math.sign('foo') // NaN
    Math.sign() // NaN
    
    Math.cbrt(-1) // -1
    Math.cbrt(0) // 0
    Math.cbrt(1) // 1
    Math.cbrt('8') // 2
    Math.cbrt('hello') // NaN
    Math.cbrt() // NaN
    
    Math.clz32(0) // 32
    Math.clz32(1) // 31
    Math.clz32(1000) // 22
    Math.clz32() // 32
    
    Math.imul(2, 4) // 8
    Math.imul(-1, 8) // -8
    Math.imul(-2, -2) // 4
    
    Math.fround(0) // 0
    Math.fround(1) // 1
    Math.fround(1.337) // 1.3370000123977661
    
    Math.hypot(3, 4) // 5
    Math.hypot(3, 4, 5) // 7.0710678118654755
    Math.hypot() // 0
    
    Math.expm1(1) // 1.718281828459045
    Math.expm1(0) // 0
    
    Math.log1p(1) // 0.6931471805599453
    Math.log1p(0) // 0
    
    Math.log10(2) // 0.3010299956639812
    Math.log10(1) // 0
    
    Math.log2(2) // 1
    Math.log2(1) // 0
    
    Math.sinh(x) // 返回 x 的双曲正弦(hyperbolic sine)
    Math.cosh(x) // 返回 x 的双曲余弦(hyperbolic cosine)
    Math.tanh(x) // 返回 x 的双曲正切(hyperbolic tangent)
    Math.asinh(x) // 返回 x 的反双曲正弦值
    
    Math.acosh(x) // 返回 x 的反双曲余弦值
    Math.atanh(x) // 返回 x 的反双曲正切值
    

19. 函数的扩展

  • 函数参数的默认值

    function log(x, y = 'World') {
      console.log(x, y)
    }
    
    log('Hello') // Hello World
    log('Hello', 'China') // Hello China
    log('Hello', '') // Hello
    
  • 与解构赋值默认值结合使用

    function foo({ x, y = 5 }) {
      console.log(x, y)
    }
    
  • 函数的 length 属性

    //(function (a) {}).length // 1 -->
    
    //(function (a = 5) {}).length // 0
    
    //(function (a, b, c = 5) {}).length // 2
    //(function (...args) {}).length // 0
    //(function (a, b, ...args) {}).length // 2
    
  • rest 参数

    function add(...values) {
      let sum = 0
    
      for (var val of values) {
        sum += val
      }
    
      return sum
    }
    
    add(2, 5, 3) // 10
    

20. 数组扩展

  • Array.from()

    Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
    
    let namesSet = new Set(['a', 'b'])
    Array.from(namesSet) // ['a', 'b']
    
  • Array.of()

    Array.of(3, 11, 8) // [3,11,8]
    Array.of(3) // [3]
    Array.of(3).length // 1
    
  • 数组实例的 copyWithin()

    ;[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
    
  • 数组实例的 find() 和 findIndex()

    ;[1, 4, -5, 10]
      .find((n) => n < 0) // -5
    
      [(1, 5, 10, 15)].find(function (value, index, arr) {
        return value > 9
      }) // 10
    

21. 对象的扩展

  • 属性的简洁表示法

    let foo = 'bar'
    let baz = { foo }
    baz // {foo: "bar"}
    
  • 属性名表达式

    let propKey = 'foo'
    
    let obj = {
      [propKey]: true,
      ['a' + 'bc']: 123,
    }
    
    obj // {foo: true, abc: 123}
    
  • 方法的 name 属性 返回函数的函数名

    const person = {
      sayName() {
        console.log('hello!')
      },
    }
    
    person.sayName.name // "sayName"
    
  • Object.is() 比较两个值是否严格相等

    Object.is('foo', 'foo') // true
    Object.is({}, {}) // false
    
  • Object.assign() 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)

    Object.assign(target, ...sources)
    
    let target = { a: 1 }
    
    let source1 = { b: 2 }
    
    let source2 = { c: 3 }
    
    Object.assign(target, source1, source2)
    
    target // {a:1, b:2, c:3}
    

22. Decorator

  • 装饰器是一个函数,用来修改类的行为

    // 类装饰器
    @testable
    class MyTestableClass {
      // ...
    }
    
    function testable(target) {
      target.isTestable = true
    }
    
    MyTestableClass.isTestable // true
    
    // 方法装饰器
    class Person {
      @readonly
      name() {
        return `${this.first} ${this.last}`
      }
    }
    
    function readonly(target, name, descriptor) {
      descriptor.writable = false
      return descriptor
    }
    
    let p = new Person()
    p.name = function () {
      return 'hello'
    }
    p.name() // TypeError: Cannot assign to read only property 'name' of object '#<Person>'
    
    // 属性装饰器
    class Person {
      @nonenumerable
      get kidCount() {
        return this.children.length
      }
    }
    
    function nonenumerable(target, name, descriptor) {
      descriptor.enumerable = false
      return descriptor
    }
    
    for (let key in p) {
      console.log(key)
    }
    
    let p = new Person({ children: ['a', 'b'] })
    p.kidCount // 2
    
    // 参数装饰器
    class Person {
      greet(@required name) {
        return 'Hello ' + name
      }
    }
    
    function required(target, name, index) {
      Object.defineProperty(target, name, {
        get: function () {
          throw new Error('Missing parameter')
        },
      })
    }
    
    let p = new Person()
    p.greet() // Error: Missing parameter
    
    // 装饰器执行顺序
    // 从后往前执行, 从下往上执行
    

    参考资料