ECMAScript新特性

228 阅读3分钟

ECMAScript2015

1. let和const

  • let和const只会在所声明的块中生效
  • let在for循环中的表现
     for(var i = 0; i< 3; i++) {
         for(let i = 0; i < 3; i++) {
                 console.log(i)
         }
         console.log(`内层循环${i}`)
     }
    
  • let修复了变量声明提升现象
  • const是恒量,恒量要求声明同时赋值
  • 恒量声明过后不允许重新赋值
  • 恒量只是要求内层指向不允许被修改,对于数据成员的修改是没有问题的

2. 数组解构

    const arr = [1, 2, 3]
    const [foo, ...rest] = arr
    console.log(rest)

3. 对象解构

    const obj = {name: 'wfy', age: 17}
    const { name: objName = 'tom' } = obj
    console.log(objName)

4. 模板字符串

    - 反单引号包裹
    - 可以换行
    - 可以通过 ${} 插入表达式或变量
    - 带标签的模板字符串
        console.log`hey, ${name} is a ${gender}.`

5. 字符串的扩展方法

    const message = 'Error: foo is not defined.'
    console.log(
      // 以下均返回布尔值
      // message.startsWith('Error')
      // message.endsWith('.')
      message.includes('foo')
    )

6. 解构分配

    function foo (first, ...args) {
        console.log(first)
        console.log(args)
    }
    foo(1, 2, 3, 4)

7. 展开数组参数

    const arr = [1, 3, 5, 6, 6, 9]
    // console.log.apply(console, arr)
    console.log(...arr)

8. 箭头函数

    - 不会改变this指向
    // 最简方式
    // const inc = n => n + 1
    // 常用场景,回调函数
    arr.filter(i => i % 2)

9. 对象字面量

    const bar = '345'
    const obj = {
        bar,
        [1 + 1]: 2 // 通过 [] 让表达式的结果作为属性名
    }

10. Object.assign(target, source)

11. Object.is

    console.log(
      // 0 == false              // => true
      // 0 === false             // => false
      // +0 === -0               // => true
      // NaN === NaN             // => false
      // Object.is(+0, -0)       // => false
      // Object.is(NaN, NaN)     // => true
    )

12. Proxy

 const person = {
   name: 'zce',
   age: 20
 }

 const personProxy = new Proxy(person, {
   // 监视属性读取
   get (target, property) {
     return property in target ? target[property] : 'default'
     // console.log(target, property)
     // return 100
   },
   // 监视属性设置
   set (target, property, value) {
     if (property === 'age') {
       if (!Number.isInteger(value)) {
         throw new TypeError(`${value} is not an int`)
       }
     }

     target[property] = value
     // console.log(target, property, value)
   }
 })

 personProxy.age = 100

 personProxy.gender = true

 console.log(personProxy.name)
 console.log(personProxy.xxx)

13. Proxy对比Object.defineProperty()

// 优势一: Proxy可以监视读写以外的操作
const person = {
name: 'tom',
age: 12
}
const personProxy = new Proxy(person, {
        deleteProperty(target, property) {
                console.log('delete', property)
                delete target[property]
        }
})
delete personProxy.age
console.log(personProxy)

// 优势二:可以很方便的监视数组操作
const list = []
const listProxy = new Proxy(list, {
        set(target, property, value) {
                console.log('set', property, value)
                target[property] = value
                return true
        }
})
listProxy.push(1)
console.log('list', list)
console.log('listProxy', listProxy)

// 优势三:Proxy不需要侵入对象
    const person = {}
    Object.defineProperty(person, 'name', {
            get() {
                    console.log('name被访问')
                    return person._name
            },
            set(value) {
                    console.log('name被设置')
                    person._name = value
            }
    } )

    person.name = 'tom'
    console.log(person.name)

14. Reflect(统一的对象操作api)

    const obj = {
      name: 'zce',
      age: 18
    }
    // console.log('name' in obj)
    // console.log(delete obj['age'])
    // console.log(Object.keys(obj))
    console.log(Reflect.has(obj, 'name'))
    console.log(Reflect.deleteProperty(obj, 'age'))
    console.log(Reflect.ownKeys(obj))

