ES6新特性

- ECMAScript 与 Javascript

- ECMAScript的发展过程

- ECMAScript2015的新特性

- And more...

- ECMAScript (ES) 通常看作Javascript的标准化规范  实际上JavaScript是ECMAScript的扩展语言

    - ECMAScript只提供了最基本的语法

    - JavaScript @ Web (在浏览器环境中): JavaScript = ECMAScript + Web APIs(DOM + BOM)

    - JavaScript @ Nodejs (在浏览器环境中): JavaScript = ECMAScript + Node APIs(fs + net + etc.)

    - Javascript语言本身是ECMAScript


#### ES6

- 解决原油语法上的一些问题或者不足

- 对原有语法进行增强

- 全新的对象、全新的方法、全新的功能

- 全新的数据类型和数据结构

#### let与块级作用域

- 作用域 - 某个成员能够起作用的范围

- 全局作用域 函数作用域 块级作用域

- 块 : 代码中花括号包裹起来的范围

- let没有声明提升

```javascript

// 块

// if(true){

//    // var foo = 'foo'

//    let foo = 'foo'

//    console.log(foo)

// }

// // console.log(foo)

// ----------------------------------------------------

// for循环中的计数器

// for(var i = 0; i < 3; i++){

//    for(var i = 0; i < 3; i++){

//        console.log(i)

//    }

//    console.log('i out', i)

// }

// for(let i = 0; i < 3; i++){

//    for(let i = 0; i < 3; i++){

//        console.log(i)

//    }

//    console.log('i out', i)

// }

// --------------------------------

// var elements = [{}, {}, {}]

// for(var i = 0; i< elements.length; i++){

//    elements[i].onclick = (function (i) {

//        return function () {

//            console.log(i)

//        }

//    })(i)

// }

// for(let i = 0; i< elements.length; i++){

//    elements[i].onclick = function () {

//        console.log(i)

//    }

// }

// elements[0].onclick()

// --------------------------------------------

// for(let i = 0; i< 3;i++){

//    let i = 'foo'

//    console.log(i)

// }

// let i = 0

// if(i < 3){

//    let i = 'foo'

//    console.log(i)

// }

// i++

// if(i < 3){

//    let i = 'foo'

//    console.log(i)

// }

// i++

// if(i < 3){

//    let i = 'foo'

//    console.log(i)

// }

// i++

// if(i < 3){

//    let i = 'foo'

//    console.log(i)

// }

// i++

// ------------------------------------

// let 没有声明提升

// console.log(foo)

// var foo = 'foo'

// console.log(foo)

// let foo = 'foo'

```

#### const

- let基础上多了**只读**特性, 声明过后不允许在被修改且变量声明必须直接赋值

- 最佳实践: 不用var, 主用const, 配合let

```javascript

// const变量声明 不能修改

// const name = 'const'

// name = 'liuchao'

// const变量声明必须直接赋值

// const name

// name = 'const'

// ------------------

// const obj = {}

// obj.name = 'const'

// obj = {}

```

#### 数组的解构

```javascript

const arr = [100, 200, 300]

// const foo = arr[0]

// const bar = arr[1]

// const baz = arr[2]

// const [foo, bar, baz] = arr

// console.log(foo, bar, baz)

// const [, , baz] = arr

// console.log( baz)

// const [foo, ...rest] = arr

// console.log(rest)

// const [foo, bar, baz, more] = arr

// console.log(more)

// const [foo, bar, baz, more = 'more'] = arr

// console.log(more)

```

#### 对象的解构

```javascript

const obj = {name: 'const', age: 10}

// const {name, age} = obj

// console.log(name, age)

// const name = 'tom'

// const {name: objName = 'objName'} = obj

// console.log(objName, name)

const {log} = console

log('xxx')

log('aaa')

log('adkdk')

```

#### 模版字符串字面量

```javascript

const str = 'hello es2015, this is a string'

const str = `hello es2015,

this is a \`string\``

// ``内支持转义字符  支持换行 多行字符串

console.log(str)

// 支持变量嵌入 简单运算 js内置函数

const name = 'liuchao'

const msg = `hey, ${name}--------${1 + 3}---------${Math.random()}`

