ES6核心內容精講--快速實踐ES6(一)

前言

本文大量參考了阮一峯老師的開源教程ECMAScript6入門和MDN,適合新手入門或者對ES6經常使用知識點進行全面回顧,目標是以較少的篇幅涵蓋ES6及部分ES7在實踐中的絕大多數使用場景。更全面、更深刻的請進入上面的教程。若是您以爲有遺漏的常見知識點或者錯誤的地方,請評論指出!javascript

新的變量聲明方式let和const

是什麼:

新的變量聲明方式,提供變量的塊級做用域,同時經過一些限制來更防止咱們犯錯誤。也就是說是更好的聲明變量的方式vue

怎麼用

1)let/const與var的區別是提供了塊級做用域以及變量建立時不會當即初始化java

2)在同一個做用域內let/const禁止重複聲明相同的變量es6

var a = 1
let a = 2 // SyntaxError

3)let聲明的變量可從新賦值,const聲明的變量不能從新賦值,即常量。ajax

4)暫時性死區:在當前做用域,使用的變量已經存在,可是在代碼執行到變量聲明前禁止訪問。vuex

var tmp = 123

if (true) {
  tmp = 'abc' // ReferenceError
  let tmp
}

常見使用場景

1)由於能建立塊級做用域,因此常見於if和for中json

for (let i = 0; i < arr.length; i++) {
    console.log(arr[i])
}

2)const在實踐中經常使用來聲明一個對象,以後能夠再對這個對象的屬性進行修改數組

const foo = {
    name: 'bar'
}

foo.name = 'baz'

console.log(foo)

解構

是什麼:

按照阮一峯大神的說法:ES6容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。也就是說經過模式匹配來進行變量賦值。數據結構

怎麼用:

1)數組基本用法app

let [a, b, c] = [1, 2, 3]

a //1
b //2
c //3

2)對象基本用法

let { foo, bar } = { foo: "aaa", bar: "bbb" }
foo // "aaa"
bar // "bbb"

3)函數參數的解構賦值

如在vuex中action不使用解構以下:

actions: {
    increment (context) {
      context.commit('increment')
    }
}

使用解構

actions: {
    increment ({ commit }) {
      commit('increment')
    }
}

4)支持不徹底解構

let [foo, bar] = [1, 2, 3]

5)若是解構不成功,變量的值就等於undefined,同時解構賦值容許指定默認值,默認值生效的條件是對象的屬性值嚴格等於undefined。

常見使用場景

1)交換變量的值

[x, y] = [y, x]

2)提取JSON數據

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
}

let { id, status, data: number } = jsonData

console.log(id, status, number) // 42, "OK", [867, 5309]

3)函數參數的默認值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
}) {
  // ... do stuff
}

4)指定加載模塊的什麼功能

import { mapActions } from 'vuex'

箭頭函數

幹嗎的:

箭頭函數能夠用來替換函數表達式,不用寫function,更加簡化。也就是說是函數表達式的簡化方式

怎麼用:

1)注意箭頭函數中的this指向外層的this

2)沒法用call/apply/bind來改變this指向。

3)在ES6中,會默認採用嚴格模式,所以默認狀況下this不是指向window對象,而是undefined。

<script type="text/javascript">
    setTimeout(() => console.log(this), 1000) // undefined,不是window
</script>

4)不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用rest參數代替。

使用場景:

關鍵是你須要this指向什麼

默認參數和rest參數

是什麼:

默認參數就是設置參數默認值,rest參數(翻譯爲不具名參數,也叫作剩餘參數)是將傳入的未具名的參數做爲一個數組集合

怎麼用:

以下,默認參數給參數賦一個默認值,rest參數使用三個點(...)加數組集合名

function foo(arg1 = 1, ...restArg){
    console.log(arg1, restArg)
}

foo(undefined, 2, 3, 4) // 1, [2, 3, 4]

foo(2, 3, 4) // 2, [3, 4]

擴展運算符

是什麼:

同rest參數同樣,也是三個點。它比如rest參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。所以經常使用於函數調用。

常見使用場景:

1)合併數組

let newArr = [...arr1, ...arr2, ...arr3]

2)與解構賦值結合

// ES5
a = list[0], rest = list.slice(1)

// ES6
[a, ...rest] = list

3)將字符串轉爲數組

[...'test'] // [ "t", "e", "s", "t"]

對象擴展

語法變化

1)屬性簡寫,當對象的一個屬性名稱與本地變量名相同的時候,能夠省略冒號和值

var foo = 'bar'
var baz = {foo}
baz // {foo: "bar"}

2)屬性名錶達式,能夠在以對象字面量方式定義對象是使用表達式做爲屬性名

// ES5只能這樣
obj['a' + 'bc'] = 123 

// ES6還能這樣
let obj = {
  ['a' + 'bc']: 123
}

3)方法簡寫,省去:和function

const foo = {
  bar () {
    console.log('1')
  }
}

