ECMAScript新特性(es6 )(1-2-1)

首先要区分语言和平台之间的关系,语言自己是指ECMAScript,平台是指浏览器或者node,在平时咱们浏览器开发里js就是ECMAScript。
浏览器的组成部分
image.png
node.js的组成部分
image.png
在ES5.1以后版本咱们统称为ES6
image.png
主要说明以下:
**• let 和 const
• Arrow functions
• Classes(类)
• Generators
• Map 和 Set
• for ... of 循环
• Symbol
• Modules
• Template literals(模板字⾯量)
• Default parameters(默认参数)
• Enhanced object literals(对象字⾯量加强)
• Destructuring assignments(解构分配)
• Spread operator(展开操做符)
• Proxy和Reflect**前端

这些新增API和对象主要是进行:
**• 对原有语法进⾏加强
• 解决原有语法上的⼀些问题或者缺陷
• 全新的对象、全新的⽅法、全新的功能
• 全新的数据类型和数据结构**node

let和const

let 声明的成员只会在所声明的块中生效
if (true) {
let foo = 'zce'
console.log(foo)
}es6

let经典应用场景算法

var elements = [{}, {}, {}]
for (let i = 0; i < elements.length; i++) {
  elements[i].onclick = function () {
    console.log(i)
  }
}

由于产生本身的循环体的块级做用域,因此能够代替闭包。api

咱们看下面例子来解析一下运行
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)
}dom

i++

if (i < 3) {
let i = 'foo'
console.log(i)
}

i++
实际上是这样的,因此咱们也就能够解释在这其中for 循环会产生两层做用域。
let 还修复了变量声明提高现象。
const 总体和let相似,

  • 恒量声明事后不容许从新赋值
  • 恒量要求声明同时赋值

const name
name = 'zce' //会报错

  • 恒量只是要求内层指向不容许被修改
  • 对于对象数据成员的修改是没有问题的

Arrow functions

箭头函数的 简易写法,能够去看下阮一峰老师的es6,这里主要标明几个箭头函数的特征。

  • 箭头函数绑定父做用域的this
  • 箭头函数this不可修改
  • 箭头函数不能做为构造函数,不能使用new
  • 箭头函数没有arguments, caller, callee
  • 箭头函数没有原型属性//prototype 为undefined
  • 箭头函数在ES6 class中声明的方法为实例方法,不是原型方法
class Super{
    sayName =()=>{
        //do some thing here
    }
}

var a = new Super()
var b = new Super()
a.sayName === b.sayName //false

class

es6里实现class关键字,来代替es5里的构造函数的方式生成类。
es6的extends关键词来进行继承,底层是使用es5寄生组合式继承的封装。
使用extends来继承,constructor中使用this必需要先实例化父类,使用super关键词实例化,其余方法里也可经过super调用父类成员。

class里的constructor至关于es5的实例化,而后以外定义的属性函数,至关于定义在原型上(不包含箭头函数)

static关键词 静态属性,能够不实例化类可直接访问,里面的this指向类自己,不是实例化后的对象。

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

Generators

Generators函数调用会返回一个iterator对象,能够继续调用next()方法来依次返回Generators函数yield关键词以后的表达式结果,结果是个对象{value:'结果值',done:布尔值(是否结束true/false)},yield能够暂停当前函数,而后再经过外面iterator调用next方法继续往下走。

代码以下:

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)

Map和Set

Map

Map对象保存键值对。任何值(对象或者原始值) 均可以做为一个键或一个值。构造函数Map能够接受一个数组做为参数。

map和object区别

  • 一个Object 的键只能是字符串或者 Symbols,但一个Map 的键能够是任意值。
  • Map中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
  • Map的键值对个数能够从 size 属性获取,而 Object 的键值对个数只能手动计算。
  • Map支持for of 循环,obj须要本身添加Symbol.iterator

经常使用api

  • set(key, val): 向Map中添加新元素
  • get(key): 经过键值查找特定的数值并返回
  • has(key): 判断Map对象中是否有Key所对应的值,有返回true,不然返回false
  • delete(key): 经过键值从Map中移除对应的数据
  • clear(): 将这个Map中的全部元素删除
  • size:返回Map对象中所包含的键值对个数

遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每一个成员

map支持 for of 遍历,内部的Symbol.iterator是entries

Set

Set对象容许你存储任何类型的值,不管是原始值或者是对象引用。它相似于数组,可是成员的值都是惟一的,没有重复的值。

Set 自己是一个构造函数,用来生成Set 数据结构。Set函数能够接受一个数组(或者具备 iterable 接口(迭代器)的其余数据结构)做为参数,用来初始化(带有Symbol.iterator)。
Set 对象存储的值老是惟一的,因此须要判断两个值是否恒等。有几个特殊值须要特殊对待:

  • +0 与 -0 在存储判断惟一性的时候是恒等的,因此不重复
  • undefined 与 undefined 是恒等的,因此不重复
  • NaN 与 NaN 是不恒等的,可是在 Set 中认为NaN与NaN相等,全部只能存在一个,不重复。

set经常使用方法

  • add(value):添加某个值,返回 Set 结构自己(能够链式调用)。
  • delete(value):删除某个值,删除成功返回true,不然返回false
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除全部成员,没有返回值。
  • size:返回Set实例的成员总数。

