ECMAScript新特性----ES6

ECMAScript新特性

1. ECMA概述

  • ECMASCript提供了最基本的语法
  • 2015年每年一个版本的迭代
  • javaScript@web ECMAScript操作的是DOM和BOM
  • javaScript@NodeJS ECMAScript操作的是NodeJS的API

2.ES2015概述

  • 解决原有语法上的一些问题或者不足
  • 对原有语法进行增强
  • 全新的对象,全新的方法,全新的功能
  • 全新的数据类型和解构

3.let与块级作用域

  • 作用域某个作用成员能够生效的范围

  • ES6以前只有两种作用域

    • 全局作用域
    • 函数作用域
  • let声明的成员只会在所声明的块中生效

    if (true) {
      // var foo = 'zce' //var 定义的可以访问到
      let foo = 'zce'
      console.log(foo)
    }
    console.log(foo)//foo is not defined
    
  • let 在for循环中的表现

    for (var i = 0; i < 3; i++) {
      for (var i = 0; i < 3; i++) {
        console.log(i)
      }
      console.log('内层结束 i = ' + i)
    }
    /*结果
    0
    1
    2
    内层结束 i = 3*/
    
  • let应用场景,循环绑定事件,事件处理程正确获取索引

    var elements = [{}, {}, {}]
    for (var i = 0; i < elements.length; i++) {
      elements[i].onclick = function () {
        console.log(i)
      }
    }
    elements[2].onclick()//2
    
  • for循环会产生两层作用域

    for (let i = 0; i < 3; i++) {
        console.log(i)
        let i = 'foo'
        console.log(i)
    }
    
  • let修复了变量的提升现象

    console.log(foo)
    var foo = 'zce'
    
    console.log(foo)//Cannot access 'i' before initialization
    let foo = 'zce'
    
  • const 是在let基础上多了只读(声明过后不允许修改)

    const name = 'zce'
        //恒量声明过后不允许重新赋值
    name = 'jack'//Assignment to constant variable.
    
  • const 声明同时必须赋值

    const name
    name = 'zce'//Missing initializer in const declaration
    
  • const内层指向是不允许修改 可以修改其成员

    // 恒量只是要求内层指向不允许被修改
    // const obj = {}
    // 对于数据成员的修改是没有问题的
    // obj.name = 'zce'
    

临时死区(temporal deada zone)

js社区

js扫描代码遇到var提升至全局,遇到let和const存放在TDZ中,访问TDZ的变量会触发错误 只有执行的时候 变量才会从TDZ中移除,然后才可以访问

4.数组,对象的解构

  • 数组的解构

    • //普通模式
      const arr = [100, 200, 300]
      const foo = arr[0]
      const bar = arr[1]
      const baz = arr[2]
      console.log(foo, bar, baz)//100 200 300
      
    • const [foo, bar, baz] = arr
      console.log(foo, bar, baz)//100 200 300
      
    • const [, , baz] = arr
      console.log(baz)//[ 200, 300 ]
      
    • const [foo, bar, baz, more] = arr
      console.log(more)//undefined
      
      const [foo, bar, baz = 123, more = 'default value'] = arr
      console.log(more)//default value
      
    • const path = '/foo/bar/baz'
      const tmp = path.split('/')//[ '', 'foo', 'bar', 'baz' ]
      const rootdir = tmp[1]
      console.log(rootdir)//foo
      
    • const [, rootdir] = path.split('/')
      
  • 对象的解构

    • const obj = { name: 'zce', age: 18 }
      
    • const { name } = obj
      console.log(name)
      
      const name = 'tom'
      const { name: objName } = obj
      console.log(objName)
      
      const name = 'tom'
      const { name: objName = 'jack' } = obj
      console.log(objName)//zce
      

