成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

ES6 常用新特性講解

荊兆峰 / 3454人閱讀

摘要:一共講解了個(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)入正文。

函數(shù)默認(rèn)值 特性 & 語(yǔ)法
// 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ù),這里只介紹一些比較常用的。

題外話(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
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() 方法相反

Array
Array.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é)果。

Object
let 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ā)者的使用。

Object 新增的特性當(dāng)然不止這一個(gè) assign() 方法,一共增加了十多個(gè)新特性,特別是對(duì)屬性或方法名字面量定義的增強(qiáng)方面,很值得一看,感興趣的自行查找資料進(jìn)行了解哈,印象會(huì)更深刻!

Math

  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

插播一個(gè)小 Tip:使用位操作符也可以很方便的進(jìn)行取整操作,例如:~~3.14 or 3.14 | 0,也許這更加方便 : )

箭頭函數(shù)

  箭頭函數(shù)無(wú)疑是 ES6 中一個(gè)相當(dāng)重要的新特性。

特性

共享父級(jí) this 對(duì)象

共享父級(jí) arguments

不能當(dāng)做構(gòu)造函數(shù)

語(yǔ)法
最簡(jiǎn)表達(dá)式
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ù)極大地減少了代碼量。

完整語(yǔ)法
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ě)法保持不變。

函數(shù)上下文 this
// 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ù)。

父級(jí)函數(shù) arguments

  我們知道在函數(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.");
}

class 關(guān)鍵字真真讓這一切變得清晰易懂了~

類(lèi)的繼承
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、UMDCommonJS 等等百花齊放的模塊化標(biāo)準(zhǔn)搞的暈頭轉(zhuǎn)向了吧。但是,現(xiàn)在 TC39ECMAScript2015(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)該避免,這也是保證代碼健壯性的前提。

模塊的定義與導(dǎo)出
內(nèi)聯(lián)導(dǎo)出
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)比成一種閉包)。

對(duì)象導(dǎo)出
// 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)。

默認(rèn)導(dǎo)出
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

相關(guān)文章

  • 30分鐘掌握ES6/ES2015核心內(nèi)容

    摘要:以下簡(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...

    LucasTwilight 評(píng)論0 收藏0
  • 30分鐘掌握ES6/ES2015核心內(nèi)容(上)

    摘要:以下簡(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ō)...

    YPHP 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(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...

    mudiyouyou 評(píng)論0 收藏0
  • H5學(xué)習(xí)

    摘要:為此決定自研一個(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)...

    aristark 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<