console.log(msg)

```

#### 模版字符串标签函数

```javascript

// const str = console.log`hello world`

const name = 'luchao'

const gender = true

function myTagFunc(str, name, gender){

    // console.log(str, name, gender)

    // return '123'

    const sex = gender ? 'man' : 'women'

    return str[0] + name + str[1] + sex + str[2]

}

const result = myTagFunc`hey, ${name} is a ${gender}.`

console.log(result)

```

#### 字符串的扩展方法

- includes

- startWith

- endWith

```javascript

const  msg = 'Error: foo is not defined.'

console.log(

    msg.startsWith('Error'),

    msg.endsWith('.'),

    msg.includes('foo')

)

```

#### 参数默认值

```javascript

// function foo(enable){

//    // enable = enable || true

//    enable = enable === undefined ? true : enable

//    console.log('foo invoked - enable: ')

//    console.log(enable)

// }

// 带默认值的参数在最后

function foo(bar,enable = true){

    console.log('foo invoked - enable: ')

    console.log(enable)

}

foo(false)

```

#### 剩余参数

```javascript

// function foo(){

//    console.log(arguments)

// }

// ...操作符只能用在最后一个参数 并且只能使用一次

function foo(...args){

    console.log(args)

}

foo(1, 2, 4, 45)

```

#### 展开数组参数

```javascript

const arr = ['foo', 'bar', 'baz']

// console.log(

//    arr[0],

//    arr[1],

//    arr[2]

// )

// console.log.apply(console, arr)

console.log(...arr)

```

#### 箭头函数

- 箭头函数不会改变this的指向

```javascript

// function inc(num){

//    return num + 1

// }

// const inc = n => n+1

// console.log(inc(100))

const arr = [1, 2, 3, 4, 5, 6, 7]

// arr.filter(function(item){

//    return item % 2

// })

const result = arr.filter(item => item % 2)

console.log(result)

// 箭头函数与 this

const person = {

    name : 'tom',

    // sayHi: function(){

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

    // }

    sayHi: () => {

        // 箭头函数没有this机制 不会改变this指向

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

    },

    sayHiAsync: function () {

        // const _this = this

        // setTimeout(function(){

        //    console.log(_this.name)

        // }, 1000)

        setTimeout(()=>{

            console.log(this.name)

        }, 1000)

    }

}

person.sayHi()

person.sayHiAsync()

```

#### 对象字面量增强

- 计算属性名

```javascript

const bar = '2233'

const obj = {

    name: '111',

    // bar: bar,

    bar,

    // method1: function(){

    //    console.log('mothed111')

    // },

    method1(){

        console.log('mothed111')

        console.log(this)

    },

    // Math.random(): 111

    // 计算属性名

    [Math.random()]: 1113

}

obj[Math.random()] = 1112

console.log(obj)

obj.method1()

```

#### 对象扩展方法

- Object.assign 将多个源对象中的属性复制到一个目标对象中(如果有相同, 源对象中的属性就会覆盖目标对象中的属性)

```javascript

// const source = {

//    a: 111,

//    b: 233

// }

// const source2 = {

//    d: 111,

//    f: 233

// }

// const target = {

//    a: 444,

//    c: 666

// }

// const result = Object.assign(target, source, source2)

// console.log(result)

// console.log(result === target)

function func(obj){

    // obj.name = 'func obj'

    // console.log(obj)

    const funcObj = Object.assign({}, obj)

    funcObj.name = 'func obj'

    console.log(funcObj, 'funcObj')

    return funcObj

}

const obj = {name: 'global obj'}

func(obj)

console.log(obj)

```

- is

```javascript

console.log(

    0 == false,

    0 === false,

    +0 === -0,

    NaN === NaN,

    Object.is(+0, -0),

    Object.is(NaN, NaN),

)

```

#### Proxy 代理对象(Object.defineProperty)以及Proxy的优势

- defineProperty只能监视属性的读写 Proxy能够监视更多对象操作(delete操作、对对象方法的调用等)

- Proxy更好的支持数组对象的监视 (以往监视数组操作方法是重写数组的操作方法)

- Proxy是以非侵入的方式监管了对象的读写(一个定义好的对象,不需要对对象本身进行操作就可以监视到内部成员的读写, 而defineProperty通过特定的方式单独定义需要被监视的属性,需要去做很多额外的操作)

```javascript