遍历方法

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回键值对的遍历器。
  • forEach():使用回调函数遍历每一个成员。

因为Set结构没有键名,只有键值(或者说键名和键值是同一个值),因此keys方法和values方法的行为彻底一致。

for...of循环

for of 循环本意是统一 js中循环的标准,咱们查看可使用for of循环的对象,
image.png
解释:里面都有一个Symbol.iterator方法,这个of循环首先调用这个方法,它返回一个对象(而后就是循环对象),这个对象内部有next方法,方法返回一个对象{value:'值',done:布尔值//是否结束},每次循环就是调用这个next方法,等done为true的时候循环结束。
这是否是很像Generator函数,因此说Generator调用的结果也是能够用of循环的,好比map和set结构都有这个Symbol.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)
}

由于咱们看到 它和Generator函数很像,因此咱们用它辅助实现一下,
给[Symbol.iterator]定义一个生成器函数,返回一个可迭代对象,而后咱们使用 yield 函数来辅助实现,由于它返回的和咱们要的那个对象是同样的。

Symbol

symbol 是一种基本数据类型 (primitive data type)。Symbol()函数会返回symbol类型的值,该类型具备静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且相似于内建对象类,但做为构造函数来讲它并不完整,由于它不支持语法:"new Symbol()"。

每一个从Symbol()返回的symbol值都是惟一的。一个symbol值能做为对象属性的标识符;这是该数据类型仅有的目的。更进一步的解析见—— glossary entry for Symbol

使用场景:扩展对象,属性名冲突问题

通常使用第三方库扩展时,咱们预防覆盖方法名,可使用Symbol对象作key,由于两个 Symbol 永远不会相等。
因为没法建立出同样的 Symbol 值, 因此咱们能够用它建立「私有」成员

更多的方法能够查看mdn
Symbol

Modules

模块 es6中的import语句为变量,函数,和类建立的是只读绑定,标识符只有在导出的模块中能够修改,即便是导入绑定的模块也没法更改绑定的值。
一些简单的语法能够在mdn上查看
这里贴一个之前的异步模块

var me =(function hello(name){
    function greeting(){
        console.log('hello'+name)
    }
    return {//public API
        greeting:greeting
    }
})('kyle')
console.log(me.greeting())

Template literals(模板字⾯量)

// 反引号包裹
const str = hello es2015, this is a string
容许换行,能够经过${}插入表达式,返回得结果会输出到对应位置
xxx${...}xxx

**带标签的模板字符串,模板字符串的标签就是一个特殊的函数,
使用这个标签就是调用这个函数**

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)
hey, tom is a woman.

就是把字符串根据变量分割成一个数组,而后后续就是字符串中的变量依次传递.

Default parameters(默认参数)

在es5中给函数的默认参数只能

function foo (enable) {
  // 短路运算不少状况下是不适合判断默认参数的,例如 0 '' false null
  // enable = enable || true
  enable = enable === undefined ? true : enable
  console.log('foo invoked - enable: ')
  console.log(enable)
}

//这样去赋值如今es6中咱们能够

function foo (enable = true) {
  console.log('foo invoked - enable: ')
  console.log(enable)
}

//包括解构的时候能够 const {sex='默认'}=props;
甚至函数能够
function foo({sex='1'}={}){
    console.log(sex)
}

Enhanced object literals(对象字⾯量加强)

这一篇比较简单看代码把

// 对象字面量

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

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
)

Destructuring assignments(解构分配)和Spread operator(展开操做符)

数组的解构

const arr = [100, 200, 300]
const [foo, bar, baz] = arr;
能够直接这样去解构,对应下表0,1,2
若是不要前面的能够
[,,baz]
这样就是只取2位置得了

经典的排序算法 交换位置能够:
const [arr[1],arr[0]]=[arr[0],arr[1]]
而后展开操做符
const [foo, ...rest] = arr;
取第一个 参数以后全部的返回一个数组。
展开操做符只能放在最后。

取出来的值也能够给定默认值
例如
const [foo, bar, baz = 123, more = 'default value'] = arr;

对象的解构:
const obj = { name: 'zce', age: 18 }
const { name } = obj;
至关于{name:name}
能够这样去解构,包括对象当参数传递时也能够这样解构
而后也能够给定默认值,前面有例子。
这个解构变量名字的声明和正常声明相反,是在右边,以下

const { name: objName = 'jack' } = obj;
name是从obj解构出来的属性名,objName是咱们新的变量名来接收这个值,而且给了它一个默认值。

而后就是展开操做

const {name,...args}=obj;
image.png
不要在意这些报错
这个解构展开就是说,除了解构指明的属性名以外,剩余的属性组成一个新对象,用剩余参数名称接受。

Proxy和Reflect

代理对象proxy和defineProperty的对比
image.png

优点:

  1. Proxy 能够监视读写之外的操做
  2. Proxy 能够很方便的监视数组操做
  3. 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)

更多的api的使用方式能够在mdn中查看
Proxy的使用方式

Reflect 是一个内置的对象,它提供拦截 JavaScript 操做的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,所以它是不可构造的。

它提供了对对象的统一操做,以前对象的操做不统一,
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))

具体提供了哪些方法,也能够直接去mdn中查看
Reflect

该内容借鉴于 拉钩大前端训练营

相关文章
相关标签/搜索