Object.is()

更好的判斷方法,與===的不一樣有兩點:一是+0不等於-0,二是NaN等於自身。

NaN === NaN // false
Object.is(NaN, NaN) // true

Object.assign()

1)Object.assign方法用於對象的合併,用法與jQuery和underscore的extend方法相似,並且一樣會改變target。

Object.assign(target, source1, source2)

2)只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)。

3)Object.assign方法實行的是淺拷貝,而不是深拷貝。

Object.setPrototypeOf

用來設置一個對象的prototype對象,返回參數對象自己

Object.setPrototypeOf(object, prototype)

Object.getPrototypeOf()

Object.getPrototypeOf方法能夠用來從子類上獲取父類。所以,可使用這個方法判斷,一個類是否繼承了另外一個類。參見下面類與繼承章節

遍歷

對象的每一個屬性都有一個描述對象(Descriptor),Object.getOwnPropertyDescriptor方法能夠獲取該屬性的描述對象。這個描述對象有value、writable、enumerable、configurable四大屬性。

ES5下面三個操做會忽略enumerable爲false的屬性。

  • for...in循環:只遍歷對象自身的和繼承的可枚舉的屬性
  • Object.keys():返回對象自身的全部可枚舉的屬性的鍵名
  • JSON.stringify():只串行化對象自身的可枚舉的屬性

ES6新增的操做Object.assign(),也會忽略enumerable爲false的屬性,只拷貝對象自身的可枚舉的屬性。

ES6一共有5種方法能夠遍歷對象的屬性。

(1)for...in

for...in循環遍歷對象自身的和繼承的可枚舉屬性(不含Symbol屬性)。

(2)Object.keys(obj)

Object.keys返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含Symbol屬性)。

(3)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一個數組,包含對象自身的全部屬性(不含Symbol屬性,可是包括不可枚舉屬性)。

(4)Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一個數組,包含對象自身的全部Symbol屬性。

(5)Reflect.ownKeys(obj)

Reflect.ownKeys返回一個數組,包含對象自身的全部屬性,無論屬性名是Symbol或字符串,也不論是否可枚舉。

以上的5種方法遍歷對象的屬性,都遵照一樣的屬性遍歷的次序規則。

  • 首先遍歷全部屬性名爲數值的屬性,按照數字排序。
  • 其次遍歷全部屬性名爲字符串的屬性,按照生成時間排序。
  • 最後遍歷全部屬性名爲Symbol值的屬性,按照生成時間排序。

大多數時候,咱們只關心對象自身的可枚舉屬性。因此,儘可能不要用for...in循環,而用Object.keys()代替。

字符串擴展

之前判斷一個字符串是否包含某個字符串只能經過indexOf的值是否大於-1來判斷,如今新增了三種方法:

includes():表示是否包含該字符串。

startsWith():表示該字符串是否在頭部。

endsWith():表示該字符串是否在尾部。

'hello world'.includes('hello') // true

模板字符串

幹嗎的:

和handlebars那些模板引擎功能相似,有模板字符串能夠不用拼接字符串了

怎麼用:

用反引號``將整個字符串包裹起來,${}表示一個變量或者一個表達式,能夠嵌套

const tmpl = addrs => `
  <table>
  ${addrs.map(addr => `
    <tr><td>${addr.first}</td></tr>
    <tr><td>${addr.last}</td></tr>
  `).join('')}
  </table>
`

const data = [
  { first: 'Jane', last: 'Bond' },
  { first: 'Lars', last: 'Croft' },
]

console.log(tmpl(data))

標籤模板

函數名後面緊接一個模板字符串。該函數將被調用來處理這個模板字符串。這被稱爲「標籤模板」功能(tagged template)。當字符串模板有變量時,函數的第一個參數爲被變量分開的字符串組成的數組,後面的參數依次爲變量,這些變量的參數序列可使用rest參數。

var a = 5
var b = 10

tag`Hello ${ a + b } world ${ a * b }`
// 等同於
tag(['Hello ', ' world ', ''], 15, 50)

數組擴展

Array.of()

Array.of方法用於將一組值,轉換爲數組。能夠替代Array,且其行爲很是統一,不像Array只有一個正整數參數n時,會生成n個空位構成的數組

Array.of(1) // [1]
Array.of(1, 2, 3) // [1, 2, 3]
Array(1) // [undefined * 1],其實不是undefined,是空位,以下可證實二者並不同
0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
Array(1, 2, 3) // [1, 2, 3]

Array.from()

Array.from方法用於將兩類對象轉爲真正的數組:類數組對象(array-like object)和可遍歷(iterable)對象(包括ES6新增的數據結構Set和Map)。Array.from還能夠接受第二個參數,做用相似於數組的map方法,用來對每一個元素進行處理,將處理後的值放入返回的數組。

Array.from({'0': 'a', length: 1}) // ['a']

Array.from('hello') // ['h', 'e', 'l', 'l', 'o'],由於字符串有Iterator接口,可遍歷