// Proxy 对象

const person = {

    name: 'liuchao',

    age: 18

}

// 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 = 99 

// personProxy.gender = 'man'

// console.log(personProxy.name)

// console.log(personProxy.xxx)

// -----------------------------------

//  Proxy 监听对象delete属性行为

// const personProxy = new Proxy(person, {

//    deleteProperty(target, property){

//        console.log('delete', target, property)

//        delete target[property]

//    }

// })

// delete personProxy.age

// console.log(person)

// -------––-------––-------––-------––-------––

// 如何使用Proxy对象监听数组

const list = []

const listProxy = new Proxy(list, {

    set(target, property, value){

        console.log('set', property, value)

        target[property] = value

        return true //表示设置成功

    }

})

listProxy.push(100)

```

#### Reflect 统一的对象操作API

- 属于一个静态类, 不能通过new 构建实例对象, 只能调用静态类中的一些方法

- Reflect内部封装了一系列对对象的底层操作(14个, 一个被废弃; 方法名和Proxy中的方法名相同)

- Reflect成员方法就是Proxy处理对象的默认实现

- **最大的作用** 统一提供一套用于操作对象的API

```javascript

// Reflect 对象

// const obj = {

//    foo: '122',

//    bar: '222'

// }

// const proxy = new Proxy(obj, {

//    get(target, property){

//        console.log('watch login~')

//        return Reflect.get(target, property)

//    }

// })

// console.log(proxy.foo)

// example

const obj = {

    name: 'liuchao',

    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))

```

#### Promise

- 一种更优的异步编程解决方案, 解决了传统异步编程中回调函数嵌套过深的问题

#### class类

- 静态成员 static

- 类的继承 extends

```javascript

// Class 关键词

// function Person (name){

//    this.name = name

// }

// Person.prototype.say = function(){

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

// }

// class Person {

//    constructor(name){

//        this.name = name

//    }

//    say(){

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

//    }

// }

// const p = new Person('liuchao')

// p.say()

// ----------------------------------------

// 静态方法 static

// class Person {

//    constructor(name){

//        this.name = name

//    }

//    say(){

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

//    }

//    static create(name){

//        return new Person(name)

//    }

// }

// Person.create('liuchao').say()

// ----------------------------------------

// 类的继承 extends

class Person {

    constructor(name){

        this.name = name

    }

    say(){

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

    }

}

class Student extends Person {

    constructor(name, num){

        super(name)

        this.num = num

    }

    hello(){

        super.say()

        console.log(`my school number is ${this.name}`)

    }

}

const s = new Student('liuchao', 200)

s.hello()

```

#### Set数据结构

```javascript

const s = new Set()

// 向Set数据结构中添加数据 重复添加会覆盖(后边覆盖前边的)

s.add(1).add(2).add(3).add(4).add(1)

console.log(s)

// 遍历成员

s.forEach(i => console.log('foreach' + i))

for(let i of s){

    console.log('for+ of' + i)

}

// 获取Set数据集合的长度

console.log(s.size)

// 判断Set数据中是否有某个元素

console.log(s.has(100))

// 删除Set数据中某个元素

console.log(s.delete(1), s)

// 清除Set数据中所有元素

console.log(s.clear(), s)

// 作用 : 数组去重

const arr = [1, 1, 3, 4, 2, 4, 2]

// const result = Array.from(new Set(arr))

const result = [...new Set(arr)]

console.log(result)

```

#### Map数据结构

- 普通对象只能使用string作为键值(就算不是也会转换成string)

- Map数据结构键值可以为任意值

```javascript

// 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)

})

```

#### Symbol 一种全新的原始数据类型

- 最主要的作用就是为对象添加独一无二的属性名

- 唯一性

```javascript

// // shared.js ======================

// const cache = {}

// // a.js ===========================

// cache['foo'] = Math.random()

// cache['a_foo'] = Math.random()

// // b.js ===========================

// cache['foo'] = '123'

