ECMAScript

目录

概述

ECMAScript

ES2015 概述

ES2015 let 与块级作用域

Const 常量/恒量

ES2015 数组的解构

ES2015 对象的解构

ES2015 模板字符串

ES2015 字符串拓展方法

ES2015 函数形参新语法

ES2015 箭头函数

 ES2015 对象字面量的增强

ES2015 Object.assign

 ES2015 Object.is

 ES2015 Proxy

 ES2015 Reflect

ES2015 Class

ES2015 Map

ES2015 Symbol函数

 ES2015 for..of

ES2015迭代器Iterator

ES2015 生成器

ES2016 概述

ES2017 概述


概述

ECMAScript

  • ECMAScript简写成ES, 也是一门编程语言,
  • 通常看作是Javascript的标准化规范,Javascript可以看作是ES的扩展语言,ES只提供最基础的语法
  • 在浏览器环境中的Javascript等于ES+web API(BOM, DOM)
  • 在Node环境中的Javascript就等于ES+ node API(fs, net...etc)

 

ES2015 概述

  • ES发布了很多版本,其中变化最多的就是2015年发布的ECMAScript2015,一般称为ES6
  • 从2015年开始,ES保持每年一个版本的迭代

ES2015 let 与块级作用域

  • 作用域就是某成员能够起作用的范围,ES6之前,只有全局作用域和函数作用域,ES6新增了块级作用域
  • 块就是一堆花括号包起来的范围,ES6中和let配合使用
// let 声明的成员只会在所声明的块中生效 
if (true) {
    var foo = 'zce'
}
console.log(foo)//zce

if (true) {
    let x = 'zce'
}
console.log(x)//undefined,  let声明的变量只能在作用域内访问
  • let能解决for循环变量重名的问题
// 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
for (var i = 0; i < 3; i++) {
  for (let i = 0; i < 3; i++) {
    console.log(i)
  }
  console.log('内层结束 i = ' + i)
}

Const 常量/恒量

  • 只读,声明后不允许修改
const name = 'zce'
// 恒量声明过后不允许重新赋值
// name = 'jack'会报错
  • 不能修改对象的内存地址,可以修改对象中的属性值(对象所占内存的数据)
// 恒量只是要求内层指向不允许被修改
const obj = {}
// 对于数据成员的修改是没有问题的
obj.name = 'zce'
  • 必须先声明再赋值

ES2015 数组的解构

const arr = [100, 200, 300]
const [foo, bar, baz] = arr
console.log(foo, bar, baz)//100, 200, 300,按顺序输出

const [, , baz] = arr
console.log(baz)//只输出300,

const [foo, ...rest] = arr
console.log(rest)//...reset只可用于数组最后一位,此处输出[200, 300]

const [foo, bar, baz, more] = arr
console.log(more)//会输出undefined,因为arr一共只有三个数据

const [foo, bar, baz = 123, more = 'default value'] = arr
console.log(bar, more)//设置默认值

const path = '/foo/bar/baz'
const [, rootdir] = path.split('/')
console.log(rootdir)//字符串分割

ES2015 对象的解构

  • 根据属性名去提取而非下标
const obj = { name: 'xm', age: 18 }

const { name } = obj
console.log(name)//xm

const name = 'ami' //变量和属性名重复
const { name: objName } = obj//属性名赋给一个新变量名
console.log(objName)//xm

const name = 'ami'
const { name: objName = 'lily' } = obj
console.log(objName)//xm
  • 具备和数组一样的操作(...rest)

ES2015 模板字符串

  • 可直接换行
  • 可以通过 ${} 去插入** 任何标准的JavaScript语句 **
const name = 'tom'
// 可以通过 ${} 插入表达式,表达式的执行结果将会输出到对应位置
const msg = `hey, ${name}`
console.log(msg)//hey, tom
  • 可以设置带标签的模板字符串

// 模板字符串的标签就是一个特殊的函数,
// 使用这个标签就是调用这个函数
// 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)

ES2015 字符串拓展方法

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

console.log(
  message.startsWith('Error'),//是否以某些字符串开头
  message.endsWith('.'),//是否以某些字符串结尾
  message.includes('foo')//是否包含某些字符串
)

 