Array.from([1, 2, 3], (x) => x * x) // [1, 4, 9]

常見使用場景:

1)轉換NodeList集合。常見的相似數組的對象是DOM操做返回的NodeList集合,以及函數內部的arguments對象。可是後者使用rest參數更簡便

// NodeList對象
let elementDivList = document.querySelectorAll('div')
Array.from(elementDivList).forEach(function (div) {
  console.log(div)
})

2)數組去重。與下面要講到的Set配合便可很簡單地實現數值去重。

var arr = [1, 3, 5, 5, 8, 3, 2]
var uniqueArr = Array.from(new Set(arr))
console.log(uniqueArr) // [1, 3, 5, 8, 2]

數組實例的copyWithin方法

Array.prototype.copyWithin(target, start = 0, end = this.length)

它接受三個參數。

  • target(必需):從該位置開始替換數據。
  • start(可選):從該位置開始讀取數據,默認爲0。若是爲負值,表示倒數。
  • end(可選):到該位置前中止讀取數據,默認等於數組長度。若是爲負值,表示倒數。
[1, 2, 3, 4, 5].copyWithin(0,2) // [3, 4, 5, 4, 5]
    /* 從索引2開始讀取數據,到數組尾部中止,即讀到(3, 4, 5),而後從索引0開始替換數據 */

數組實例的find和findIndex方法

找到第一個符合條件的item(項)或index(索引),前者至關於underscore中的first方法,後者則和underscore中的同名方法一致。另外,這兩個方法均可以藉助Object.is發現NaN,彌補了數組的IndexOf方法的不足。

[1, 2, 3, 4].find(x => x > 2) // 3
[1, 2, 3, 4].findIndex(x => x > 2) // 2
[NaN].findIndex(x => Object.is(NaN, x)) // 0

數組實例的fill方法

Array.prototype.fill(fillItem, start = 0, end = this.length)

[1, 3, 6, 11, 4].fill(10,2) // [1, 3, 10, 10, 10]

數組實例的includes方法

與字符串的includes方法相似。該方法屬於ES7,但Babel轉碼器已經支持。

[1, 2, 3].includes(3, 3) // false
[1, 2, 3].includes(3, -1) // true
[NaN].includes(NaN) // true

Set和Map

ES6中增長了兩個新的數據結構:Set和Map。Set是不包含重複值的列表,而Map則是鍵與相對應的值的集合。

Set

是什麼:

Set是不包含重複值的有序列表。

怎麼用:

1)Set構造函數能夠接受一個數組(或相似數組的對象)做爲參數,用來初始化。

const set = new Set([1, 2, 3, 4, 4])
console.log(set)

2)四個操做方法(add()、delete()、has()、clear())和一個屬性(size),使用方法根據名字和下面例子就知道了

const s = new Set()
s.add(1).add(2).add(2) // 注意2被add了兩次

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2)
s.has(2) // false

s.add(3)
s.size // 2

s.clear()
s.size // 0

3)三個遍歷器生成函數(keys()、values()、entries())和一個遍歷方法(forEach())

keys方法、values方法、entries方法返回的都是遍歷器對象(詳見Iterator)。都這可使用遍歷器對象的方法for...of進行遍歷。因爲 Set 結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),因此keys方法和values方法的行爲徹底一致。forEach方法與ES5數組的forEach相似。

let set = new Set(['red', 'green', 'blue'])

for (let item of set.keys()) {
  console.log(item)
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item)
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item)
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

set.forEach((value, key) => console.log(value, key))

4)Set轉化爲數組,有兩種方法:...擴展運算符和Array.from()

這二者可互換,所以前面提到的使用Array.from()來數組去重也能夠這樣作:[...new Set(arr)]

// 方法一
let set = new Set([1, 2, 3])
set = new Set([...set].map(val => val * 2))
// set的值是2, 4, 6

// 方法二
let set = new Set([1, 2, 3])
set = new Set(Array.from(set, val => val * 2))
// set的值是2, 4, 6

Map

是什麼:

一種由鍵值對集合構成的數據結構,相似於對象,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

怎麼用:

1)Set構造函數能夠接收任何一個具備Iterator接口的數據結構做爲參數

const set = new Set([
  ['foo', 1],
  ['bar', 2]
])
const m1 = new Map(set)
m1.get('foo') // 1

2)5個操做方法(set(key, value)、get(key)、has(key)、delete(key)、clear())和一個屬性(size)

3)遍歷生成函數和遍歷方法和Set相似,Map結構的默認遍歷器接口(Symbol.iterator屬性),就是entries方法。

map[Symbol.iterator] === map.entries // true

4)Map轉爲數組,使用...擴展運算符

WeakSet和WeakMap

WeakSet、WeakMap分別和Set、Map相似,不過存儲的是對象的弱引用方式,這樣在內存管理上更加容易優化。

相關文章
相關標籤/搜索