// cache['b_foo'] = '123'

// console.log(cache)

const s = Symbol()

console.log(s)

console.log(typeof s)

console.log(Symbol() === Symbol())

console.log(Symbol('foo'))

console.log(Symbol('bar'))

console.log(Symbol('baz'))

const obj = {

    [Symbol()]: '122'

}

console.log(obj)

// a.js ================================

const name = Symbol()

const person = {

    [name]: 'liuchao',

    say(){

        console.log(this[name])

    }

}

// b.js ================

// console.log(person[Symbol()]) //得不到结果

person.say()

// Symbol补充

// 唯一性

console.log(

    Symbol() === Symbol(),

    Symbol('foo') === Symbol('foo'),

)

// 全局服用一个相同的Symbol值 方式:1. 全局变量 2. Symbol.for方法

const s1 = Symbol.for('foo')

const s2 = Symbol.for('foo')

console.log(s1 === s2)

// ***** 特别注意: Symbol.for方法中维护的注册表是字符串string关联的, 非string也会转换成string

console.log(

    Symbol.for(true) === Symbol.for('true')

)

// Symbol提供的Symbol常量

console.log(Symbol.iterator)

console.log(Symbol.hasInstance)

const obj1 = {

    [Symbol.toStringTag]: 'Symbol'

}

console.log(obj1.toString())

// Symbol作为键值通过for in循环无法拿到 Object.key()也无法获取到 字符串化JSON.stringigy也会被忽略掉

const obj2 = {

    [Symbol()]: '222',

    name: 'liuchao'

}

for(let key in obj2){

    console.log(key)

}

console.log(Object.keys(obj2))

console.log(JSON.stringify(obj2))

// 可以通过Object.getOwnPropertySymbols()

console.log(Object.getOwnPropertySymbols(obj2))

```

#### BigInt 原始数据类型(用于储存更长的数字) 处在stage-4阶段

#### for of循环 作为遍历所有数据结构的统一方式

- ES2015提供了Iterable接口(可迭代接口)

- 实现Iterable接口就是for...of的前提

- 实现可迭代接口

- 迭代器模式

- 迭代器意义: 对外提供统一遍历接口, 不用关心数据内部结构

```javascript

const arr = [100, 200 , 399 ,3999]

// for(const item of arr){

//    console.log(item)

// }

// arr.forEach(item => {

//    console.log(item)

// })

// for of 可以使用break关键字 forEach循环不可以

// for(const item of arr){

//    console.log(item)

//    if(item > 200){

//        break

//    }

// }

// arr.forEach(item => {

//    console.log(item)

//    // if(item > 200){

//    //    break

//    // }

// })

// 终止遍历方法 arr.some() arr.every()

// ----------------------------------------------

// 遍历Set数据和Map数据

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

for(const item of s){

    console.log('set ' + item)

}

const m = new Map()

m.set('foo', '133')

m.set('bar', '13dkdk')

for(const [key, value] of m){

    console.log('map', key, value)

}

// -----------------------------

// 遍历普通对象

const obj = {

    foo: 122,

    bar: 333

}

// for(const item of obj){ //TypeError: obj is not iterable 不可被迭代

//    console.log('obj  ' + item)

// }

```

#### 迭代器[Iterator]

```javascript

// 迭代器 [Iterator]

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

const iterator = set[Symbol.iterator]()

console.log(iterator.next())

console.log(iterator.next())

console.log(iterator.next())

console.log(iterator.next())

console.log(iterator.next())

console.log(iterator.next())

// 实现可迭代接口

// const obj = {

//    [Symbol.iterator]: function(){ //Iterator接口

//        return {

//            next: function(){ //IteratorREsult

//                return {

//                    value: 'liuchao',

//                    done: true

//                }

//            }

//        }

//    }

// }

const obj = {

    store: ['foo', 'bar', 'baz'],

    [Symbol.iterator]: function(){ //Iterator接口

        let index = 0

        const self = this

        return {

            next: function(){ //IteratorREsult

                const result = {

                    value: self.store[index],

                    done: index >= self.store.length

                }

                index++

                return result

            }

        }

    }

}

for(const item of obj){

    console.log(item)

}

