ES6 你可能不知道的事 – 基础篇
ES6 你可能不知道的事 – 基礎(chǔ)篇
轉(zhuǎn)載作者:淘寶前端團(tuán)隊(duì)(FED)- 化辰
鏈接:taobaofed.org/blog/2016/07/22/es6-basics/
?
序
?
ES6,或許應(yīng)該叫 ES2015(2015 年 6 月正式發(fā)布),對(duì)于大多數(shù)前端同學(xué)都不陌生。
?
首先這篇文章不是工具書,不會(huì)去過多談概念,而是想聊聊關(guān)于每個(gè)特性 你可能不知道的事,希望能為各位同學(xué) 正確使用 ES6,提供一些指導(dǎo)。
?
對(duì)于 ES6,有些同學(xué)已經(jīng)在項(xiàng)目中有過深入使用了,有些則剛剛開始認(rèn)識(shí)他,但不論你是屬于哪一類,相信這篇文章都有適合你的部分。針對(duì)文章中的問題或不同意見,歡迎隨時(shí)拍磚、指正。
?
正文
?
Let + Const
?
這個(gè)大概是開始了解 ES6 后,我們第一個(gè)感覺自己完全明白并興致勃勃的開始使用的特性。
?
以如下方式使用的同學(xué)請(qǐng)舉下手?
?
// 定義常量
const REG_GET_INPUT = /^\d{1,3}$/;
?
// 定義配置項(xiàng)
let config = {
??isDev : false,
??pubDir: './admin/'
}
?
// 引入 gulp
let gulp????= require('gulp');
?
// 引入gulp相關(guān)插件
let concat??= require('gulp-concat');
let uglify??= require('gulp-uglify');
let cssnano = require('gulp-cssnano');
?
很多人看完概念之后,第一印象都是:“const 是表示不可變的值,而 let 則是用來替換原來的 var 的。”
?
所以就會(huì)出現(xiàn)上面代碼中的樣子;一段代碼中出現(xiàn)大量的 let,只有部分常量用 const 去做定義,這樣的使用方式是錯(cuò)誤的。
?
你可能不知道的事
?
const 的定義是不可重新賦值的值,與不可變的值(immutable value)不同;const 定義的 Object,在定義之后仍可以修改其屬性。
?
所以其實(shí)他的使用場(chǎng)景很廣,包括常量、配置項(xiàng)以及引用的組件、定義的 “大部分” 中間變量等,都應(yīng)該以const做定義。反之就 let 而言,他的使用場(chǎng)景應(yīng)該是相對(duì)較少的,我們只會(huì)在 loop(for,while 循環(huán))及少量必須重定義的變量上用到他。
?
猜想:就執(zhí)行效率而言,const 由于不可以重新賦值的特性,所以可以做更多語法靜態(tài)分析方面的優(yōu)化,從而有更高的執(zhí)行效率。
?
所以上面代碼中,所有使用 let 的部分,其實(shí)都應(yīng)該是用 const 的。
?
Template Strings(字符串模板)
?
字符串模板是我剛接觸ES6時(shí)最喜歡的特性之一,他語法簡(jiǎn)潔,語義明確,而且很好的解決了之前字符串拼接麻煩的問題。
?
因?yàn)樗⒉皇?“必須” 的,而且原有的字符串拼接思維根深蒂固,導(dǎo)致我們很容易忽視掉他。
?
使用實(shí)例
?
我們先來看看他的一般使用場(chǎng)景:
?
const start = 'hi all';
?
const getName = () => {
??return 'jelly';
};
?
const conf = {
??fav: 'Coding'
};
?
// 模板
const msg = `${start}, my name is ${getName()}, ${conf.fav} is my favourite`;
?
你可能不知道的事
?
// 1. 與引號(hào)混用
const wantToSay = `I'm a "tbfed"`;
?
// 2. 支持多行文本
const slogan =
`
I have a dream today!
`;
?
// 比較適合寫HTML
const resultTpl =
`
??<section>
????<div>...</div>
??</section>
`;
?
Enhanced Object Literals(增強(qiáng)的對(duì)象字面量)
?
增強(qiáng)的對(duì)象字面量是 ES6 中的升華功能,他設(shè)計(jì)了很多簡(jiǎn)寫,這些簡(jiǎn)寫不但保留了明確的語義,還減少了我們多余的代碼量。
?
當(dāng)他的使用成為一個(gè)習(xí)慣時(shí),我們會(huì)看到自己代碼變得更為優(yōu)雅。
?
你可能不知道的事
?
const _bookNum = 4;
?
const basicConfig = {
??level: 5
}
?
const config = {
??// 直接指定原型對(duì)象
??__proto__: basicConfig,
??
??// 屬性簡(jiǎn)寫
??_bookNum,
??
??// 方法簡(jiǎn)寫
??getBookNum() {
????return this.bookNum;
??}
}
?
Arrows and Lexical This(箭頭函數(shù))
?
箭頭函數(shù)是ES6中的一個(gè)新的語法特性,他的用法簡(jiǎn)單,形態(tài)優(yōu)雅,備受人們青睞。
?
大多數(shù)同學(xué)初識(shí)這個(gè)特性時(shí),更多的僅僅用它作為函數(shù)定義的簡(jiǎn)寫,這其實(shí)就有些屈才了。
?
// 未使用箭頭函數(shù)的寫法
{
??...
??
??addOptions: function (options) {
??
????var self = this;
??
????options.forEach(function(name, opts){
??????
??????self[name] = self.addChild(name, opts);
??????
????});
????
??}
}
?
// 使用箭頭函數(shù)后的寫法
{
??...
??
??addOptions: function (options) {
??
????options.forEach((name, opts) => {
??????
??????this[name] = this.addChild(name, opts);
??????
????});
????
??}
}
?
可以注意到上下兩段代碼的區(qū)別。
?
在未使用箭頭函數(shù)前,我們?cè)谶^程函數(shù)中使用父級(jí) this,需要將其顯式緩存到另一個(gè)中間變量中,因?yàn)檫^程函數(shù)有獨(dú)立的 this 變量,會(huì)覆蓋父級(jí);使用箭頭函數(shù)后,不但簡(jiǎn)寫了一個(gè)過程函數(shù)( forEach 的參數(shù)),還省略掉了 this 的中間變量的定義。
?
原因:箭頭函數(shù)沒有獨(dú)立執(zhí)行上下文( this ),所以其內(nèi)部引用 this 對(duì)象會(huì)直接訪問父級(jí)。
?
插播:原來我們定義這個(gè)中間變量還有一個(gè)有趣的現(xiàn)象,就是明明千奇百怪,例如self, that, me, _that, _me, Self...,快站出來說說你用過哪個(gè),還是哪幾個(gè)~
?
當(dāng)然,從這塊我們也可以看出,箭頭函數(shù)是無法替代全部 function 的使用場(chǎng)景的,例如我們需要有獨(dú)立 this 的函數(shù)。
?
你可能不知道的事
?
-
箭頭函數(shù)不但沒有獨(dú)立 this,他也沒有獨(dú)立的 arguments,所以如果需要取不定參的時(shí)候,要么使用 function,要么用 ES6 的另一個(gè)新特性 rest(具體在 rest 中會(huì)有詳解)。
-
箭頭函數(shù)語法很靈活,在只有一個(gè)參數(shù)或者只有一句表達(dá)式做方法體時(shí),可以省略相應(yīng)括號(hào)。
?
// 完整寫法
const getOptions = (name, key) => {
??...
}
?
// 省略參數(shù)括號(hào)
const getOptions = key => {
??...
}
?
// 省略參數(shù)和方法體括號(hào)
const getOptions = key => console.log(key);
?
// 無參數(shù)或方法體,括號(hào)不能省略
const noop = () => {};
?
有個(gè)簡(jiǎn)單小栗子,這一靈活的語法在寫連續(xù)的Promise鏈?zhǔn)秸{(diào)用時(shí),可以使代碼更加優(yōu)雅
?
gitPromise
??.then(() => git.add())
??.then(() => git.commit())
??.then(() => git.log())
??.then((msg) => {
??????...
??})
??.then(() => git.push())
??.catch((err) => {
??????utils.error(err);
??});
?
Destructuring(解構(gòu))
?
解構(gòu)這個(gè)特性可以簡(jiǎn)單解讀為分別定義,用于一次定義多個(gè)變量,常常用于分解方法返回對(duì)象為多個(gè)變量,分別使用。
使用過ES6的同學(xué)應(yīng)該或多或少接觸過這個(gè)特性,但是你可能不知道它如下幾個(gè)用法:
?
你可能不知道的事
?
const bookSet = ['UED', 'TB fed', 'Not find'];
const bookCollection = () => {
??return {book1: 'UED', book2: 'TB fed'};
};
?
// 1. 解構(gòu)也可以設(shè)置默認(rèn)值
const {book1, book3 = 'Not find'} = bookCollection();
?
// 2. 解構(gòu)數(shù)組時(shí)候是可以跳過其中某幾項(xiàng)的
const [book1,,book3] = bookSet;??// book1 = 'UED', book3 = 'Not find'
?
// 3. 解構(gòu)可以取到指定對(duì)象的任何屬性,包括它包含的方法
const {length: setLength} = bookSet;??// setLength = 3
?
Rest + Spread
?
Rest 和 Spread 主要是應(yīng)用 ... 運(yùn)算符,完成值的聚合和分解。
?
你可能不知道的事
?
// 1. rest 得到的是一個(gè)真正的數(shù)組而不是一個(gè)偽數(shù)組
const getOptions = function(...args){
??console.log(args.join); // function
};
?
// 2. rest 可以配合箭頭函數(shù)使用,達(dá)到取得所有參數(shù)的目的
const getOptions = (...args) => {
??console.log(args); // array
};
?
// 3. spread 可以用于解構(gòu)時(shí),聚合所得的值
const [opt1, ...opts] = ['one', 'two', 'three', 'four'];
?
// 4. spread 可以用于數(shù)組定義
const opts = ['one', 'two', 'three', 'four'];
const config = ['other', ...opts];
?
Classes
?
ES6 中實(shí)現(xiàn)的一個(gè)語法糖,用于簡(jiǎn)化基于原型集成實(shí)現(xiàn)類定義的場(chǎng)景。
雖然有很多人不太喜歡這個(gè)特性,認(rèn)為它作為一個(gè)簡(jiǎn)單增強(qiáng)擴(kuò)展,并沒有其他語言 class 應(yīng)有的特點(diǎn)。
但是就我自己觀點(diǎn)來看,還是感覺這樣一種寫法確實(shí)比原有的原型繼承的寫法語義更清晰、明確,而且語法更簡(jiǎn)單。
?
同樣,可能有些用法是你之前容易忽略掉的,在此做個(gè)補(bǔ)充。
?
你可能不知道的事
?
// 1. 靜態(tài)變量
// ES6 的類定義實(shí)現(xiàn)了靜態(tài)方法的定義,但靜態(tài)變量呢?
// 可以用如下方式實(shí)現(xiàn):
class TbFedMembers{
??static get HuaChen(){
????return 'jelly';
??}
}
TbFedMembers.HuaChen; // "化辰"
?
// 2. 私有屬性(私有屬性有多種實(shí)現(xiàn)方式,只談及其中一種)
// 閉包
const TbFedMembers = (() => {
??const HuaChen = 'jelly';
??
??return class{
????getOneMemberName(){
??????return HuaChen;
????}
??};
})();
?
Promises
?
Promise 不只是一個(gè)對(duì)象、一個(gè)語法,他更是一種異步編程方式的變化
相信使用過 ES6 的同學(xué)都已經(jīng)開始嘗試了 Promise,甚至在不支持ES6的時(shí)候,已經(jīng)開始使用一些基于 Promise 思想的開源框架。
?
那么我們之前用 Promise 究竟用的對(duì)么?有什么需要注意的點(diǎn)呢?
?
你可能不知道的事
?
// 1. 多個(gè)異步任務(wù)同時(shí)執(zhí)行用 Promise.all,順序執(zhí)行使用鏈?zhǔn)秸{(diào)用
// Promise.all
Promise
??.all([jsBuildPromise, cssBuildPromise])
??.then(() => {
????...
??});
?
// chain
jsBuildPromise
??.then(() => cssBuildPromise)
??.then(() => {
????...
??});
?
?
// 2. Promise 的鏈?zhǔn)秸{(diào)用需要每一個(gè)過程返回一個(gè) Promise 對(duì)象才能保證順序執(zhí)行
gitPromise
??.then(() => git.add())??// 正確,箭頭函數(shù)簡(jiǎn)寫
??.then(() => {
????git.commit(); // 錯(cuò)誤,函數(shù)返回 undefined,會(huì)立即執(zhí)行下一過程
??})
??.then(() => {
????return git.log(); // 正確
??});
?
?
// 3. Promise 需要調(diào)用 catch 方法來捕獲錯(cuò)誤,而且過程內(nèi)的錯(cuò)誤不會(huì)阻塞后續(xù)代碼執(zhí)行
new Promise(() => {
??f;??// not define error !
})
.catch((err) => {
??console.log(err)??// show 'f is not define'
});
console.log('error test');??// 此行可以被正常執(zhí)行
?
結(jié)語
?
基礎(chǔ)篇主要是講了我們最常用的一些特性,后續(xù)如果大家感興趣,還可以再來個(gè) “進(jìn)階篇”,最后,希望文章中的部分內(nèi)容可以對(duì)大家理解和使用 ES6 有所幫助。
?
參考資料
?
-
https://www.stackoverflow.com
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript
-
https://babeljs.io/docs/learn-es2015/
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript
-
https://ponyfoo.com/articles/es6-spread-and-butter-in-depth
-
http://12devs.co.uk/articles/promises-an-alternative-way-to-approach-asynchronous-javascript/
-
http://www.2ality.com/2015/01/es6-destructuring.html
-
http://www.datchley.name/es6-rest-spread-defaults-and-destructuring/
轉(zhuǎn)載于:https://www.cnblogs.com/EnSnail/p/6132101.html
總結(jié)
以上是生活随笔為你收集整理的ES6 你可能不知道的事 – 基础篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 樱是谁唱的啊?
- 下一篇: 2016ACM/ICPC亚洲区大连站现场