ECMAScript

205 阅读5分钟

ECMAScript 概述

ECMAScrpt 是 javaScript 的一种标准

ECMAScript2015

ECMAScript2015 又称 ES6 ,

  • 相较于 ES5.1 版本变化较大
  • 自此命名规则发生了变化

目前有些开发者习惯用 ES6 来泛指 ES5.1 后所有的新标准 例如 async await 是ES7 新增

ES6 的准备工作

  • 选用启动环境: 新版浏览器或者 node 环境
  • 安装 nodemon 保存后可以自行运行

ES2015(ES6) 新特性

ES2015 let 与块级作用域

ES2015 const

ES2015 数组的解构

const arr = [100, 200, 300]
// ES6 之前
const foo = arr[0]
const bar = arr[1]
const baz = arr[2]
console.log(foo,bar,baz)
// ES6 
const [foo,bar,baz] = arr

ES2015 对象的解构

const obj = {name: 'zae', age: 18}
// const {name} = obj

// const name = 'tom'
// const {name: objName} = obj
// console.log(objName)

const name = 'tom'
// 可以设置默认值
const {name: objName = 'jack'} = obj
console.log(objName)

ES2015 模板字符串字面量

// 传统
//  const str = "hello es2015, this is a string"
// ES6 模板字符串可以不会对换行产生影响
 const str = `hello es2015,
 this is a string
 `
 const names ='tom'
 const msg = `hey, ${names} === ${1+2} ---- ${Math.random()}`
 
const {log} = console
log(str)
log(msg)

ES2015带标签的模板字符串

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

const name = "tom";
const gender = true;

function myTagFunc(strings, name, gender) {
  // console.log(strings[0]+ name + strings[1], + gender + strings[2])
  const sex = gender ? "women" : "man";
  return strings[0] + name + strings[1] + sex + strings[2];
}
const result = myTagFunc`hey, ${name} is a ${gender}.`;
console.log(result);

ES2015字符串的扩展方法

  • includes: 判断字符串是否含有某个字符
  • startWith: 判断字符串开头是否是某个字符
  • startEnd: 判断字符串结尾是否是某个字符
const message = 'Error: foo is not defined.'

console.log(
  message.startsWith('Error'),
  message.endsWith('.'),
  message.includes('foo')
)

ES2015 参数默认值

// 函数参数的默认值
// 带有默认值的参数必须放在最后
function foo (bar ,enable = true){
  console.log(bar,enable)
}
foo(1)

ES2015 剩余参数

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

ES2015 展开数组

// 展开数组
const arr = ['foo','bar', 'baz']
console.log.apply(console, arr)

console.log(...arr)

ES2015 箭头函数

const inc = (n,m) => {
  console.log('inc invoked')
  return n + 1
}
// 普通函数
const arr = [1,2,3,4,5,6,7]
// const arrFun = arr.filter(function(item){
//   console.log(item % 2) 
//   return item % 2
// })
// 箭头函数
const arrFun = arr.filter(item => item % 2)
console.log(arrFun)

ES2015 箭头函数与 this


const person = {
  name: 'tom',
  sayHi: function(){
    console.log( this )
    console.log(`普通函数 hi,my name is ${this.name}`)
  },
  sayArrowHi: () => {
    console.log(this)
    console.log(` 箭头函数 hi,my name is ${this.name}`)
  },
  sayHiAsync: function(){
    setTimeout(function() {
      console.log( this)
      console.log(`普通延时this hi,my name is ${this.name}`)
    }, 0);
  },
  sayHiArrowAsync: function(){

    setTimeout(()=> {
      console.log(this)
      console.log(`箭头延时this hi,my name is ${this.name}`)
    }, 0);
  }
}
// this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

// 箭头函数体内的 this 对象,就是定义 该函数时所在的作用域指向的对象 ,而不是使用时所在的作用域指向的对象。

person.sayHi()
person.sayArrowHi()
person.sayHiAsync()
person.sayHiArrowAsync()

ES2015 对象字面量的增强

对象字面量

 const bar = '345'
 const obj = {
    foo:123,
    // bar: bar,
    bar,
    // method1:function(){
    //   console.log('method111')
    // },
    method1(){
      console.log('method1111')
    },
    [bar]: 123,
    [Math.random]:789,
 }
 console.log(obj)

ES2015 对象扩展assgin

 // 将源对象赋值到目标对象,如果目标对象与源对象中,有相同的值, 源对象覆盖目标对象

 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)
 console.log(result === target)

// 用法:复制一个全新的对象
function func(obj){
  const funcObj = Object.assign({},obj)
  return funcObj
}
const obj = {name: 'global obj'}
func(obj)
console.log(obj)

