摘要:一共講解了個(gè)常用的新特性,講解過(guò)程也是由淺入深。最后一個(gè)新增的方法主要是為了彌補(bǔ)當(dāng)做構(gòu)造函數(shù)使用時(shí)產(chǎn)生的怪異結(jié)果。特性共享父級(jí)對(duì)象共享父級(jí)不能當(dāng)做構(gòu)造函數(shù)語(yǔ)法最簡(jiǎn)表達(dá)式前后對(duì)比很容易理解,可以明顯看出箭頭函數(shù)極大地減少了代碼量。
上周在公司組織了 ES6 新特性的分享會(huì),主要講了工程化簡(jiǎn)介、ES6 的新特性與前端常用的幾種構(gòu)建工具的配合使用。ES6 這塊主要講了一些我們平時(shí)開(kāi)發(fā)中經(jīng)常會(huì)用到的新特性。在這里整理一下關(guān)于 ES6 的部分。
一共講解了 8 個(gè)常用的 ES6 新特性,講解過(guò)程也是由淺入深。廢話(huà)不多說(shuō),下面進(jìn)入正文。
// Before function decimal(num, fix) { fix = fix === void(0) ? 2 : fix; return +num.toFixed(fix); }
// After function decimal(num, fix = 2) { return +num.toFixed(fix); }
首先,我們看一下之前我們是怎么寫(xiě)函數(shù)默認(rèn)值的:我們通常會(huì)使用三元運(yùn)算符來(lái)判斷入?yún)⑹欠裼兄?,然后決定是否使用默認(rèn)值運(yùn)行函數(shù)(如示例中 fix = fix === void(0) ? 2 : fix)
而在 ES6 中,我們可以直接在函數(shù)的顯示入?yún)⒅兄付ê瘮?shù)默認(rèn)值(function decimal(num, fix = 2){}),很明顯,這種寫(xiě)法更自然易懂,也更加方便,不過(guò)有一點(diǎn)需要注意:
設(shè)定了默認(rèn)值的入?yún)ⅲ瑧?yīng)該放在沒(méi)有設(shè)置默認(rèn)值的參數(shù)之后,也就是我們不應(yīng)該這樣寫(xiě):function decimal(fix = 2, num){},雖然通過(guò)變通手段也可以正常運(yùn)行,但不符合規(guī)范。
模板字符串 特性 & 語(yǔ)法// Before // Before.1 var type = "simple"; "This is a " + type + " string join." // Before.2 var type = "multiline"; "This is a " + type + " string." // Before.3 var type = "pretty singleline"; "This is a " + type + " string." // OR // Before.4 "This " + "is" + "a" + type + "string."
// After var type = "singleline"; `This is a ${type} string.` var type = "multiline"; `This is a ${type} string.` var type = "pretty singleline"; `This is a ${type} string.`
我們之前在對(duì)字符串和變量進(jìn)行拼接的時(shí)候,通常都是反復(fù)一段一段使用引號(hào)包裹的字符串,再反復(fù)使用加號(hào)進(jìn)行拼接(Before.1)。多行字符串的時(shí)候我們還要寫(xiě)上蹩腳的 來(lái)?yè)Q行以得到一個(gè)多行的字符串(Before.2)。
在字符串過(guò)長(zhǎng)的時(shí)候可能會(huì)使用 在編輯器中書(shū)寫(xiě)多行字符串來(lái)表示單行字符串,用來(lái)方便較長(zhǎng)的字符串在編輯器中的閱讀(Before.3),或者簡(jiǎn)單粗暴的反復(fù)引號(hào)加號(hào)這樣多行拼接(Before.4)。
ES6 中我們可以使用反引號(hào)(`,位于 TAB 上方)來(lái)輸入一段簡(jiǎn)單明了的多行字符串,還可以在字符串中通過(guò) ${變量名} 的形式方便地插入一個(gè)變量,是不是方便多了!
解構(gòu)賦值 數(shù)組解構(gòu)var [a, ,b] = [1, 2, 3, 4, 5]; console.log(a); // => 1 console.log(b); // => 3
數(shù)組解構(gòu),使用變量聲明關(guān)鍵字聲明一個(gè)形參數(shù)組([a, , b]),等號(hào)后跟一個(gè)待解構(gòu)目標(biāo)數(shù)組([1, 2, 3]),解構(gòu)時(shí)可以通過(guò)留空的方式跳過(guò)數(shù)組中間的個(gè)別元素,但是在形參數(shù)組中必須留有相應(yīng)空位才可以繼續(xù)解構(gòu)之后的元素,如果要跳過(guò)的元素處于數(shù)組末端,則在形參數(shù)組中可以不予留空。
對(duì)象解構(gòu)var {b, c} = {a: 1, b: 2, c: 3}; console.log(b); // => 2 console.log(c); // => 3
對(duì)象解構(gòu)與數(shù)組解構(gòu)大體相同,不過(guò)需要注意一點(diǎn)
形參對(duì)象({b, c})的屬性或方法名必須與待解構(gòu)的目標(biāo)對(duì)象中的屬性或方法名完全相同才能解構(gòu)到對(duì)應(yīng)的屬性或方法
對(duì)象匹配解構(gòu)var example = function() { return {a: 1, b: 2, c: 3}; } var {a: d, b: e, c: f} = example(); console.log(d, e, f); // => 1, 2, 3
對(duì)象匹配解構(gòu)是對(duì)象解構(gòu)的一種延伸用法,我們可以在形參對(duì)象中使用:來(lái)更改解構(gòu)后的變量名。
函數(shù)入?yún)⒔鈽?gòu)function example({param: value}) { return value; } console.log(example({param: 5})); // => 5
函數(shù)的入?yún)⒔鈽?gòu)也是對(duì)象解構(gòu)的一種延伸用法,我們可以通過(guò)改寫(xiě)入?yún)?duì)象目標(biāo)值為變量名的方式,在函數(shù)內(nèi)部直接獲取到入?yún)?duì)象中某個(gè)屬性或方法的值。
函數(shù)入?yún)⒛J(rèn)值解構(gòu)function example({x, y, z = 0}) { return x + y + z; } console.log(example({x: 1, y: 2})); // => 3 console.log(example({x: 1, y: 2, z: 3})); // => 6
這是入?yún)⒔鈽?gòu)的另一種用法,我們可以在入?yún)?duì)象的形參屬性或方法中使用等號(hào)的方式給入?yún)?duì)象的某些屬性或方法設(shè)定默認(rèn)值。
Let & Const Let無(wú)變量提升
// Before console.log(num); // => undefined var num = 1;
// After console.log(num); // => ReferenceError let num = 1;
使用 var 聲明的變量會(huì)自動(dòng)提升到當(dāng)前作用域的頂部,如果聲明位置與作用域頂部之間有另一個(gè)同名變量,很容易引起難以預(yù)知的錯(cuò)誤。使用 let 聲明的變量則不會(huì)進(jìn)行變成提升,規(guī)避了這個(gè)隱患。
注意:var 聲明的變量提升后雖然在聲明語(yǔ)句之前輸出為 undefined,但這并不代表 num 變量還沒(méi)有被聲明,此時(shí) num 變量已經(jīng)完成聲明并分配了相應(yīng)內(nèi)存,只不過(guò)該變量目前的值為 undefined,并不是我們聲明語(yǔ)句中賦的初始值 1。
有塊級(jí)作用域
// Before { var num = 1; console.log(num); // => 1 } console.log(num); // => 1
// After { let num = 1; console.log(num); // => 1 } console.log(num); // => ReferenceError
let 聲明的變量只能在當(dāng)前塊級(jí)作用域中使用,最常見(jiàn)的應(yīng)用大概就是 for(let i = 0, i < 10; i++) {},相信許多小伙伴在面試題中見(jiàn)過(guò),哈哈。
禁止重復(fù)聲明
// Before var dev = true; var dev = false; console.log(dev); // => false
// After let dev = true; let dev = false; // => SyntaxError
var 聲明的變量可以重復(fù)聲明,而且不會(huì)有任何警告或者提示,就這樣悄悄的覆蓋了一個(gè)值,隱患如變量提升一樣讓人擔(dān)憂(yōu)。( ̄┰ ̄*)
而 let 聲明的變量如果進(jìn)行重復(fù)聲明,則會(huì)直接拋出一個(gè)語(yǔ)法錯(cuò)誤(是的,就是直接明確地告訴你:你犯了一個(gè)相當(dāng)?shù)图?jí)的語(yǔ)法錯(cuò)誤哦)
Const無(wú)變量提升
有塊級(jí)作用域
禁止重復(fù)聲明
前 3 點(diǎn)跟 let 一個(gè)套路,就不多說(shuō)了
禁止重復(fù)賦值
const DEV = true; DEV = false; // => TypeError
基于靜態(tài)常量的定義我們可以很明顯知道,const 聲明的常量一經(jīng)聲明便不能再更改其值,無(wú)需多說(shuō)。
必須附初始值
const DEV; // => SyntaxError
也是基于定義,const 聲明的常量既然一經(jīng)聲明便不能再更改其值,那聲明的時(shí)候沒(méi)有附初始值顯然是不合理的,一個(gè)沒(méi)有任何值的常量是沒(méi)有意義的,浪費(fèi)內(nèi)存。
新增庫(kù)函數(shù)ES6 新增了許多(相當(dāng)多)的庫(kù)函數(shù),這里只介紹一些比較常用的。
Number題外話(huà):多了解一下內(nèi)建函數(shù)與方法有時(shí)候可以很方便高效地解決問(wèn)題。有時(shí)候絞盡腦汁寫(xiě)好的一個(gè)算法,沒(méi)準(zhǔn)已經(jīng)有內(nèi)建函數(shù)實(shí)現(xiàn)了!而且內(nèi)建函數(shù)經(jīng)過(guò)四海八荒眾神的考驗(yàn),性能一定不錯(cuò),哈哈。
Number.EPSILON Number.isInteger(Infinity); // => false Number.isNaN("NaN"); // => false
首先是 ? 這個(gè)常量屬性,表示小數(shù)的極小值,主要用來(lái)判斷浮點(diǎn)數(shù)計(jì)算是否精確,如果計(jì)算誤差小于該閾值,則可以認(rèn)為計(jì)算結(jié)果是正確的。
然后是 isInteger() 這個(gè)方法用來(lái)判斷一個(gè)數(shù)是否為整數(shù),返回布爾值。
最后是 isNaN() 用來(lái)判斷入?yún)⑹欠駷?NaN。是的,我們?cè)僖膊挥猛ㄟ^(guò) NaN 不等于 NaN 才能確定一個(gè) NaN 就是 NaN 這種反人類(lèi)的邏輯來(lái)判斷一個(gè) NaN 值了!
if(NaN !== NaN) { console.log("Yes! This is actually the NaN!"); }
另外還有兩個(gè)小改動(dòng):兩個(gè)全局函數(shù) parseInt() 與 parseFloat() 被移植到 Number 中,入?yún)⒎磪⒈3植蛔儭_@樣所有數(shù)字處理相關(guān)的都在 Number 對(duì)象上嘞!規(guī)范多了。
String"abcde".includes("cd"); // => true "abc".repeat(3); // => "abcabcabc" "abc".startsWith("a"); // => true "abc".endsWith("c"); // => true
inclueds() 方法用來(lái)判斷一個(gè)字符串中是否存在指定字符串
repeat() 方法用來(lái)重復(fù)一個(gè)字符串生成一個(gè)新的字符串
startsWith() 方法用來(lái)判斷一個(gè)字符串是否以指定字符串開(kāi)頭,可以傳入一個(gè)整數(shù)作為第二個(gè)參數(shù),用來(lái)設(shè)置查找的起點(diǎn),默認(rèn)為 0,即從字符串第一位開(kāi)始查找
endsWith() 與 startsWith() 方法相反
ArrayArray.from(document.querySelectorAll("*")); // => returns a real array. [0, 0, 0].fill(7, 1); // => [0, 7, 7] [1, 2, 3].findIndex(function(x) { return x === 2; }); // => 1 ["a", "b", "c"].entries(); // => Iterator [0: "a"], [1: "b"], [2: "c"] ["a", "b", "c"].keys(); // => Iterator 0, 1, 2 ["a", "b", "c"].values(); // => Iterator "a", "b", "c" // Before new Array(); // => [] new Array(4); // => [,,,] new Array(4, 5, 6); // => [4, 5, 6] // After Array.of(); // => [] Array.of(4); // => [4] Array.of(4, 5, 6); // => [4, 5, 6]
首先是 from() 方法,該方法可以將一個(gè)類(lèi)數(shù)組對(duì)象轉(zhuǎn)換成一個(gè)真正的數(shù)組。還記得我們之前常寫(xiě)的 Array.prototype.slice.call(arguments) 嗎?現(xiàn)在可以跟他說(shuō)拜拜了~
之后的 fill() 方法,用來(lái)填充一個(gè)數(shù)組,第一個(gè)參數(shù)為將要被填充到數(shù)組中的值,可選第二個(gè)參數(shù)為填充起始索引(默認(rèn)為 0),可選第三參數(shù)為填充終止索引(默認(rèn)填充到數(shù)組末端)。
findIndex() 用來(lái)查找指定元素的索引值,入?yún)楹瘮?shù),函數(shù)形參跟 map() 方法一致,不多說(shuō)。最終輸出符合該條件的元素的索引值。
entries()、keys()、values() 三個(gè)方法各自返回對(duì)應(yīng)鍵值對(duì)、鍵、值的遍歷器,可供循環(huán)結(jié)構(gòu)使用。
最后一個(gè)新增的 of() 方法主要是為了彌補(bǔ) Array 當(dāng)做構(gòu)造函數(shù)使用時(shí)產(chǎn)生的怪異結(jié)果。
Objectlet target = { a: 1, b: 3 }; let source = { b: 2, c: 3 }; Object.assign(target, source); // => { a: 1, b: 2, c: 3}
assign() 方法用于合并兩個(gè)對(duì)象,不過(guò)需要注意的是這種合并是淺拷貝??赡芸吹竭@個(gè)方法我們還比較陌生,不過(guò)了解過(guò) jQuery 源碼的應(yīng)該知道 $.extend() 這個(gè)方法,例如在下面這個(gè)粗糙的 $.ajax() 模型中的應(yīng)用:
$.ajax = function(opts) { var defaultOpts = { method: "GET", async: true, //... }; opts = $.extend(defaultOpts, opts); }
從這我們可以看到 TC39 也是在慢慢吸收百家所長(zhǎng),努力讓 JavaScript 變得更好,更方便開(kāi)發(fā)者的使用。
MathObject 新增的特性當(dāng)然不止這一個(gè) assign() 方法,一共增加了十多個(gè)新特性,特別是對(duì)屬性或方法名字面量定義的增強(qiáng)方面,很值得一看,感興趣的自行查找資料進(jìn)行了解哈,印象會(huì)更深刻!
Math 對(duì)象上同樣增加了許多新特性,大部分都是數(shù)學(xué)計(jì)算方法,這里只介紹兩個(gè)常用的
Math.sign(5); // => +1 Math.sign(0); // => 0 Math.sign(-5); // => -1 Math.trunc(4.1); // => 4 Math.trunc(-4.1); // => -4
sign() 方法用來(lái)判斷一個(gè)函數(shù)的正負(fù),使用與對(duì)應(yīng)返回值如上。
trunc() 用來(lái)取數(shù)值的整數(shù)部分,我們之前可能經(jīng)常使用 floor() 方法進(jìn)行取整操作,不過(guò)這個(gè)方法有一個(gè)問(wèn)題就是:它本身是向下取整,當(dāng)被取整值為正數(shù)的時(shí)候計(jì)算結(jié)果完全 OK,但是當(dāng)被取整值為負(fù)數(shù)的時(shí)候:
Math.floor(-4.1); // => -5
箭頭函數(shù)插播一個(gè)小 Tip:使用位操作符也可以很方便的進(jìn)行取整操作,例如:~~3.14 or 3.14 | 0,也許這更加方便 : )
箭頭函數(shù)無(wú)疑是 ES6 中一個(gè)相當(dāng)重要的新特性。
特性共享父級(jí) this 對(duì)象
共享父級(jí) arguments
不能當(dāng)做構(gòu)造函數(shù)
語(yǔ)法var arr = [1, 2, 3, 4, 5, 6]; // Before arr.filter(function(v) { return v > 3; }); // After arr.filter(v => v > 3); // => [4, 5, 6]
前后對(duì)比很容易理解,可以明顯看出箭頭函數(shù)極大地減少了代碼量。
var arr = [1, 2, 3, 4, 5, 6]; arr.map((v, k, thisArr) => { return thisArr.reverse()[k] * v; }) // => [6, 10, 12, 12, 10, 6]
一個(gè)簡(jiǎn)單的首尾相乘的算法,對(duì)比最簡(jiǎn)表達(dá)式我們可以發(fā)現(xiàn),函數(shù)的前邊都省略了 function 關(guān)鍵字,但是多個(gè)入?yún)r(shí)需用括號(hào)包裹入?yún)?,單個(gè)入?yún)⑹菚r(shí)可省略括號(hào),入?yún)?xiě)法保持一致。后面使用胖箭頭 => 連接函數(shù)名與函數(shù)體,函數(shù)體的寫(xiě)法保持不變。
// Before var obj = { arr: [1, 2, 3, 4, 5, 6], getMaxPow2: function() { var that = this, getMax = function() { return Math.max.apply({}, that.arr); }; return Math.pow(getMax(), 2); } } // After var obj = { arr: [1, 2, 3, 4, 5, 6], getMaxPow2: function() { var getMax = () => { return Math.max.apply({}, this.arr); } return Math.pow(getMax(), 2); } }
注意看中第 5 行 var that = this 這里聲明的一個(gè)臨時(shí)變量 that。在對(duì)象或者原型鏈中,我們以前經(jīng)常會(huì)寫(xiě)這樣一個(gè)臨時(shí)變量,或 that 或 _this,諸如此類(lèi),以達(dá)到在一個(gè)函數(shù)內(nèi)部訪(fǎng)問(wèn)到父級(jí)或者祖先級(jí) this 對(duì)象的目的。
如今在箭頭函數(shù)中,函數(shù)體內(nèi)部沒(méi)有自己的 this,默認(rèn)在其內(nèi)部調(diào)用 this 的時(shí)候,會(huì)自動(dòng)查找其父級(jí)上下文的 this 對(duì)象(如果父級(jí)同樣是箭頭函數(shù),則會(huì)按照作用域鏈繼續(xù)向上查找),這無(wú)疑方便了許多,我們無(wú)需在多余地聲明一個(gè)臨時(shí)變量來(lái)做這件事了。
注意:
某些情況下我們可能需要函數(shù)有自己的 this,例如 DOM 事件綁定時(shí)事件回調(diào)函數(shù)中,我們往往需要使用 this 來(lái)操作當(dāng)前的 DOM,這時(shí)候就需要使用傳統(tǒng)匿名函數(shù)而非箭頭函數(shù)。
在嚴(yán)格模式下,如果箭頭函數(shù)的上層函數(shù)均為箭頭函數(shù),那么 this 對(duì)象將不可用。
另,由于箭頭函數(shù)沒(méi)有自己的 this 對(duì)象,所以箭頭函數(shù)不能當(dāng)做構(gòu)造函數(shù)。
我們知道在函數(shù)體中有 arguments 這樣一個(gè)偽數(shù)組對(duì)象,該對(duì)象中包含該函數(shù)所有的入?yún)ⅲ@示入?yún)?+ 隱式入?yún)ⅲ?,?dāng)函數(shù)體中有另外一個(gè)函數(shù),并且該函數(shù)為箭頭函數(shù)時(shí),該箭頭函數(shù)的函數(shù)體中可以直接訪(fǎng)問(wèn)父級(jí)函數(shù)的 arguments 對(duì)象。
function getSum() { var example = () => { return Array .prototype .reduce .call(arguments, (pre, cur) => pre + cur); } return example(); } getSum(1, 2, 3); // => 6
由于箭頭函數(shù)本身沒(méi)有 arguments 對(duì)象,所以如果他的上層函數(shù)都是箭頭函數(shù)的話(huà),那么 arguments 對(duì)象將不可用。
最后再鞏固一下箭頭函數(shù)的語(yǔ)法:
當(dāng)箭頭函數(shù)入?yún)⒅挥幸粋€(gè)時(shí)可以省略入?yún)⒗ㄌ?hào);
當(dāng)入?yún)⒍嘤嘁粋€(gè)或沒(méi)有入?yún)?/strong>時(shí)必須寫(xiě)括號(hào);
當(dāng)函數(shù)體只有一個(gè) return 語(yǔ)句時(shí)可以省略函數(shù)體的花括號(hào)與 return 關(guān)鍵字。
類(lèi) & 繼承類(lèi)也是 ES6 一個(gè)不可忽視的新特性,雖然只是句法上的語(yǔ)法糖,但是相對(duì)于 ES5,學(xué)習(xí) ES6 的類(lèi)之后對(duì)原型鏈會(huì)有更加清晰的認(rèn)識(shí)。
特性本質(zhì)為對(duì)原型鏈的二次包裝
類(lèi)沒(méi)有提升
不能使用字面量定義屬性
動(dòng)態(tài)繼承類(lèi)的構(gòu)造方法中 super 優(yōu)先 this
類(lèi)的定義/* 類(lèi)不會(huì)被提升 */ let puppy = new Animal("puppy"); // => ReferenceError class Animal { constructor(name) { this.name = name; } sleep() { console.log(`The ${this.name} is sleeping...`); } static type() { console.log("This is an Animal class."); } } let puppy = new Animal("puppy"); puppy.sleep(); // => The puppy is sleeping... /* 實(shí)例化后無(wú)法訪(fǎng)問(wèn)靜態(tài)方法 */ puppy.type(); // => TypeError Animal.type(); // => This is an Animal class. /* 實(shí)例化前無(wú)法訪(fǎng)問(wèn)動(dòng)態(tài)方法 */ Animal.sleep(); // => TypeError /* 類(lèi)不能重復(fù)定義 */ class Animal() {} // => SyntaxError
以上我們使用 class 關(guān)鍵字聲明了一個(gè)名為 Animal 的類(lèi)。
雖然類(lèi)的定義中并未要求類(lèi)名的大小寫(xiě),但鑒于代碼規(guī)范,推薦類(lèi)名的首字母大寫(xiě)。
兩點(diǎn)注意事項(xiàng):
在類(lèi)的定義中有一個(gè)特殊方法 constructor(),該方法名固定,表示該類(lèi)的構(gòu)造函數(shù)(方法),在類(lèi)的實(shí)例化過(guò)程中會(huì)被調(diào)用(new Animal("puppy"));
類(lèi)中無(wú)法像對(duì)象一樣使用 prop: value 或者 prop = value 的形式定義一個(gè)類(lèi)的屬性,我們只能在類(lèi)的構(gòu)造方法或其他方法中使用 this.prop = value 的形式為類(lèi)添加屬性。
最后對(duì)比一下我們之前是怎樣寫(xiě)類(lèi)的:
function Animal(name) { this.name = name; } Animal.prototype = { sleep: function(){ console.log("The " + this.name + "is sleeping..."); } }; Animal.type = function() { console.log("This is an Animal class."); }
類(lèi)的繼承class 關(guān)鍵字真真讓這一切變得清晰易懂了~
class Programmer extends Animal { constructor(name) { /* 在 super 方法之前 this 不可用 */ console.log(this); // => ReferenceError super(name); console.log(this); // Right! } program() { console.log("I"m coding..."); } sleep() { console.log("Save all files."); console.log("Get into bed."); super.sleep(); } } let coder = new Programmer("coder"); coder.program(); // => I"m coding... coder.sleep(); // => Save all files. => Get into bed. => The coder is sleeping.
這里我們使用 class 定義了一個(gè)類(lèi) Programmer,使用 extends 關(guān)鍵字讓該類(lèi)繼承于另一個(gè)類(lèi) Animal。
如果子類(lèi)有構(gòu)造方法,那么在子類(lèi)構(gòu)造方法中使用 this 對(duì)象之前必須使用 super() 方法運(yùn)行父類(lèi)的構(gòu)造方法以對(duì)父類(lèi)進(jìn)行初始化。
在子類(lèi)方法中我們也可以使用 super 對(duì)象來(lái)調(diào)用父類(lèi)上的方法。如示例代碼中子類(lèi)的 sleep() 方法:在這里我們重寫(xiě)了父類(lèi)中的 sleep() 方法,添加了兩條語(yǔ)句,并在方法末尾使用 super 對(duì)象調(diào)用了父類(lèi)上的 sleep() 方法。
俗話(huà)講:沒(méi)有對(duì)比就沒(méi)有傷害 (*゜ー゜*),我們最后來(lái)看一下以前我們是怎么來(lái)寫(xiě)繼承的:
function Programmer(name) { Animal.call(this, name); } Programmer.prototype = Object.create(Animal.prototype, { program: { value: function() { console.log("I"m coding..."); } }, sleep: { value: function() { console.log("Save all files."); console.log("Get into bed."); Animal.prototype.sleep.apply(this, arguments); } } }); Programmer.prototype.constructor = Programmer;
如果前文類(lèi)的定義中的前后對(duì)比不足為奇,那么這個(gè)。。。
給你一個(gè)眼神,自己去體會(huì) (⊙?⊙),一臉懵逼.jpg
模塊啊哈,終于寫(xiě)到最后一部分了。
模塊系統(tǒng)是一切模塊化的前提,在未推出 ES6 Module 標(biāo)準(zhǔn)之前,相信大伙兒已經(jīng)被滿(mǎn)世界飛的 AMD、CMD、UMD、CommonJS 等等百花齊放的模塊化標(biāo)準(zhǔn)搞的暈頭轉(zhuǎn)向了吧。但是,現(xiàn)在 TC39 在 ECMAScript2015(ES6) 版本里終于推出了正式的模塊化規(guī)范,前端模塊系統(tǒng)的大一統(tǒng)時(shí)代已經(jīng)到來(lái)了!
OMG,這段話(huà)寫(xiě)的好燃 orz
廢話(huà)有點(diǎn)多。。。
下面咱們來(lái)了解一個(gè)這個(gè)模塊系統(tǒng)的基本規(guī)范。
特性為方便描述,下文中導(dǎo)出對(duì)象指一切可導(dǎo)出的內(nèi)容(變量、函數(shù)、對(duì)象、類(lèi)等),勿與對(duì)象(Object)混淆。
導(dǎo)入對(duì)象同理。
封閉的代碼塊
每個(gè)模塊都有自己完全獨(dú)立的代碼塊,跟作用域類(lèi)似,但是更加封閉。
無(wú)限制導(dǎo)出導(dǎo)出
一個(gè)模塊理論上可以導(dǎo)出無(wú)數(shù)個(gè)變量、函數(shù)、對(duì)象屬性、對(duì)象方法,甚至一個(gè)完整的類(lèi)。但是我們應(yīng)該時(shí)刻牢記單一職責(zé)這一程序設(shè)計(jì)的基本原則,不要試圖去開(kāi)發(fā)一個(gè)臃腫的巨大的面面俱到的模塊,合理控制代碼的顆粒度也是開(kāi)發(fā)可維護(hù)系統(tǒng)必不可少的一部分。
嚴(yán)格模式下運(yùn)行
模塊默認(rèn)情況下在嚴(yán)格模式下運(yùn)行("use strict;"),這時(shí)候要注意一些取巧甚至有風(fēng)險(xiǎn)的寫(xiě)法應(yīng)該避免,這也是保證代碼健壯性的前提。
export const DEV = true; export function example() { //... } export class expClass { //... } export let obj = { DEV, example, expClass, //... }
使用 export 關(guān)鍵字,后面緊跟聲明關(guān)鍵字(let、function 等)聲明一個(gè)導(dǎo)出對(duì)象,這種聲明并同時(shí)導(dǎo)出的導(dǎo)出方式稱(chēng)作內(nèi)聯(lián)導(dǎo)出。
未被導(dǎo)出的內(nèi)容(變量、函數(shù)、類(lèi)等)由于獨(dú)立代碼塊的原因,將僅供模塊內(nèi)部使用(可類(lèi)比成一種閉包)。
// module example.js const DEV = true; function example() { //... } class expClass { //... } let obj = { DEV, example, expClass, //... } // module example.js export {DEV, example, expClass, obj}; export {DEV, example as exp, expClass, obj};
相對(duì)于內(nèi)聯(lián)導(dǎo)出,上邊的這種方式為對(duì)象導(dǎo)出。我們可以像寫(xiě)普通 JS 文件一樣寫(xiě)主要的功能邏輯,最后通過(guò) export 集中導(dǎo)出。
在導(dǎo)出時(shí)我們可以使用 as 關(guān)鍵字改變導(dǎo)出對(duì)象的名稱(chēng)。
export default {DEV, example as exp, expClass, obj}; // OR export default obj; // OR export default const DEV = true;
我們可以在 export 關(guān)鍵字后接 default 來(lái)設(shè)置模塊的默認(rèn)導(dǎo)出對(duì)象,需要注意的是:一個(gè)模塊只能有一個(gè)默認(rèn)導(dǎo)出。
先不多說(shuō),后面講導(dǎo)入的時(shí)候再細(xì)講相互之間的關(guān)聯(lián)。
模塊的導(dǎo)入與使用前文我們定義了一個(gè)名為 example 的模塊,寫(xiě)在文件 example.js中,下面我們來(lái)導(dǎo)入并使用這個(gè)模塊。
import example from "./example.js"; // OR import default as example from "./example.js";
使用 import 關(guān)鍵字導(dǎo)入一個(gè)模塊,上邊這兩種寫(xiě)法是等效的。默認(rèn)導(dǎo)入對(duì)象既是模塊默認(rèn)導(dǎo)出對(duì)象,即對(duì)應(yīng)模塊定義中的 export default 所導(dǎo)出的內(nèi)容。
此外我們還可以這樣導(dǎo)入一個(gè)模塊:
import {DEV, example} from "./example.js"; import * as exp from "./example.js"; import {default as expMod, * as expAll, DEV, example as exp} from "./example.js";
這種導(dǎo)入方式對(duì)應(yīng)模塊定義中的 export {DEV, example, expClass, obj} 或 export const DEV = true。下面我們逐行分析:
第一行,我們使用對(duì)象導(dǎo)入的方式導(dǎo)入一個(gè)模塊內(nèi)容,可能有些人已經(jīng)發(fā)現(xiàn),這跟解構(gòu)賦值很相似,但也有不同,下面會(huì)講到。需要注意的是形參對(duì)象({DEV, example})與模塊定義中導(dǎo)出的名稱(chēng)必須保持一致。
第二行,導(dǎo)入時(shí)可以使用通配符 * 配合 as 關(guān)鍵字一次性導(dǎo)出模塊中所有內(nèi)容,最終導(dǎo)入的內(nèi)容放在 exp 對(duì)象中。
第三行,在使用對(duì)象導(dǎo)入來(lái)導(dǎo)入一個(gè)模塊的指定內(nèi)容時(shí),也可以使用 as 關(guān)鍵字更改最終導(dǎo)入對(duì)象的名稱(chēng),這里表現(xiàn)出與解構(gòu)賦值的一個(gè)不同之處,忘記解構(gòu)賦值的小伙伴可以翻翻前文對(duì)比一下哈~
最后,在導(dǎo)入一個(gè)模塊后我們就可以直接使用模塊的函數(shù)、變量、類(lèi)等了,完整的代碼示例:
import {DEV, example, expClass as EC} from "./example.js"; if(DEV) { let exp = new EC(); // anything you want... example(); }
好嘞!到這里,ES6 常用的 8 個(gè)新特性就講完了,恭喜你耐心地看完了。當(dāng)然,還有許多地方?jīng)]有講到,有時(shí)間的話(huà)會(huì)考慮繼續(xù)寫(xiě)一些。
好嘞,就這樣吧,希望對(duì)你有所幫助,拜拜~<(* ̄▽?zhuān)?)/。
文中部分專(zhuān)業(yè)名詞由于未找到合適譯文,最后自行翻譯,如有不妥,歡迎指正。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84084.html
摘要:以下簡(jiǎn)稱(chēng)是語(yǔ)言的下一代標(biāo)準(zhǔn)。因?yàn)楫?dāng)前版本的是在年發(fā)布的,所以又稱(chēng)。用它所聲明的變量,只在命令所在的代碼塊內(nèi)有效。的繼承機(jī)制,實(shí)質(zhì)是先創(chuàng)造父類(lèi)的實(shí)例對(duì)象所以必須先調(diào)用方法,然后再用子類(lèi)的構(gòu)造函數(shù)修改。 ECMAScript 6(以下簡(jiǎn)稱(chēng)ES6)是JavaScript語(yǔ)言的下一代標(biāo)準(zhǔn)。因?yàn)楫?dāng)前版本的ES6是在2015年發(fā)布的,所以又稱(chēng)ECMAScript 2015。 也就是說(shuō),ES6就是E...
摘要:以下簡(jiǎn)稱(chēng)是語(yǔ)言的下一代標(biāo)準(zhǔn)。的繼承機(jī)制,實(shí)質(zhì)是先創(chuàng)造父類(lèi)的實(shí)例對(duì)象所以必須先調(diào)用方法,然后再用子類(lèi)的構(gòu)造函數(shù)修改??偨Y(jié)以上就是最常用的一些語(yǔ)法,可以說(shuō)這的語(yǔ)法,在的日常使用中占了追加十分鐘好的嗎分鐘掌握核心內(nèi)容下 ECMAScript 6(以下簡(jiǎn)稱(chēng)ES6)是JavaScript語(yǔ)言的下一代標(biāo)準(zhǔn)。因?yàn)楫?dāng)前版本的ES6是在2015年發(fā)布的,所以又稱(chēng)ECMAScript 2015。 也就是說(shuō)...
摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...
摘要:為此決定自研一個(gè)富文本編輯器。本文,主要介紹如何實(shí)現(xiàn)富文本編輯器,和解決一些不同瀏覽器和設(shè)備之間的。 對(duì)ES6Generator函數(shù)的理解 Generator 函數(shù)是 ES6 提供的一種異步編程解決方案,語(yǔ)法行為與傳統(tǒng)函數(shù)完全不同。 JavaScript 設(shè)計(jì)模式 ② 巧用工廠(chǎng)模式和創(chuàng)建者模式 我為什么把他們兩個(gè)放在一起講?我覺(jué)得這兩個(gè)設(shè)計(jì)模式有相似之處,有時(shí)候會(huì)一個(gè)設(shè)計(jì)模式不能滿(mǎn)...
閱讀 1332·2021-10-27 14:14
閱讀 3583·2021-09-29 09:34
閱讀 2488·2019-08-30 15:44
閱讀 1733·2019-08-29 17:13
閱讀 2577·2019-08-29 13:07
閱讀 880·2019-08-26 18:26
閱讀 3351·2019-08-26 13:44
閱讀 3217·2019-08-26 13:37