ES2015 函数形参新语法

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

foo("a")
  • 剩余参数 (...args)
//只能出现在最后一位,使用一次,表示之后的所有参数
function foo (first, ...args) {
  console.log(args)
}

foo(1, 2, 3, 4)
  • 展开数组 (...array)
const arr = ['foo', 'bar', 'baz']
console.log.apply(console, arr)//foo, bar, baz
console.log(...arr)//foo, bar, baz

ES2015 箭头函数

  • 简化代码
// 最简方式
const inc = n => n + 1

// 函数体多条语句,返回值仍需 return
const inc = (n, m) => {
  console.log('inc invoked')
  return n + 1
}

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

const person = {
  name: 'tom',
  // sayHi: function () {
  //   console.log(`hi, my name is ${this.name}`)//this指向person对象
  // }
  sayHi: () => {
    console.log(`hi, my name is ${this.name}`)//this指向sayHi这个方法
  },
  sayHiAsync: function () {
    // const _this = this//es6之前改变this指向
    // setTimeout(function () {
    //   console.log(_this.name)
    // }, 1000)

    console.log(this)
    setTimeout(() => {
      // console.log(this.name)//this指向sayHiAsync函数
      console.log(this)
    }, 1000)
  }
}

person.sayHiAsync()

 ES2015 对象字面量的增强

const bar = '345'
const obj = {
  foo:123,
  // bar:bar, 等价于下面的
  bar,//属性名和属性值相同的,可以只写属性名
  // method1:function(){
  //   console.log('method1')
  // },
  method1(){//方法可以省略“:function”
    console.log('method1');
    console.log(this)
  },
  [1+1]:2,//计算属性名: 表达式执行结果将会变为属性名
}

 

ES2015 Object.assign

  • 将源对象合并到目标对象中,如有相同属性,则以源对象的为主
// Object.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
  •  使用场景
// 应用场景

function func (obj) {
  // obj.name = 'func obj'//在内部直接修改obj对象属性值则会影响到外部的obj对象
  // console.log(obj)

  const funcObj = Object.assign({}, obj)//为了不影响外部的obj对象,就可以用assign生成新的对象
  funcObj.name = 'func obj'
  console.log(funcObj)
}

const obj = { name: 'global obj' }

func(obj)
console.log(obj)

 ES2015 Object.is

  • 判断两个值是否相等(很少使用)
// 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
)

 ES2015 Proxy

  • 代理,比Object.defineProperty更高级,用来监视属性的读写,Vue3中已经开始用到
// Proxy 对象

const person = {
  name: 'zce',
  age: 20
}
//Proxy第一个参数是目标对象,第二个参数是一个对象,具备get,set方法
const personProxy = new Proxy(person, {
  // get监视属性读取
  get (target, property) {
    return property in target ? target[property] : 'default'
    // console.log(target, property)
    // return 100
  },
  // set监视属性设置
  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)

打印内容

  • 比较Object.DefineProperty和Proxy

1. Proxy相对而言功能更强大,例如可以监视对象的delete操作

// 优势1:Proxy 可以监视读写以外的操作 --------------------------
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)

还有其他方法

2. 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)
listProxy.push(100)

注意,监听的是下标和对应的值

3. Proxy不需要侵入对象,Object.defineProperty使用的时候需要拆解对象本身,去对每个属性进行读写,Proxy不需要对对象进行多于拆解(此处是自己的理解)

 

 ES2015 Reflect

  • Reflect 内部封装了一系列对对象的底层操作
  • 无法使用 new 关键字 是一个静态类
  • 对 Proxy 处理对象的方法的默认实现
  • 统一提供一套用于操作对象的API
// Reflect 对象

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

const proxy = new Proxy(obj, {
  get (target, property) {
    console.log('watch logic~')
    //返回reflect的方法
    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))
//现在统一可以用reflect
console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))

 

ES2015 Class

  • 创建class
// class 关键词

function Person (name) {
  this.name = name
}
//以前是通过原型链去添加方法
Person.prototype.say = function () {
  console.log(`hi, my name is ${this.name}`)
}

class Person1 {
  constructor (name) {
    this.name = name
  }
  
