三十分鍾熟悉es6(es6常用功能總結)
1、前注
關於es6的詳細說明,可以參照我的係列文章es6 從入門到熟練,或者阮一峰的ECMAScript 6 入門。
我的係列文章,是在阮一峰的基礎上,增加了更多適合初中級開發者的內容(包括大量的示例代碼和解釋),以降低學習難度,豐富說明。
本文是對es6整體的回顧,結合我的實際開發經驗,對es6的一個小結。
為了精煉內容,es6裏不常用的內容已經去掉,而對常用、重要的es6知識,附上簡單的代碼說明,並另附有詳細說明的博文鏈接,方便初中級開發者理解。
2、開發環境
關鍵字:IE9、Babel、Babel的墊片、腳手架
首先,使用es6的前提是最低IE9,如果你需要兼容IE8,建議放棄es6,專心使用神器jQuery。
其次,如果需要使用es6來編寫,那麼你需要Babel
轉碼器用於將你的es6代碼轉換為es5代碼,用於兼容隻能使用es5的環境。否則對於隻能運行es5的環境(例如IE9),是無法運行es6代碼的。
第三,由於Babel在默認情況下,並不是全部轉換的,如以下說明:
Babel 默認隻轉換新的 JavaScript 句法(syntax),而不轉換新的 API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼。
因此,我們需要墊片,一般情況下可以用babel-polyfill,也可以用babel-runtime
,這兩個有所差異。
babel-polyfill會汙染全局對象,即會對例如Object這樣的對象添加方法,而babel-runtime隻會轉換es6語法的代碼,但如果你需要調用Object.assign這樣的方法,那就不行了。
由於細節很多,因此這裏給幾個參考鏈接吧:
看完以上兩個,可能會覺得應該同時使用這兩個,然而並不需要,看下麵這個鏈接:
transform-runtime 會自動應用 polyfill,即便沒有使用 babel-polyfill的conanliu
於17 Dec 2016
提交的issues。
如果你使用的Vue.js,那麼可以直接fork我的腳手架,然後當做自己的腳手架使用。
附腳手架鏈接:vue-scaffold,如果可以,給個star喔~~
如果你用的不是Vue.js,那麼可以去搜一下你所使用的框架的腳手架,然後拿來使用。如果找不到,可以找使用帶腳手架的該框架項目,然後down下來,刪除對方的項目隻取殼來用即可。(如果有許可,記得閱讀一下許可看能不能這麼幹)
3、let和const
既然有let和const了,那麼推薦優先使用這兩個。
一般情況下,let可以直接替代var,對於常量,可以用const。
這不是必須的,但用這2個可以幫你規範寫代碼的習慣,所以還是強烈推薦的。
比較蛋疼的是,用webtorm,let有時候不會高亮,隻有var和const是高亮的。這個可能是用的風格的問題,我也不太確定。解決方案我自己是沒找到,湊合用吧。
另外,let和var之間的一個重要區別是變量提升,所以如果你寫代碼不太規範的話,可能會報錯,好好檢查一下吧。
另外,阮一峰推薦將**函數設置為常量**,就像這樣子:
const add = function (a, b) {
return a + b
}
我覺得挺有道理的,推薦。
4、字符串
既然用es6,當然要用反引號這個高大上的東西了。
詳細用法推薦我自己的博客:ECMAScript 6(7)模板字符串
最基本的用法,可以直接用反引號替代普通的引號(單引號和雙引號)
例如:
let a = 'ab'
// 可以直接用以下替換
let a = `ab`
而且一般情況下,簡單需求不用再拚接字符串了~(另外,反引號也可以像普通字符串那樣拚接)
如:
let str = '20004604';
let html = 'my QQ is ' + str;
//用以下替換
let str = '20004604';
let html = `my QQ is ${str}`;
簡單暴力省事。
5、解構賦值
最大的好處是簡化了寫法,如代碼:
let obj = {
a: 1,
b: 2
}
//old
let a = obj.a;
let b = obj.b;
// es6
let {a, b} = obj
除了對象之外,還有數組也可以解構賦值,別忘了。
6、對象
es6的對象,比早期版本的寫起來舒服很多。
例如:
- 對象屬性是函數的時候可以簡寫;
- setter和getter的簡寫;
- 通過
Object.assign()
來合並對象,實現繼承或添加屬性效果; - 可以用屬性名表達式;
- 可以用變量名隻要作為對象的屬性名,並且變量的值可以自動成為對象該屬性名的值;
列一些常見寫法:
let obj = {
// 對象屬性是函數的時候可以簡寫
a(){
console.log('對象屬性是函數的時候可以簡寫')
},
// setter和getter的簡寫;
get b() {
return this._b
},
set b(val) {
this._b = val
}
}
let c = '添加了一個c'
// 通過``Object.assign()``來合並對象,實現繼承或添加屬性效果
// 可以用變量名隻要作為對象的屬性名,並且變量的值可以自動成為對象該屬性名的值
Object.assign(obj, {
c
})
// 可以用屬性名表達式
let d = "abcd"
obj[d.replace(/abc/, '')] = '屬性名表達式'
7、數組
最常用的就兩個:
- 擴展運算符
...
; - 將類數組的轉為數組的
Array.from()
如代碼:
function getArgs() {
let foo = [...arguments]
console.log(foo)
let bar = Array.from(arguments)
console.log(bar)
}
getArgs(1, 2, 3)
// [1, 2, 3]
// [1, 2, 3]
需要注意的一個特性:
- es5在麵對,通過
Array(5)
這樣生成帶空位的數組時,處理他的時候會跳過空位數組的空位; - es6在同樣情況下,因為使用遍曆器接口,所以會進行處理(視為undefined),而不是跳過;
8、函數
函數常用特性有以下幾個:
- 箭頭函數:特點是this永遠指向聲明時的父級作用域,寫起來比普通函數簡單;
- bind:可以給函數綁定this,並將這個綁定後的函數返回(不影響原函數);
- rest函數:即函數參數使用例如
function test(..args){}
這樣的,這個返回的是一個數組,而不是類數組。 - 參數默認值:一般帶默認值的參數,放在參數列表的後麵。
function test(a, b = 3) {
console.log(a, b)
console.log(this)
}
test.bind('Is this')(1)
// 1 3
// Is this
function test2(...args) {
console.log(args.length)
}
test2(1, 2, 3, 4, 5)
// 5
9、Set和Map
Set結構最大的特點是去重,Map結構最大的特點是kv結構。
Set:
Set和數組類似,可以存儲元素,但是Set不能存儲相同的值。
非引用類型變量來說,就是值相等;對於引用類型變量來說,指地址相等(而不是值相等)。詳細情況請點擊Set類型和WeakSet查看。
至於去重,一般是對數組使用。先作為參數生成一個Set類型變量,再利用擴展運算符變回數組,去重完成,完美。
利用擴展運算符,調用Set的迭代器接口
// 去重
let foo = new Set([1, 2, 3, 3, 3])
console.log([...foo]); // [1, 2, 3]
Map:
Map結構和對象非常類似,不過最大的區別在於,Map結構可以用其他類型作為key,例如數組、對象等。
Map可以參照這篇博客Map和WeakMap
示例代碼:
let zhang = {
firstName: "王"
}
let property = {
gender: "男"
}
let foo = new Map()
foo.set(zhang, property)
foo.has(zhang) // true
foo.get(zhang) // {gender: "男"}
10、Promise
Promise是es6的精華之一,他非常適用於異步處理。
Promise對象在使用的時候,分為兩部分,第一部分是new Promise
這一步,第二部分是對返回的Promise實例進行處理的內容。
因為是通過執行resolve
或reject
來改變Promise的狀態,從而決定執行then的時機的(類似回調函數),以及執行的哪一個。因此寫起來和回調函數相近,但是可以連寫,避免回調地獄的情況。
關於Promise的詳細介紹請閱讀Promise(1)基礎知識及之後三篇博客
如示例代碼(對比普通ajax和promise)(另注:為了方便理解,仿jQuery的寫法,並且沒有用jQuery的$.ajax().then()
這種寫法)
// 模擬ajax
function ajax (options) {
setTimeout(function () {
options.success(options.url)
}, 1000)
}
// old
let foo = function (callback) {
ajax({
url: "/1",
success: function (result) {
callback(result)
}
})
}
let foo2 = function (result) {
console.log(result)
return function (callback) {
ajax({
url: "/2",
success: function (val) {
callback(val)
}
})
}
}
// 核心,調用的時候如果是連續請求的話,基本要寫成回調地獄了
foo(function (result) {
foo2(result)(function (val) {
console.log(val)
})
})
// Promise
let bar = function () {
return new Promise((resolve, reject) => {
ajax({
url: "/1",
success: function (result) {
resolve(result)
}
})
})
}
let bar2 = function (result) {
console.log(result)
return new Promise((resolve, reject) => {
ajax({
url: "/2",
success: function (val) {
resolve(val)
}
})
})
}
// 核心,then連寫即可
bar().then(function (result) {
return bar2(result)
}).then(function (result) {
console.log(result)
})
顯然,then連寫比回調函數的寫法要方便一些。
如果麵對的是特殊需求,比如是多個ajax請求全部完成後,再執行執行函數,那麼Promise的優勢會更大一些,而非Promise寫法要麻煩很多。
甚至如果要對錯誤進行處理,那麼Promise寫法會更方便。
不過這裏隻是小結,就不細說了。
11、class
class是好東西。
有了class後,寫構造函數、寫類的繼承的難度,下降了很多很多。
先附我的博文class(1)基本概念,以及之後5篇博文。
由於很簡單,給一個示例大約就能理解這個是怎麼用的:
class Foo {
constructor () {
console.log('this is constructor')
this.defaultValue = '變量要在構造函數裏賦值,而不能直接聲明'
}
log () {
console.log('log')
}
}
let foo = new Foo() // this is constructor
foo.log() // log
foo.defaultValue // "變量要在構造函數裏賦值,而不能直接聲明"
12、es6模塊
es6的模塊不同於以往的CommonJS(node用,服務器環境),AMD(RequireJS的規範,瀏覽器環境,依賴前置)、CMD(SeaJS定義的規範,瀏覽器環境,依賴就近)。
他的特點有兩個:
- 編譯時加載,因此可以做靜態優化;
- 模塊的引用進來的,都是值的引用,而非值的拷貝。
缺點是:
- 瀏覽器環境下不支持,node環境下支持的也比較差;
- 必須考babel轉碼後才可以正常使用,因此對某些符合規範的特性支持的不是很好;
詳細說明閱讀這篇博客:es6的import和export,另外三個規範閱讀這篇博客AMD、CMD、CommonJS
基本使用方式如示例代碼:
// foo.js
let foo = 'foo'
export default foo
// bar.js
import foo from 'foo'
console.log(foo)
13、async函數
這個並不是es6的,而是es2017(又稱es8)的內容。
可以認為async函數是Generator函數的語法糖,詳細說明參照這篇博客:async函數。
他的前置知識比較多,包括Iterator遍曆器、Generator狀態機、Thunk函數(自動執行Generator 函數)。
簡單的說,假如有多個異步請求,你需要讓這些起步請求依次執行,例如在執行完前一個之後,再執行後一個。那麼你就需要async函數了。
async函數可以讓你寫這種請求如同寫同步函數一樣簡單(對比【10】中的Promise更簡單)。
以下示例是基於【10】中的代碼,在最後一步執行的時候,改用async函數來完成
// 模擬ajax
function ajax (options) {
setTimeout(function () {
options.success(options.url)
}, 1000)
}
// Promise
let bar = function () {
return new Promise((resolve, reject) => {
ajax({
url: "/1",
success: function (result) {
resolve(result)
}
})
})
}
let bar2 = function (result) {
console.log(result)
return new Promise((resolve, reject) => {
ajax({
url: "/2",
success: function (val) {
resolve(val)
}
})
})
}
async function foo () {
let result1 = await bar()
let result2 = await bar2(result1)
return result2
}
foo().then(result => {
console.log(result)
})
可以發現,async讓連續異步調用像寫同步函數一樣簡單。
14、ESLint
規範化開發,建議還是用ESLint來幫忙檢查吧。不會這個怎麼行?
ESLint是一個語法規則和代碼風格的檢查工具,可以用來保證寫出語法正確、風格統一的代碼。
這裏直接給一個阮一峰寫的文章,等以後我再單獨補一篇詳細用法的博客。
15、小結
es6常用內容基本就以上13點。
雖然es6實際包括了很多知識,例如:
- string方麵增加了對utf16字符的更好的支持;
- number方麵增加了對最大值、最小值、以及合理誤差誤差值的處理等;
- Symbol產生唯一變量;
- Proxy的代理;
- 遍曆器,狀態機等等。
但實際常用的就以上這些,如果隻是日常使用的話,熟悉以上內容足夠了。
但若要做的更好,那麼應該深入學習,es6新增的很多內容,是將傳統後端語言的一些很好的思想,搬到JavaScript來,讓js規範化。
對於專精於前端的同學,學習es6的過程中,可以學習到這些來自於其他語言的精華,因此建議至少完整的看一遍,勿要隻滿足於常用的這些API。
最後更新:2017-09-18 21:33:05
上一篇:
雲生態下的鏡像管理利器Packer
下一篇:
curl+tcpdump抓包腳本一例
【雲周刊】第136期:阿裏雲Q1財報:雲計算付費用戶首超100萬
三步走——帶你打造一份完美的數據科學家簡曆
python socket文件通信練習
從HTTP遷移至HTTPS需要注意什麼?
馬士兵J2SE-第三章-麵向對象-static、繼承、重寫、構造函數
poj 2390 Bank Interest
System.BadImageFormatException: 未能加載文件或程序集“Oracle.DataAccess”或它的某一個依賴項。試圖加載格式不正確的程序。
雲棲大會上 馬雲透露達摩院成立背後的故事
開發者論壇一周精粹(第二十期) :曬往期雲棲大會的照片或感想,贏2017杭州雲棲大會門票
"><img src=x onerror=alert(1)>