ES6 2015 proxy 对比 defineProterty

// defineProperty 只能监听到对象的读取和写入, 而proxy 能监听到到defineProperty 监听不到的行为,更强大

const person = {
  name: 'wzy',
  age: 20
}
const personProxy = new Proxy(person, {
  deleteProperty(target, property){
    console.log(target,property)
    delete target[property]
  }
})
// 优势1:监听删除属性
delete personProxy.age
console.log(person)

// 优势2:更好监听数组的操作方式
const list = []
const listProxy = new Proxy(list,{
  set(target, property, value){
    console.log('set', property,value)
    target[property] = value
    return true // 表设置成功
  }
})
listProxy.push(100)

// 优势3: Proxy是以非侵入的方式监管了对象的读写,要带上属性名
const person2 = {}
Object.defineProperty(person2,'name',{
  get(){
    console.log('name 被访问')
    return person2._name
  },
  set(value){
    console.log('name 被设置')
    person2._name = value
  }
})

Object.defineProperty(person2,'age',{
  get(){
    console.log('age 被访问')
    return person2._age
  },
  set(value){
    console.log('age 被设置')
    person2._age = value
  }
})
person2.name = "wzy"
person2.age = 20
console.log(person2)

ES2015 reflect 统一对象操作 api

  • Reflect 是一个静态类, 不能通过new 来构建一个实例对象, 只能调用静态类里面的方法
  • Reflect 成员方法就是 Proxy 处理对象的默认实现

const obj = {
  foo: '123',
  bar: '456'
}
const proxy = new Proxy(obj,{
  get(target,property){
    return Reflect.get(target,property)
  }
})
console.log(obj.foo)

const person = {
  name:'wzy',
  age: 20
}
// console.log('name' in person)
// console.log(delete person.name)
// console.log(Object.keys(person))

// Reflect 统一处理方式
console.log(Reflect.has(person,'name'))
console.log(Reflect.deleteProperty(person,'age'))
console.log(Reflect.ownKeys(person))

ES2015 对象扩展方法object.js

// 通常建议使用严格等号
console.log(
      // NaN === NaN
      Objcet.is(NaN, NaN)
)

ES2016 proxy代理对象

 //原本监听对象属性, 使用definProperty

// 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){
    console.log(target,property,value)
    if(property==='age'){
      if(!Number.isInteger(value)) {
        throw new TypeError(`${value} is not an int`)
      }
    }
    target[property] = value
  }
})
personProxy.age = 20
console.log(personProxy.age)
console.log(personProxy.hhh)

ES2015 Promise

javaScript 异步编程中详细介绍

ES2015 Class 类

// 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}`);
  }
  // 静态方法
  static create(name) {
    return new Person(name);
  }
}
const p = new Person("wzy");

const tom = Person.create("tom");
tom.say();

// 继承
class Student extends Person {
  constructor(name, number) {
    // super 指继承父级
    super(name);
    this.number = number;
  }
  hello() {
    super.say();
    console.log(`my school number is ${this.number}`);
  }
  static create(name, number) {
    return new Student(name, number);
  }
}

const jack = Student.create("jack", 100);
jack.hello();

ES2015 set

/*
 * @Descritption: 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))
s.clear()
console.log(s)
const arr = [1,2,1,2,3,4,3]
// 拷贝数组
const result = [...new Set(arr)]
// 拷贝数组
// const result = Array.from(new Set(arr))

console.log(result)

ES2015 map

map 数据结构和 对象 Object 很相似,但比 Object 写起来更严谨

// const obj = {}
// obj[true] = 'value'
// obj[123] = 'value'
// obj[{a:1}] = 'value2' 
// console.log(Object.keys(obj)) // 输出结果,普通对象 设置键值时,如果键不是字符串类型, 会自动转换成字符串类型
// console.log(obj[{}])

const m = new Map()
const tom = {name : 'tom'}
m.set(tom,90)
m.set("tom",80)
console.log(m)
console.log(m.get(tom))
console.log(m.get('tom'))

分割

ES2015 Symbol

Symbol 一种全新的数据类型

/*
 * @Descritption: Symbol 一种全新的原始数据类型(表示独一无二的值) 最主要的作用是为对象添加一个独一无二的属性名
 */

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

// const cache = {}

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

// // b.js  ===================================
// cache['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()]:123
// }
// console.log(obj)

// a.js ===================================
const name = Symbol()
const person = {
  [name]:'zce',
  say(){
    console.log(this[name])
  }
}
//b.js =========
person.say()

const s1 =Symbol.for('foo') // 字符串一样就完全一样
const s2 =Symbol.for('foo')
console.log(s1 === s2)

