翻譯 | ES6 箭頭函數使用禁忌

做者:扉扉 (滬江web前端開發工程師)
本文原創翻譯,有不當的地方歡迎指出。轉載請指明出處。javascript

看到你天天使用的編程語言在不斷進化是一件使人開心的事情 。從錯誤中學習,找到更好的實現方式,創造新的語法特性,語言就這樣一步一步地實現了版本更新。前端

這正是近幾年Javascript身上發生的事情 ,ECMAScript6 引入了: 箭頭函數,類以及其它特性,真的太棒了!java

其中一個很是好用的箭頭函數,有許多文件介紹了了這個漂亮的語法糖,還具備透明上下文的做用(原文爲 context transparency), 若是你對於ES6還不熟悉,請先閱讀箭頭函數的一些入門文章。web

凡事都有兩面性,新的特性每每也會帶來新的困擾, 好比對箭頭函數的誤用。編程

這篇文章經過實際使用場景帶你瞭解在一些特定狀況下究竟是應該使用傳統的函數,仍是該使用更簡潔的箭頭函數。dom

1.在對象上定義方法

在javascript中,方法能夠作爲一個對象的屬性,當調用這個方法時, this 指向這個方法所屬的對象;編程語言

1a. 對象字面量

既然箭頭函數只是一個語法糖,那咱們來嘗試一下使用箭頭函數作爲一個對象的方法會發生什麼:函數

var calculate = {  
  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"
calculate.sum();

calculate.sum使用箭頭函數來定義,可是調用 calculate.sum() 時出現了異常。由於當執行sum的時候上下文仍然是window,這是由於箭頭函數已經綁定了window作爲上下文。學習

執行this.array 等同於 window.array ,固然是 undefinedthis

解決辦法就是不要在對象的方法上使用箭頭函數短語法,這樣this關鍵字會在調用時決定,而不是早早綁定在閉合的上下文中, 讓咱們看一下具體代碼:

var calculate = {  
  array: [1, 2, 3],
  sum() {
    console.log(this === calculate); // => true
    return this.array.reduce((result, item) => result + item);
  }
};
calculate.sum(); // => 6
  1. 對象原型

一樣的規則也適用於給對象prototype原型上定義方法:

function MyCat(name) {  
  this.catName = name;
}
MyCat.prototype.sayCatName = () => {  
  console.log(this === window); // => true
  returnthis.catName;
};
var cat = new MyCat('Mew');  
cat.sayCatName(); // => undefined

使用傳統方式便可正常工做:

function MyCat(name) {  
  this.catName = name;
}
MyCat.prototype.sayCatName = function() {  
  console.log(this === cat); // => true
  returnthis.catName;
};
var cat = new MyCat('Mew');  
cat.sayCatName(); // => 'Mew'

2.動態上下文中的回調函數

this是js中很是強大的特色,他讓函數能夠根據其調用方式動態的改變上下文,而後箭頭函數直接在聲明時就綁定了this對象,因此再也不是動態的。

在客戶端,在dom元素上綁定事件監聽函數是很是廣泛的行爲,在dom事件被觸發時,回調函數中的this指向該dom,可當咱們使用箭頭函數時:

button.addEventListener('click', () => {  
    console.log(this === window); // => true
    this.innerHTML = 'Clicked button';
});

由於這個回調的箭頭函數是在全局上下文中被定義的,因此他的this是window。因此當this是由目標對象決定時,咱們應該使用函數表達式:

button.addEventListener('click', function() {  
    console.log(this === button); // => true
    this.innerHTML = 'Clicked button';
});

3.調用構造函數

當函數作爲構造函數執行時 new MyFunction(),this指向新建立的對象實例:

this instanceOf MyFunction === true

須要注意的是,構造函數不能使用箭頭函數,若是這樣作會拋出異常。

由於使用箭頭函數後this會指定閉合的當前上下文,而當函數作爲構造器的時候,this又會指向生成的實例, 這個形成歧義。

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

咱們都知道使用函數表達式便可正常:

var Message = function(text) {  
  this.text = text;
};
var helloMessage = new Message('Hello World!');  
console.log(helloMessage.text); // => 'Hello World!'

4.超短的語法

箭頭函數可讓語句寫的很是的簡潔,參數只有一個時能夠省略(),函數體只有一句話能夠省略{},若是返回值是一個表達式還甚至還能夠省略return!

個人大學老師曾給咱們佈置了一道有趣的做業: 使用C語言來編寫一個計算字符串長度的函數,函數要儘量的短,這是一個很好的方法去學習一門新的語言。

不過在真實生活中,代碼要被其它開發者閱讀,超短的語法有時會讓你的同事陷入難以理解中。上代碼:

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

這個函數的做用就是當只有一個參數 a 時,返回接受一個參數 b 返回 a * b 的函數,接收兩個參數時直接返回乘積,這個函數能夠很好的工做而且看起很簡潔,可是從第一眼看去並非很好理解。

爲了讓這個函數更好的讓人理解,咱們能夠爲這個箭頭函數加一對花括號,並加上 return 語句,或者直接使用函數表達式:

function multiply(a, b){
    if (b === undefined) {
        return function(b){
            return a * b;
        }
    }
    return a * b;
}
 
letdouble = multiply(2);
 
double(3); // => 6
multiply(2, 3);// => 6

怎麼樣是否是好理解多了?

如何平衡簡潔與易理解也是使用箭頭函數須要注意的地方。

5.總結

毫無疑問,箭頭函數是一個很棒的特性。之前咱們使用bind()函數或者須要固定上下文的地方如今使用箭頭函數會讓代碼更加簡潔。

但有一些狀況下,使用箭頭函數也有一些不便利。在須要動態上下文的地方不能使用箭頭函數,使用構造函數建立對象時不能使用箭頭函數等等。除去文中列舉不適合使用的狀況下,盡情地使用箭頭函數吧。

原文地址:https://rainsoft.io/when-not-...

clipboard.png

圖片描述

iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、噹噹開售。

相關文章
相關標籤/搜索