国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

什么時(shí)候你不能使用箭頭函數(shù)?

guyan0319 / 1476人閱讀

摘要:顯然,箭頭函數(shù)是不能用來做構(gòu)造函數(shù),實(shí)際上會(huì)禁止你這么做,如果你這么做了,它就會(huì)拋出異常。換句話說,箭頭構(gòu)造函數(shù)的執(zhí)行并沒有任何意義,并且是有歧義的。

共 2670 字,讀完需 5 分鐘。編譯自 Dmitri Pavlutin 的文章,對(duì)原文內(nèi)容做了精簡(jiǎn)和代碼風(fēng)格優(yōu)化。ES6 中引入的箭頭函數(shù)可以讓我們寫出更簡(jiǎn)潔的代碼,但是部分場(chǎng)景下使用箭頭函數(shù)會(huì)帶來嚴(yán)重的問題,有哪些場(chǎng)景?會(huì)導(dǎo)致什么問題?該怎么解決,容我慢慢道來。

能見證每天在用的編程語言不斷演化是一件讓人非常興奮的事情,從錯(cuò)誤中學(xué)習(xí)、探索更好的語言實(shí)現(xiàn)、創(chuàng)造新的語言特性是推動(dòng)編程語言版本迭代的動(dòng)力。JS 近幾年的變化就是最好的例子, 以 ES6 引入的箭頭函數(shù)(arrow functions)、class 等特性為代表,把 JS 的易用性推到了新的高度。

關(guān)于 ES6 中的箭頭函數(shù),網(wǎng)上有很多文章解釋其作用和語法,如果你剛開始接觸 ES6,可以從這里開始。任何事物都具有兩面性,語言的新特性常常被誤解、濫用,比如箭頭函數(shù)的使用就存在很多誤區(qū)。接下來,筆者會(huì)通過實(shí)例介紹該避免使用箭頭函數(shù)的場(chǎng)景,以及在這些場(chǎng)景下該如何使用函數(shù)表達(dá)式(function expressions)、函數(shù)聲明或者方法簡(jiǎn)寫(shorthand method)來保障代碼正確性和可讀性。

1. 定義對(duì)象方法

JS 中對(duì)象方法的定義方式是在對(duì)象上定義一個(gè)指向函數(shù)的屬性,當(dāng)方法被調(diào)用的時(shí)候,方法內(nèi)的 this 就會(huì)指向方法所屬的對(duì)象。

1.1 定義字面量方法

因?yàn)榧^函數(shù)的語法很簡(jiǎn)潔,可能不少同學(xué)會(huì)忍不住用它來定義字面量方法,比如下面的例子 JS Bin:

const calculator = {
    array: [1, 2, 3],
    sum: () => {
        console.log(this === window); // => true
        return this.array.reduce((result, item) => result + item);
    }
};

console.log(this === window); // => true

// Throws "TypeError: Cannot read property "reduce" of undefined"
calculator.sum();

calculator.sum 使用箭頭函數(shù)來定義,但是調(diào)用的時(shí)候會(huì)拋出 TypeError,因?yàn)檫\(yùn)行時(shí) this.array 是未定義的,調(diào)用 calculator.sum 的時(shí)候,執(zhí)行上下文里面的 this 仍然指向的是 window,原因是箭頭函數(shù)把函數(shù)上下文綁定到了 window 上,this.array 等價(jià)于 window.array,顯然后者是未定義的。

解決的辦法是,使用函數(shù)表達(dá)式或者方法簡(jiǎn)寫(ES6 中已經(jīng)支持)來定義方法,這樣能確保 this 是在運(yùn)行時(shí)是由包含它的上下文決定的,修正后的代碼如下 JS Bin:

const calculator = {
    array: [1, 2, 3],
    sum() {
        console.log(this === calculator); // => true
        return this.array.reduce((result, item) => result + item);
    }
};
calculator.sum(); // => 6

這樣 calculator.sum 就變成了普通函數(shù),執(zhí)行時(shí) this 就指向 calculator 對(duì)象,自然能得到正確的計(jì)算結(jié)果。

1.2 定義原型方法

同樣的規(guī)則適用于原型方法(prototype method)的定義,使用箭頭函數(shù)會(huì)導(dǎo)致運(yùn)行時(shí)的執(zhí)行上下文錯(cuò)誤,比如下面的例子 JS Bin:

function Cat(name) {
    this.name = name;
}

Cat.prototype.sayCatName = () => {
    console.log(this === window); // => true
    return this.name;
};

const cat = new Cat("Mew");
cat.sayCatName(); // => undefined

使用傳統(tǒng)的函數(shù)表達(dá)式就能解決問題 JS Bin:

function Cat(name) {
    this.name = name;
}

Cat.prototype.sayCatName = function () {
    console.log(this === cat); // => true
    return this.name;
};

const cat = new Cat("Mew");
cat.sayCatName(); // => "Mew"

sayCatName 變成普通函數(shù)之后,被調(diào)用時(shí)的執(zhí)行上下文就會(huì)指向新創(chuàng)建的 cat 實(shí)例。

2. 定義事件回調(diào)函數(shù)