15. class

    // function Person(name) {
    // 	this.name = name
    // }
    // Person.prototype.study = function() {
    // 	console.log('study hard and make progress everyday')
    // }
    class Person {
            constructor(name) {
                    this.name = name
            }

            study() {
                    console.log('study hard and make progress everyday')
            }
    }

    let p1 = new Person('tom')
    console.log(p1)
    p1.study()

16. static(静态方法)

   class Person {
      constructor (name) {
        this.name = name
      }

      say () {
        console.log(`hi, my name is ${this.name}`)
      }

      static create (name) {
        return new Person(name)
      }
   }
    const tom = Person.create('tom')
    tom.say()

17. extends(继承)

class Student extends Person {
   constructor (name, number) {
     super(name) // 父类构造函数
     this.number = number
   }

   hello () {
     super.say() // 调用父类成员
     console.log(`my school number is ${this.number}`)
   }
 }

18. Set(数据结构)

const s = new Set()
s.add(1).add(3).add(8)
s.forEach(value => console.log(value))
s.delete(8)
s.size
s.has(8)
s.clear()
// 应用场景:数组去重
const arr = [1, 2, 4, 5, 6, 6, 6, 8]
// const result = Array.from(new Set(arr))
const result = [...new Set(arr)]

19. WeakSet(弱引用版本)

  • 差异就在于Set会对于它使用到的数据产生引用
  • 即便这个数据在外面被消耗,但是由于Set引用了这个数据,所以不会被回收
  • 而weakSet的特点就是不会产生引用
  • 一旦数据销毁,就可以被回收,所以不会产生内存泄漏的问题

20. Map(数据结构)

 // const obj = {}
 // obj[true] = 'value'
 // obj[123] = 'value'
 // obj[{ a: 1 }] = 'value'
 // console.log(Object.keys(obj))
 // console.log(obj['[object Object]'])
 const m = new Map()
 const tom = { name: 'tom' }
 m.set(tom, 90)
 console.log(m)
 console.log(m.get(tom))
 // m.has()
 // m.delete()
 // m.clear()
 m.forEach((value, key) => {
   console.log(value, key)
 })

21. WeakMap(弱引用版本)

  • 差异就是Map会对所使用的数据产生引用
  • 即使这个数据在外面被消耗,但是由于Map引用了这个数据,所以依然不会回收
  • 而WeakMap的特点就是不会产生引用
  • 一旦数据销毁,就可以被回收,所以不会产生内存泄漏的问题

22. Symbol

  • 新增的一种基本数据类型(原始数据类型),由此原始数据类型变为7种
  • 唯一性
    • 解决属性名冲突问题(两个Symbol永远不会相等)
    • Symbol 模拟实现私有成员

23. for-of循环

  • for of循环可以代替 数组对象 的forEach方法
  • forEach无法跳出循环,必须使用some 或者 every 方法
  • 遍历 Set 与遍历数组相同
  • 遍历 Map 可以配合数组结构语法,直接获取键值
  • 普通对象不能被直接 for...of 遍历

24. 迭代器(Iterator)

  • 凡是含有iterator的结构,都可以进行遍历操作(generator原理)

25. generator函数

  • 执行generator函数会返回一个遍历器对象,遍历器对象.next方法会返回一个对象,对象有两个属性,一个是value,value的值是yield后面跟的内容,还有一个是done,判断后面还有没有内容

ECMAScript 2016

1. includes

  • Array.prototype.includes
    • 原来的做法:
    // 找到返回元素下标
    // console.log(arr.indexOf('foo'))
    // 找不到返回 -1
    // console.log(arr.indexOf('bar'))
    // 无法找到数组中的 NaN
    // console.log(arr.indexOf(NaN))
    
    • 有了includes之后:
    // 直接返回是否存在指定元素
    // console.log(arr.includes('foo'))
    // 能够查找 NaN
    // console.log(arr.includes(NaN))
    

2. 指数运算符

```js
console.log(Math.pow(2, 10))
console.log(2 ** 10)
```

ECMAScript 2017

1. Object新增了api

- Object.values
- Object.entries
- Object.getOwnPropertyDescriptors

2. String新增了api

- String.prototype.padStart
- String.protptype.padEnd

3. 在函数参数中添加尾逗号

 function foo (
  bar,
   baz,
 ) { }