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

該內容借鑑於 拉鉤大前端訓練營

相關文章
相關標籤/搜索