// 迭代器模式

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

// 我的代码=====================

const todos = {

    life: ['吃饭', '睡觉', '打豆豆'],

    learn: ['语文', '数学', '英语'],

    work: ['喝茶'],

    each(callback){

        const all = [].concat(this.life, this.learn, this.work)

        for(const item of all){

            callback(item)

        }

    },

    [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(item => {

    console.log(item)

})

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

for(const item of todos){

    console.log(item)

}

```

#### 生成器函数Generator

- 避免异步编程中回调嵌套过深,从而提供更好的异步编程解决方案

```javascript

// function * foo(){

//    console.log('foo')

//    return 100

// }

// const result = foo()

// console.log(result.next())

function * foo(){

    console.log(11111)

    yield 100

    console.log(2222)

    yield 200

    console.log(3333)

    yield 300

}

const generator = foo()

console.log(generator.next())

console.log(generator.next())

console.log(generator.next())

console.log(generator.next())

// ---------------------------------

// 生成器的应用 Generator

// 案例一: 发号器

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

// function * createIdMaker(){

//    let id = 1

//    while(true){

//        yield id++

//    }

// }

// const idMaker = createIdMaker()

// console.log(idMaker.next().value)

// console.log(idMaker.next().value)

// console.log(idMaker.next().value)

// console.log(idMaker.next().value)

// console.log(idMaker.next().value)

// 案例二: 使用Generator函数实现iterator接口

const todos = {

    life: ['吃饭', '睡觉', '打豆豆'],

    learn: ['语文', '数学', '英语'],

    work: ['喝茶'],

    [Symbol.iterator]: function *(){

        const all = [...this.life, ...this.learn, ...this.work]

        for(const item of all){

            yield item

        }

    }

}

for(const item of todos){

    console.log(item,'yield')

}

```

#### ES Modules 语言层面的模块化标准

#### ES2016

- 1. Array.prototype.includes

- 2. 指数运算符 console.log(2 ** 20)

```javascript

// 1. Array.prototype.includes

const arr = ['foo', 1, NaN, false]

// indexOf不能用于查找NaN

console.log(arr.indexOf('foo'))

console.log(arr.indexOf('bar'))

console.log(arr.indexOf(NaN))

console.log(arr.includes('foo'))

console.log(arr.includes('bar'))

console.log(arr.includes(NaN))

// 指数运算符

console.log(Math.pow(2, 10))

console.log(2 ** 20)

```

#### ES2017

- 1. Object.values

- 2. Object.entries

- 3. Object.getOwnPropertyDescriptors

- 4. String.prototype.padStart / String.prototype.padEnd

- 5. 在函数参数中添加尾逗号

- 6. Async/await

```javascript

const obj = {

    foo: 'value1',

    bar: 'value2'

}

// - 1. Object.values

console.log(Object.values(obj))

// - 2. Object.entries

console.log(Object.entries(obj))

for(const [key, value] of Object.entries(obj)){

    console.log(key, value)

}

console.log(new Map(Object.entries(obj)))

// - 3. Object.getOwnPropertyDescriptors

const p1 = {

    firstName: 'lei',

    lastName: 'wang',

    get fullName(){

        return this.firstName + ' ' + this.lastName

    }

}

console.log(p1.fullName)

// const p2 = Object.assign({}, p1)

// p2.firstName = 'liuchao'

// console.log(p2.fullName)

const descriptors = Object.getOwnPropertyDescriptors(p1)

console.log(descriptors)

const p2 = Object.defineProperties({}, descriptors)

p2.firstName = 'liuchao'

console.log(p2.fullName)

// - 4. String.prototype.padStart / String.prototype.padEnd

const books = {

    html: 3,

    css: 15,

    js: 22

}

// for(const [key, value] of Object.entries(books)){

//    console.log(key, value)

// }

for(const [key, value] of Object.entries(books)){

    console.log(`${key.padEnd(16, '-')}|${value.toString().padStart(3, '0')}`)

}

// - 5. 在函数参数中添加尾逗号

function foo2(bar, baz,) {

    return 100

}

const arr2 = [100,200,300,]

```

你可能感兴趣的:(ES6新特性)