  //直接添加方法
  say () {
    console.log(`hi, my name is ${this.name}`)
  }
}
//通过new的方式构造实例对象
const p = new Person1('tom')
p.say()
  • 实例方法VS静态方法

实例方法就是通过类构造实例对象去调用,静态方法直接通过这个类去调用,ES6中用static来写静态方法

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

  say(){
    console.log(`hi,my name is ${this.name}`);
  }
 //静态方法this返回当前类,并不会指向某个实例对象
  static create(name){
    return new Person(name)
  }
}

const tom = Person.create('tom')
tom.say();
  • extends(继承)

// extends 继承

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

 

ES2015 Map

和Object对象一样的键值对结构,对象键是string类型,但是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)

具备set.get.clear.delete等方法

 

ES2015 Symbol函数

  • 为对象添加一个独一无二的属性标识符
// 场景1:扩展对象,属性名冲突问题

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

// 两个 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 objects = {
  [Symbol()]: 123
}
console.log(objects)

// 案例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为对象添加了唯一属性名, 所以一般的循环拿不到这个属性名,Object.getOwnPropertySymbols才可以拿到

const obj = {
  [Symbol()]: 'symbol value',
  foo: 'normal value'
}

for (var key in obj) {
  console.log(key)//foo
}
console.log(Object.keys(obj))//[ 'foo' ]
console.log(JSON.stringify(obj))//{"foo":"normal value"}

//下面方法可以拿到
console.log(Object.getOwnPropertySymbols(obj))//[ Symbol() ]
  •  Symbol.for方法
console.log(
  Symbol() === Symbol(),
  Symbol('foo') === Symbol('foo')
)//false false

 

// 两个Symbol无法相等,但是可以用for方法来让处理后的值相等
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2)

console.log(//注意,这里接收的参数会转换成字符串,所以此处输出true
  Symbol.for(true) === Symbol.for('true')
)
  •  内置常量
//用Symbol常量标识内部方法
console.log(Symbol.iterator)//Symbol(Symbol.iterator)
console.log(Symbol.hasInstance)//Symbol(Symbol.hasInstance)
const obj1 = {}
console.log(obj1.toString())//[object Object]

const obj = {
  [Symbol.toStringTag]: 'XObject'
}
console.log(obj.toString())//[object XObject]

 ES2015 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 方法

  • 遍历 Set 与遍历数组相同

  •  遍历 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)
}

 

ES2015迭代器Iterator

  • 实现可迭代接口Iterable就是for...of能遍历的前提

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

也可以用while实现

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

  • 实现Iterator
const obj = {
  store: ['foo', 'bar', 'baz'],

  [Symbol.iterator]: function () {
    let index = 0
    const self = this

    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 生成器

  • 异步编程中减少回调嵌套
  • 惰性执行,和yield关键字一起用(迭代器模式),遇见yield关键字函数的执行就会暂停,直到下一次调用.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 暂停 
//1111   { value: 100, done: false }
console.log(generator.next()) // 第二次调用,从暂停位置继续,直到遇到下一个 yield 再次暂停
//2222   { value: 200, done: false }
console.log(generator.next()) // 。。。
console.log(generator.next()) 
// 第四次调用,已经没有需要执行的内容,{ value: undefined, done: true }
  • 应用
// Generator 应用

// 案例1:发号器

function * createIdMaker () {
  let id = 1
  while (true) {
    yield id++
  }
}

const idMaker = createIdMaker()

console.log(idMaker.next().value)//1
console.log(idMaker.next().value)//2
console.log(idMaker.next().value)//3
console.log(idMaker.next().value)//4

// 案例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)
}

 

ES2016 概述

  • Array.prototype.includes

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


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

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

 

ES2017 概述

  • Object.values

const obj = {
  foo: 'value1',
  bar: 'value2'
}
console.log(Object.values(obj))//[ 'value1', 'value2' ]
  • Object.entries

console.log(Object.entries(obj))//[ [ 'foo', 'value1' ], [ 'bar', 'value2' ] ]
//可以结合for...of遍历得到键,值
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value)
}
//foo value1   bar value2
  •  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.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`)
}

  • 在函数参数中添加尾逗号 

const arr = [
  100,
  200,
  300,
]
  • async/await promise语法糖
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值