新事物也是有兩面性的,箭頭函數有他的便捷有他的優勢,可是他也有缺點,他的優勢是代碼簡潔,this
提早定義,但他的缺點也是這些,好比代碼太過簡潔,致使很差閱讀,this
提早定義,致使沒法使用JS
進行一些ES5
裏面看起來很是正常的操做。javascript
本質來講箭頭函數沒有本身的this
,它的this
是派生而來的,根據「詞法做用域」派生而來。java
因爲箭頭函數在調用時不會生成自身做用域下的this
和arguments
值,其持有外部包含它的函數的this
值,而且在調用的時候就定下來了,不可動態改變,下面我就總結一下什麼狀況下不應使用箭頭函數。函數
const test = { array: [1, 2, 3], sum: () => { console.log(this === window); // => true return this.array.reduce((result, item) => result + item); } }; test.sum(); // TypeError: Cannot read property 'reduce' of undefined
緣由就是,箭頭函數沒有它本身的this
值,箭頭函數內的this
值繼承自外圍做用域。this
對象方法內的this
指向調用這個方法的對象,若是使用箭頭函數,this
和對象方法在調用的時候所處環境的this
值一致。由於 test.sum()
是在全局環境下進行調用,此時this
指向全局。prototype
解決方法也很簡單,使用函數表達式或者方法簡寫(ES6 中已經支持)來定義方法,這樣能確保 this 是在運行時是由包含它的上下文決定的。code
const test = { array: [1, 2, 3], sum() { console.log(this === test); // => true return this.array.reduce((result, item) => result + item); } }; test.sum(); // 6
在對象原型上定義函數也是遵循着同樣的規則對象
function Person(name) { this.name = name; } Person.prototype.sayName = () => { console.log(this === window); // => true return this.name; }; const cat = new Person('Mew'); cat.sayName(); // => undefined
使用傳統的函數表達式就能解決問題繼承
function Person(name) { this.name = name; } Person.prototype.sayName = function() { console.log(this === Person); // => true return this.name; }; const cat = new Person('Mew'); cat.sayName(); // => Mew
this
是JS
中很是強大的特色,他讓函數能夠根據其調用方式動態的改變上下文,而後箭頭函數直接在聲明時就綁定了this
對象,因此再也不是動態的。事件
在客戶端,在DOM
元素上綁定事件監聽函數是很是廣泛的行爲,在DOM
事件被觸發時,回調函數中的this
指向該DOM
,可是,箭頭函數在聲明的時候就綁定了執行上下文,要動態改變上下文是不可能的,在須要動態上下文的時候它的弊端就凸顯出來:ip
const button = document.getElementById('myButton'); button.addEventListener('click', () => { console.log(this === window); // => true this.innerHTML = 'Clicked button'; });
由於這個回調的箭頭函數是在全局上下文中被定義的,因此他的this
是window
。換句話說就是,箭頭函數預約義的上下文是不能被修改的,這樣 this.innerHTML
就等價於 window.innerHTML
,然後者是沒有任何意義的。
使用函數表達式就能夠在運行時動態的改變 this
:
const button = document.getElementById('myButton'); button.addEventListener('click', function() { console.log(this === button); // => true this.innerHTML = 'Clicked button'; });
若是使用箭頭函數會報錯。
顯然,箭頭函數是不能用來作構造函數。
const Message = (text) => { this.text = text; }; const helloMessage = new Message('Hello World!'); // Throws "TypeError: Message is not a constructor"
理論上來講也是不能這麼作的,由於箭頭函數在建立時this對象就綁定了,更不會指向對象實例。
箭頭函數可讓語句寫的很是的簡潔,可是一個真實的項目,通常由多個開發者共同協做完成,箭頭函數有時候並不會讓人很好的理解:
const multiply = (a, b) => b === undefined ? b => a * b : a * b; const 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; } const double = multiply(2); double(3); // => 6 multiply(2, 3); // => 6
毫無疑問,箭頭函數帶來了不少便利。恰當的使用箭頭函數可讓咱們避免使用早期的.bind()
函數或者須要固定上下文的地方而且讓代碼更加簡潔。
箭頭函數也有一些不便利的地方。咱們在須要動態上下文的地方不能使用箭頭函數:定義對象方法、定義原型方法、定義構造函數、定義事件回調函數。在其餘狀況下,請盡情的使用箭頭函數。