this 是 JS 中很強(qiáng)大的特性,可以通過多種方式改變函數(shù)執(zhí)行上下文,JS 內(nèi)部也有幾種不同的默認(rèn)上下文指向,但普適的規(guī)則是在誰上面調(diào)用函數(shù) this 就指向誰,這樣代碼理解起來也很自然,讀起來就像在說,某個(gè)對(duì)象上正在發(fā)生某件事情。

但是,箭頭函數(shù)在聲明的時(shí)候就綁定了執(zhí)行上下文,要?jiǎng)討B(tài)改變上下文是不可能的,在需要?jiǎng)討B(tài)上下文的時(shí)候它的弊端就凸顯出來。比如在客戶端編程中常見的 DOM 事件回調(diào)函數(shù)(event listenner)綁定,觸發(fā)回調(diào)函數(shù)時(shí) this 指向當(dāng)前發(fā)生事件的 DOM 節(jié)點(diǎn),而動(dòng)態(tài)上下文這個(gè)時(shí)候就非常有用,比如下面這段代碼試圖使用箭頭函數(shù)來作事件回調(diào)函數(shù) JS Bin:

const button = document.getElementById("myButton");
button.addEventListener("click", () => {
    console.log(this === window); // => true
    this.innerHTML = "Clicked button";
});

在全局上下文下定義的箭頭函數(shù)執(zhí)行時(shí) this 會(huì)指向 window,當(dāng)單擊事件發(fā)生時(shí),瀏覽器會(huì)嘗試用 button 作為上下文來執(zhí)行事件回調(diào)函數(shù),但是箭頭函數(shù)預(yù)定義的上下文是不能被修改的,這樣 this.innerHTML 就等價(jià)于 window.innerHTML,而后者是沒有任何意義的。

使用函數(shù)表達(dá)式就可以在運(yùn)行時(shí)動(dòng)態(tài)的改變 this,修正后的代碼 JS Bin:

const button = document.getElementById("myButton");
button.addEventListener("click", function() {
    console.log(this === button); // => true
    this.innerHTML = "Clicked button";
});

當(dāng)用戶單擊按鈕時(shí),事件回調(diào)函數(shù)中的 this 實(shí)際指向 button,這樣的 this.innerHTML = "Clicked button" 就能按照預(yù)期修改按鈕中的文字。

3. 定義構(gòu)造函數(shù)

構(gòu)造函數(shù)中的 this 指向新創(chuàng)建的對(duì)象,當(dāng)執(zhí)行 new Car() 的時(shí)候,構(gòu)造函數(shù) Car 的上下文就是新創(chuàng)建的對(duì)象,也就是說 this instanceof Car === true。顯然,箭頭函數(shù)是不能用來做構(gòu)造函數(shù), 實(shí)際上 JS 會(huì)禁止你這么做,如果你這么做了,它就會(huì)拋出異常。

換句話說,箭頭構(gòu)造函數(shù)的執(zhí)行并沒有任何意義,并且是有歧義的。比如,當(dāng)我們運(yùn)行下面的代碼 JS Bin:

const Message = (text) => {
    this.text = text;
};
// Throws "TypeError: Message is not a constructor"
const helloMessage = new Message("Hello World!");

構(gòu)造新的 Message 實(shí)例時(shí),JS 引擎拋了錯(cuò)誤,因?yàn)?Message 不是構(gòu)造函數(shù)。在筆者看來,相比舊的 JS 引擎在出錯(cuò)時(shí)悄悄失敗的設(shè)計(jì),ES6 在出錯(cuò)時(shí)給出具體錯(cuò)誤消息是非常不錯(cuò)的實(shí)踐。可以通過使用函數(shù)表達(dá)式或者函數(shù)聲明 來聲明構(gòu)造函數(shù)修復(fù)上面的例子 JS Bin:

const Message = function(text) {
    this.text = text;
};
const helloMessage = new Message("Hello World!");
console.log(helloMessage.text); // => "Hello World!"
4. 追求過短的代碼

箭頭函數(shù)允許你省略參數(shù)兩邊的括號(hào)、函數(shù)體的花括號(hào)、甚至 return 關(guān)鍵詞,這對(duì)編寫更簡(jiǎn)短的代碼非常有幫助。這讓我想起大學(xué)計(jì)算機(jī)老師給學(xué)生留過的有趣作業(yè):看誰能使用 C 語言編寫出最短的函數(shù)來計(jì)算字符串的長度,這對(duì)學(xué)習(xí)和探索新語言特性是個(gè)不錯(cuò)的法子。但是,在實(shí)際的軟件工程中,代碼寫完之后會(huì)被很多工程師閱讀,真正的 write one, read many times,在代碼可讀性方面,最短的代碼可能并不總是最好的。一定程度上,壓縮了太多邏輯的簡(jiǎn)短代碼,閱讀起來就沒有那么直觀,比如下面的例子 JS Bin:

const multiply = (a, b) => b === undefined ? b => a * b : a * b;
const double = multiply(2);
double(3);      // => 6
multiply(2, 3); // => 6