5.模板字符串

  • 反引号包裹

    const str = `hello es2015, this is a string`
    
  • 允许换行

    const str = `hello es2015,
    
    this is a \`string\``
    
  • 可以通过 ${} 插入表达式,表达式的执行结果将会输出到对应位置

    const name = 'tom'
        // 可以通过 ${} 插入表达式,表达式的执行结果将会输出到对应位置
    const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}`
    console.log(msg)//hey, tom --- 3 ---- 0.7692434959917887
    
  • 带标签的模板字符串

    // 带标签的模板字符串
    
    // 模板字符串的标签就是一个特殊的函数,
    // 使用这个标签就是调用这个函数
    // const str = console.log`hello world`
    
    const name = 'tom'
    const gender = false
    
    function myTagFunc (strings, name, gender) {
      // console.log(strings, name, gender)
      // return '123'
      const sex = gender ? 'man' : 'woman'
      return strings[0] + name + strings[1] + sex + strings[2]
    }
    const result = myTagFunc`hey, ${name} is a ${gender}.`
    console.log(result)
    
  • 模板字符串(字符串)的扩展方法

    const message = 'Error: foo is not defined.'
    console.log(
        message.startsWith('Error'),
        message.endsWith('.'),
        message.includes('foo')
    )// true true true
    

6.ES2015参数默认值,剩余参数,展开数组

  • 参数默认

    function foo (enable = true) {
      console.log('foo invoked - enable: ')
      console.log(enable)
    }
    //默认参数一定是在形参列表的最后
    
  • 剩余参数

    function foo (first, ...args) {
      console.log(args)
    }
    
    foo(1, 2, 3, 4)
    
  • 展开数组

    const arr = ['foo', 'bar', 'baz']
    console.log(...arr)
    

7.ES2015箭头函数

  • 对比

    function inc (number) {
      return number + 1
    }
    // 完整参数列表,函数体多条语句,返回值仍需 return
    const inc = (n, m) => {
      console.log('inc invoked')
      return n + 1
    }
    //最简方式
    const inc = n => n + 1
    
  • 常用场景——回调函数

    const arr = [1, 2, 3, 4, 5, 6, 7]
    
    // arr.filter(function (item) {
    //   return item % 2
    // })
    
    // 常用场景,回调函数
    arr.filter(i => i % 2)
    
  • 箭头函数不会改变this的指向

    // 箭头函数与 this
    // 箭头函数不会改变 this 指向
    
    const person = {
      name: 'tom',
      // sayHi: function () {
      //   console.log(`hi, my name is ${this.name}`)
      // }
      sayHi: () => {
        console.log(`hi, my name is ${this.name}`)
      },
      sayHiAsync: function () {
        // const _this = this
        // setTimeout(function () {
        //   console.log(_this.name)
        // }, 1000)
    
        console.log(this)
        setTimeout(() => {
          // console.log(this.name)
          console.log(this)
        }, 1000)
      }
    }
    person.sayHiAsync()
    

8.ES2015对象字面量的增强

const bar = '345'

const obj = {
  foo: 123,
  // bar: bar
  // 属性名与变量名相同,可以省略 : bar
  bar,
  // method1: function () {
  //   console.log('method111')
  // }
  // 方法可以省略 : function
  method1 () {
    console.log('method111')
    // 这种方法就是普通的函数,同样影响 this 指向。
    console.log(this)
  },
  // Math.random(): 123 // 不允许
  // 通过 [] 让表达式的结果作为属性名
  [bar]: 123
}

// obj[Math.random()] = 123

console.log(obj)
obj.method1()

9.object.assign object.is Proxy defineProperty

  • object.assign

    • assign方法可以将两个对象合并成一个对象,第一个参数是合并返回的对象 后面是合并的对象

      const source1 = {
          a: 123,
          b: 123
      }
      
      const source2 = {
          b: 789,
          d: 789
      }
      
      const target = {
          a: 456,
          c: 456
      }
      
      const result = Object.assign(target, source1, source2)
      
      console.log(target)//{ a: 123, c: 456, b: 789, d: 789 }
      console.log(result === target)//true
      
    • 方便copy对象

      function func (obj) {
        // obj.name = 'func obj'
        // console.log(obj)
      
        const funcObj = Object.assign({}, obj)
        funcObj.name = 'func obj'
        console.log(funcObj)
      }
      
      const obj = { name: 'global obj' }
      
      func(obj)
      console.log(obj)
      
  • 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
    )
    
  • 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)
      }
    })
    

    Proxy对比object.defineProperty

    可以监视读写以外的操作

    const person = {
      name: 'zce',
      age: 20
    }
    
    const personProxy = new Proxy(person, {
      deleteProperty (target, property) {
        console.log('delete', property)
        delete target[property]
      }
    })
    
    delete personProxy.age
    console.log(person)
    

    可以很方便的监视数组操作

    const list = []
    
    const listProxy = new Proxy(list, {
        set(target, property, value) {
            console.log('set', property, value)
            target[property] = value
            return true // 表示设置成功
        }
    })
    
    listProxy.push(100)
    //set 0 100 set length 1
    listProxy.push(100)
    //set 1 100 set length 2
    

    Proxy不需要入侵对象

    const person = {}
    
    Object.defineProperty(person, 'name', {
      get () {
        console.log('name 被访问')
        return person._name
      },
      set (value) {
        console.log('name 被设置')
        person._name = value
      }
    })
    Object.defineProperty(person, 'age', {
      get () {
        console.log('age 被访问')
        return person._age
      },
      set (value) {
        console.log('age 被设置')
        person._age = value
      }
    })
    
    person.name = 'jack'
    console.log(person.name)
    // Proxy 方式更为合理
    const person2 = {
        name: 'zce',
        age: 20
    }
    
    const personProxy = new Proxy(person2, {
        get(target, property) {
            console.log('get', property)
            return target[property]
        },
        set(target, property, value) {
            console.log('set', property, value)
            target[property] = value
        }
    })
    
    personProxy.name = 'jack'
    
    console.log(personProxy.name)
    /*
    set 0 100   
    set length 1
    set 1 100
    set length 2
    name 被设置
    name 被访问
    jack
    set name jack
    get name
    jack
    */
    
  • Object.defineProperty()

在这里插入图片描述

10.Reflect Promise

// Reflect 内置对象,提供拦截javaScript的方法

// const obj = {
//   foo: '123',
//   bar: '456'
// }

// const proxy = new Proxy(obj, {
//   get (target, property) {
//     console.log('watch logic~')
    
//     return Reflect.get(target, property)
//   }
// })

// console.log(proxy.foo)

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

11.ES2015 Class 类 ES2015 静态方法 继承

1.创建一个类

function Person(name){
	this.name=name
}
Person.prototype.say=function(){
	console.log(`hi name is${this.name}`)
}
class Person{
	constructor(name){
        this.name=name;
    }
    say(){
        console.log(`hi,name is ${this.name}`)
    }
}

2.静态方法

class Person{
	constructor(name){
        this.name=name;
    }
    say(){
        console.log(`hi,name is ${this.name}`)
    }
    static create(name){
    return new Person(name)
    }
}

3.类的继承

class Person{
	constructor(name){
	this.name=name
	}
    say(){
        console.log(`hi my name is ${this.name}`)
    }
}

class Student extends Person{
    constructor(name,number){
        super(name)
        this.number=number
    }
    hello(){
        super.say()
        console.log(`my school  number is ${this.number}`)
    }
}
const s=new Student(jack,100)
s.hello()

12.Set Map Symbol

  • set
// Set 数据结构

const s = new Set()

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

// console.log(s)

// s.forEach(i => console.log(i))

// for (let i of s) {
//   console.log(i)
// }

// console.log(s.size)

// console.log(s.has(100))

// console.log(s.delete(3))
// console.log(s)

// s.clear()
// console.log(s)

// 应用场景:数组去重

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

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

console.log(result)

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

    // 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)
    })
    
    // 弱引用版本 WeakMap
    // 差异就是 Map 中会对所使用到的数据产生引用
    // 即便这个数据在外面被消耗,但是由于 Map 引用了这个数据,所以依然不会回收
    // 而 WeakMap 的特点就是不会产生引用,
    // 一旦数据销毁,就可以被回收,所以不会产生内存泄漏问题。
    
    
  • Symbol

    // Symbol 数据类型
    
    // 场景1:扩展对象,属性名冲突问题
    
    // // shared.js ====================================
    
    // const cache = {}
    
    // // a.js =========================================
    
    // cache['a_foo'] = Math.random()
    
    // // b.js =========================================
    
    // cache['b_foo'] = '123'
    
    // console.log(cache)
    
    // =========================================================
    
    // const s = Symbol()
    // console.log(s)
    // console.log(typeof s)
    
    // 两个 Symbol 永远不会相等
    
    // console.log(
    //   Symbol() === Symbol()
    // )
    
    // Symbol 描述文本
    
    // console.log(Symbol('foo'))
    // console.log(Symbol('bar'))
    // console.log(Symbol('baz'))
    
    // 使用 Symbol 为对象添加用不重复的键
    
    // const obj = {}
    // obj[Symbol()] = '123'
    // obj[Symbol()] = '456'
    // console.log(obj)
    
    // 也可以在计算属性名中使用
    
    // const obj = {
    //   [Symbol()]: 123
    // }
    // console.log(obj)
    
    // =========================================================
    
    // 案例2:Symbol 模拟实现私有成员
    
    // a.js ======================================
    
    const name = Symbol()
    const person = {
      [name]: 'zce',
      say () {
        console.log(this[name])
      }
    }
    // 只对外暴露 person
    
    // b.js =======================================
    
    // 由于无法创建出一样的 Symbol 值,
    // 所以无法直接访问到 person 中的「私有」成员
    // person[Symbol()]
    person.say()
    
    
    // Symbol 补充
    
    // console.log(
    //   // Symbol() === Symbol()
    //   Symbol('foo') === Symbol('foo')
    // )
    
    // Symbol 全局注册表 ----------------------------------------------------
    
    // const s1 = Symbol.for('foo')
    // const s2 = Symbol.for('foo')
    // console.log(s1 === s2)
    
    // console.log(
    //   Symbol.for(true) === Symbol.for('true')
    // )
    
    // 内置 Symbol 常量 ---------------------------------------------------
    
    // console.log(Symbol.iterator)
    // console.log(Symbol.hasInstance)
    
    // const obj = {
    //   [Symbol.toStringTag]: 'XObject'
    // }
    // console.log(obj.toString())
    
    // Symbol 属性名获取 ---------------------------------------------------
    
    const obj = {
      [Symbol()]: 'symbol value',
      foo: 'normal value'
    }
    
    // for (var key in obj) {
    //   console.log(key)
    // }
    // console.log(Object.keys(obj))
    // console.log(JSON.stringify(obj))
    
    console.log(Object.getOwnPropertySymbols(obj))
    
    

13.for。。。of

// for...of 循环

const arr = [100, 200, 300, 400]

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

// for...of 循环可以替代 数组对象的 forEach 方法

// arr.forEach(item => {
//   console.log(item)
// })

for (const item of arr) {
    console.log(item)
    if (item > 100) {
        break
    }
}

// forEach 无法跳出循环,必须使用 some 或者 every 方法

// arr.forEach() // 不能跳出循环
// arr.some()
// arr.every()

// 遍历 Set 与遍历数组相同

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

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

// 遍历 Map 可以配合数组结构语法,直接获取键值

// const m = new Map()
// m.set('foo', '123')
// m.set('bar', '345')

// for (const [key, value] of m) {
//   console.log(key, value)
// }

// 普通对象不能被直接 for...of 遍历

// const obj = { foo: 123, bar: 456 }

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

14.可迭代的接口

// 迭代器(Iterator)

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

const iterator = set[Symbol.iterator]()

// console.log(iterator.next()) //{value:"foo",done:false}
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

while (true) {
  const current = iterator.next()
  if (current.done) {
    break // 迭代已经结束了,没必要继续了
  }
  console.log(current.value)
}

//interable 接口的实现
const obj={
    store:[]
	[Symbol.interator]:function(){
        let index=0;
        const self=this
		return {
			next:function(){
			const result=return{ //迭代结果接口
					value:"",//迭代结果
					done:true//表示迭代完成
				}
                index++
                return index
			}
		}
	}
}
for(const item of obj){
    console.log('循环体')
}

15.迭代器模式

//
const todos={
	life:['吃饭','睡觉','打豆豆'],
    learn:['语文','数学','外语'],
    work:['写代码'],
    each:function(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
            }
        }
    }
	}
}

16.生成器 及应用

  • Generator

    // Generator 函数
    
    // function * foo () {
    //   console.log('zce')
    //   return 100
    // }
    
    // const result = foo()
    // console.log(result.next())
    
    function * foo () {
      console.log('1111')
      yield 100
      console.log('2222')
      yield 200
      console.log('3333')
      yield 300
    }
    
    const generator = foo()
    
    console.log(generator.next()) // 第一次调用,函数体开始执行,遇到第一个 yield 暂停
    console.log(generator.next()) // 第二次调用,从暂停位置继续,直到遇到下一个 yield 再次暂停
    console.log(generator.next()) // 。。。
    console.log(generator.next()) // 第四次调用,已经没有需要执行的内容了,所以直接得到 undefined
    
  • 应用

    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)
    
    // 案例2:使用 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)
    }
    

17.ESMoudules(语言层面的模块化开发)


18.ECMAScript2016

  • Array.prototype.includes

    // Array.prototype.includes -----------------------------------
    
    const arr = ['foo', 1, NaN, false]
    
    // 找到返回元素下标
    console.log(arr.indexOf('foo'))
        // 找不到返回 - 1
    console.log(arr.indexOf('bar'))
        // 无法找到数组中的 NaN
    console.log(arr.indexOf(NaN))
    
    // 直接返回是否存在指定元素
    console.log(arr.includes('foo'))
        // 能够查找 NaN
    console.log(arr.includes(NaN))
    
  • 指数运算符

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

19.ECMAScript2017

  • object.values 将对象的所有value存进一个数组

    const obj = {
        foo: 'value1',
        bar: 'value2'
    }
    console.log(Object.values(obj))//[ 'value1', 'value2' ]
    
  • object.entries 数组的每一个属性对应的值变成一个数组 并返回所有属性

    console.log(Object.entries(obj))//[ [ 'foo', 'value1' ], [ 'bar', 'value2' ] ]
    
  • 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 = 'zce'
    // console.log(p2)
    
    const descriptors = Object.getOwnPropertyDescriptors(p1)
    console.log(descriptors)// 打印值和属性描述符
    /*{
    <p>“属性描述符”对象只能在Object.defineProperty或Object.defineProperties中使用
      firstName: {        
        value: 'Lei', //数据属性    
        writable: true, //可以写的  
        enumerable: true, //可以枚举的
        configurable: true//可以配置的
      },
      lastName: {
        value: 'Wang',    
        writable: true,   
        enumerable: true, 
        configurable: true
      },
      fullName: {
        get: [Function: get fullName],
        set: undefined,
        enumerable: true,
        configurable: true
      }
    }*/
    
  • String.prototype.padStart / String.prototype.padEnd

    const books = {
        html: 5,
        css: 16,
        javascript: 128
    }
    
    // for (const [name, count] of Object.entries(books)) {
    //   console.log(name, count)
    // }
    
    for (const [name, count] of Object.entries(books)) {
        console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`)
    }
    
  • 函数参数尾部可以添加逗号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值