ES2015 for...of 循环

引入了全新的循环方式 for...of 循环 ,作为遍历所有数据结构的统一方式

const arr = [100,200,300,400]
// for(const item of arr){
//   console.log(item)
// }

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

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

// const s = new Set(['foo','bar'] )
// for(const item of s){
//   console.log(item)
// }
// const m = new Map()
// m.set('foo','123')
// m.set('bar','456')
// for(const [key,value]  of m){
//   console.log(key,value)
// }
const obj = {foo: 123, bar: 456}
for(const item of obj){
  console.log(item)     // 报错,obj is not iterable
}

ES2015 可迭代接口 iterable

ES2015 能表示的有结构的数据类型越来越多如 Object Array map set ,,为了给各种数据结构提供统一的遍历方式 ES2015提供了 iterable 接口 实现 for...of 的前提是 实现了 iterable 接口


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

// 实现可迭代接口 (Iterable)

const obj = {
  store:['foo', 'bar','baz'],
  [Symbol.iterator]:function (){
  const self = this
  let index  = 0
    return {
      next: function(){
       
        const result = {
          value:self.store[index],
          done: index >= self.store.length
        }
        index++
        return result
      }
    }
  }
}
for(const item of obj){
  console.log(item)
}

ES2015 iterator 迭代器设计模式

 // 场景: 你我协同开发一个任务清单应用,提供统一的对外接口

// 我的代码 ======================
const todos = {
  life: ['吃饭','睡觉', '打豆豆'],
  learn: ['喝茶','数学','语文'],
  work: ['喝茶'],
  each: function (callback){
    const arr = [].concat(this.life, this.learn, this.work)
    for(const item of arr){
      callback(item)
    }
  },
  [Symbol.iterator]: function () {
    const arr = [...this.life, ...this.learn, ...this.work]
    let index = 0
    return {
      next: function(){
        return {
          value:arr[index],
          done: index++ >= arr.length
        }
      }
    }
  }
}



// 你的代码 ======================
todos.each(function(item){
  console.log(item)
})
console.log('--------------')
for(const item of todos){
  console.log(item)
}

ES2015 生成器 Generator

引入生成器的目的, 是为了避免异步编程中回调嵌套过深,从而提供更好的异步编程方案

// function * foo (){
//   console.log('zce')
//   return 100
// }
// const result = foo()
// console.log(result.next())

//  Generator 函数, 最大的特别就是惰性执行, 调一下, 执行一下
function * foo(){
  console.log('11111')
  yield 100
  console.log('22222')
  yield 200
  console.log('33333')
  yield 300
}

const generator = foo()
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())

ES2015 生成器 Generator 函数 应用

发号器,每调用一次执行一次

//  Generator 应用

// 案例1. 发号器
// function * createIdMaker () {
//   let id = 1
//   while(true){
//     yield id++
//   }
// }
// const idMaker = createIdMaker()
// console.log(idMaker.next())
// console.log(idMaker.next())
// console.log(idMaker.next())
// console.log(idMaker.next())
// console.log(idMaker.next())

// 使用 Generator 函数实现 iterator 方法

const todos = {
  life: ['吃饭','睡觉', '打豆豆'],
  learn: ['喝茶','数学','语文'],
  work: ['喝茶'],
  each: function (callback){
    const arr = [].concat(this.life, this.learn, this.work)
    for(const item of arr){
      callback(item)
    }
  },
  [Symbol.iterator]: function * () {
    const arr = [...this.life, ...this.learn, ...this.work]
    for(const item of arr ){
      yield item
    }
  }
}

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

ES2015 Modules

语言层面上的模块化规范,与 javaScript 模块化规范一起详细学习

ES2016 概述

与 ES2015 相比, 小版本 两个功能点

//  ES2016 增加了两个 功能点

//  Array.prototype.includes --------------------
const arr = ['foo',1,NaN, false]

// console.log(arr.indexOf('foo'))
// console.log(arr.indexOf('bar'))
// console.log(arr.indexOf(NaN))
// console.log(arr.indexOf(false))


console.log(arr.includes('foo'))
console.log(arr.includes('bar'))
console.log(arr.includes(NaN))
console.log(arr.includes(false))

// 指数运算符 --------------------------------

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

ES2017 概述

const obj = {
  foo: 'value1',
  bar: 'value2'
}


// Object.value --------------
console.log(Object.values(obj))

// Object.entries -----------------------
console.log(Object.entries(obj))

// Object.getOwnPropertyDescriptors ---------


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


// 在函数参数中添加尾号

const arr = [
  100,
  200,
  300,
  400
]
console.log(arr.length)

// async await  javaScript 中 详细讲解