multiply 函數(shù)會(huì)返回兩個(gè)數(shù)字的乘積或者返回一個(gè)可以繼續(xù)調(diào)用的固定了一個(gè)參數(shù)的函數(shù)。代碼看起來很簡(jiǎn)短,但大多數(shù)人第一眼看上去可能無法立即搞清楚它干了什么,怎么讓這段代碼可讀性更高呢?有很多辦法,可以在箭頭函數(shù)中加上括號(hào)、條件判斷、返回語句,或者使用普通的函數(shù) JS Bin:

function multiply(a, b) {
    if (b === undefined) {
        return function (b) {
            return a * b;
        }
    }
    return a * b;
}

const double = multiply(2);
double(3); // => 6
multiply(2, 3); // => 6

為了讓代碼可讀性更高,在簡(jiǎn)短和啰嗦之間把握好平衡是非常有必要的。

5. 總結(jié)

箭頭函數(shù)無疑是 ES6 帶來的重大改進(jìn),在正確的場(chǎng)合使用箭頭函數(shù)能讓代碼變的簡(jiǎn)潔、短小,但某些方面的優(yōu)勢(shì)在另外一些方面可能就變成了劣勢(shì),在需要?jiǎng)討B(tài)上下文的場(chǎng)景中使用箭頭函數(shù)你要格外的小心,這些場(chǎng)景包括:定義對(duì)象方法、定義原型方法、定義構(gòu)造函數(shù)、定義事件回調(diào)函數(shù)。

One More Thing

本文作者王仕軍,商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。如果你覺得本文對(duì)你有幫助,請(qǐng)點(diǎn)贊!如果對(duì)文中的內(nèi)容有任何疑問,歡迎留言討論。想知道我接下來會(huì)寫些什么?歡迎訂閱我的掘金專欄或知乎專欄:《前端周刊:讓你在前端領(lǐng)域跟上時(shí)代的腳步》。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/82661.html

相關(guān)文章

  • ES6 系列之箭頭函數(shù)

    摘要:回顧我們先來回顧下箭頭函數(shù)的基本語法。主要區(qū)別包括沒有箭頭函數(shù)沒有,所以需要通過查找作用域鏈來確定的值。箭頭函數(shù)并沒有方法,不能被用作構(gòu)造函數(shù),如果通過的方式調(diào)用,會(huì)報(bào)錯(cuò)。 回顧 我們先來回顧下箭頭函數(shù)的基本語法。 ES6 增加了箭頭函數(shù): let func = value => value; 相當(dāng)于: let func = function (value) { return ...

    hsluoyz 評(píng)論0 收藏0
  • 論普通函數(shù)箭頭函數(shù)的區(qū)別以及箭頭函數(shù)的注意事項(xiàng)、不適用場(chǎng)景

    摘要:第二種情況是箭頭函數(shù)的如果指向普通函數(shù)它的繼承于該普通函數(shù)。箭頭函數(shù)的指向全局,使用會(huì)報(bào)未聲明的錯(cuò)誤。 showImg(https://segmentfault.com/img/remote/1460000018610072?w=600&h=400); 箭頭函數(shù)是ES6的API,相信很多人都知道,因?yàn)槠湔Z法上相對(duì)于普通函數(shù)更簡(jiǎn)潔,深受大家的喜愛。就是這種我們?nèi)粘i_發(fā)中一直在使用的API...

    paulquei 評(píng)論0 收藏0
  • 什么時(shí)候使用箭頭函數(shù)

    摘要:換句話說,箭頭函數(shù)構(gòu)造函數(shù)調(diào)用沒有意義,而且是模糊的。讓我們看看如果嘗試這樣做會(huì)發(fā)生什么執(zhí)行,其中是一個(gè)箭頭函數(shù),拋出一個(gè)錯(cuò)誤,不能用作構(gòu)造函數(shù)。當(dāng)需要?jiǎng)討B(tài)上下文時(shí),不能使用箭頭函數(shù)定義方法,使用構(gòu)造函數(shù)創(chuàng)建對(duì)象,在處理事件時(shí)從獲取目標(biāo)。 為了保證的可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 這些年來,ES6 將 JS 的可用性...

    MkkHou 評(píng)論0 收藏0
  • 《深入理解ES6》筆記——函數(shù)(3)

    摘要:錯(cuò)誤的寫法錯(cuò)誤的寫法中的構(gòu)造函數(shù)新增了支持默認(rèn)參數(shù)和不定參數(shù)。箭頭函數(shù)的簡(jiǎn)單理解箭頭函數(shù)的左邊表示輸入的參數(shù),右邊表示輸出的結(jié)果。但是有了尾調(diào)用優(yōu)化之后,遞歸函數(shù)的性能有了提升。 作為前端切圖仔,越發(fā)覺得自己離不開函數(shù)了。 說到JavaScript函數(shù),腦子里都是匿名函數(shù)、普通函數(shù)、閉包函數(shù)、構(gòu)造函數(shù)......然后還能說出一大堆函數(shù)的概念。如果你達(dá)到這個(gè)水平,那么函數(shù)對(duì)你來說沒有難度...

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

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

0條評(píng)論

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