前言javascript
箭頭函數極大地簡化了this的取值規則。html
普通函數與箭頭函數vue
普通函數指的是用function定義的函數:java
var hello = function () { console.log("Hello, Fundebug!"); }
箭頭函數指的是用=>定義的函數:編程
var hello = () => { console.log("Hello, Fundebug!"); }
JavaScript箭頭函數與普通函數不僅是寫法上的區別,它們還有一些微妙的不一樣點,其中一個不一樣點就是this。瀏覽器
箭頭函數沒有本身的this值,箭頭函數中所使用的this來自於函數做用域鏈。less
這句話很簡單,不過聽着稍微有點莫名其妙,得從頭提及。ide
this究竟是什麼?函數
關於this的文章也夠多了,有時候越描越黑,我就再也不添亂了,我只負責搬運一下MDN文檔:this,感興趣的能夠仔細閱讀一下,我摘錄一些最重要的話就行了。學習
A function's this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.
JavaScript是一門比較奇特的語言,它的this與其餘語言不同,而且它的取值還取決於代碼是否爲嚴格模式("use strict")。
this的值是什麼?
The JavaScript context object in which the current code is executing.
this就是代碼執行時當前的context object。
Global context
In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.
代碼沒有在任何函數中執行,而是在全局做用域中執行時,this的值就是global對象,對於瀏覽器來講,this就是window。
這一條規則仍是比較容易接受的。
Function context
Inside a function, the value of this depends on how the function is called.
函數中的this值取決於這個函數是怎樣被調用的,這一條規則就有點變態了,也是很容易出BUG的地方。
另外,this的值還與函數是否爲嚴格模式("use strict")有關,這就很是的喪心病狂了...
你們若是好奇的話,出門左轉看MDN文檔,我多說無益,只說明一種簡單的狀況。
As an object method
When a function is called as a method of an object, its this is set to the object the method is called on.
當函數做爲對象的方法被調用時,它的this值就是該對象。
var circle = { radius: 10, getRadius() { console.log(this.radius); } }; circle.getRadius(); // 打印 10
self = this?
當咱們須要在對象方法中嵌套一個內層函數時,this就會給咱們帶來實際的困擾了,你們應該寫過這樣的代碼:
// 使用臨時變量self var circle = { radius: 10, outerDiameter() { var self = this; var innerDiameter = function() { console.log(2 * self.radius); }; innerDiameter(); } }; circle.outerDiameter(); // 打印20
outerDiameter函數是circle對象的方法,所以其this值就是circle對象。
那咱們直接寫this.radius多好啊,惋惜不能這麼寫,由於內層函數innerDiameter並不會繼承外層函數outerDiameter的this值。outerDiameter函數的this值就是circle對象,this.radius等於10。
可是,innerDiameter函數的this值不是circle對象,那它究竟是啥?它是innerDiameter函數執行時當前的context object,這個context object又是啥?其實我也暈了,因此不妨測試一下:
// innerDiameter函數中的this是window var circle = { radius: 10, outerDiameter() { var innerDiameter = function() { console.log(this === window); }; innerDiameter(); } }; circle.outerDiameter(); // 打印true
innerDiameter函數中的this是window,爲啥是window這個不去管它,反正不是circle對象。
所以,若是咱們直接在innerDiameter函數中使用this的話,就出問題了:
// 使用普通函數 var circle = { radius: 10, outerDiameter() { var innerDiameter = function() { console.log(2 * this.radius); }; innerDiameter(); } }; circle.outerDiameter(); // 打印NaN
因而,咱們不得不使用一個臨時變量self將外層函數outerDiameter的this值搬運到內層函數innerDiameter。
.bind(this)
咱們也可使用.bind(this)來規避this變來變去的問題:
// 使用.bind(this) var circle = { radius: 10, outerDiameter() { var innerDiameter = function() { console.log(2 * this.radius); }; innerDiameter = innerDiameter.bind(this); innerDiameter(); } }; circle.outerDiameter(); // 打印20
可是,不管是使用臨時變量self,仍是使用.bind(this),都不是什麼很簡潔的方式。
總之,普通函數的this取值多少有點奇怪,尤爲當咱們採用面向對象的方式編程時,不少時候都須要用到this,大多數時候咱們都不會去使用.bind(this),而是使用臨時變量self或者that來搬運this的取值,寫起來固然不是很爽,並且一不當心就會寫出BUG來。
正如MDN文檔所說:
Until arrow functions, every new function defined its own this value based on how the function was called。This proved to be less than ideal with an object-oriented style of programming.
箭頭函數
箭頭函數的this取值,規則很是簡單,由於this在箭頭函數中,能夠看作一個普通變量。
An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules.
箭頭函數沒有本身的this值,箭頭函數中所使用的this都是來自函數做用域鏈,它的取值遵循普通普通變量同樣的規則,在函數做用域鏈中一層一層往上找。
有了箭頭函數,我只要遵照下面的規則,this的問題就能夠基本上不用管了:
對於須要使用object.method()方式調用的函數,使用普通函數定義,不要使用箭頭函數。對象方法中所使用的this值有肯定的含義,指的就是object自己。
其餘狀況下,所有使用箭頭函數。
// 使用箭頭函數 var circle = { radius: 10, outerDiameter() { var innerDiameter = () => { console.log(2 * this.radius); }; innerDiameter(); } }; circle.outerDiameter(); // 打印20
對於內層函數innerDiameter,它自己並無this值,其使用的this來自做用域鏈,來自更高層函數的做用域。innerDiameter的外層函數outerDiameter是普通函數,它是有this值的,它的this值就是circle對象。所以,innerDiameter函數中所使用的this來自outerDiameter函數,其值爲circle對象。
結論
JavaScript是Brendan Eich花了10天時間設計出來的,所以各類莫名其妙的特性,this也算是其中一個奇葩。好在這些年ECMAScript標準發展很快也很穩定,每一年擼一個新的標準,多少能夠彌補一下JS的先天不足。
箭頭函數對於this取值規則的簡化,其實也就是爲了少給你們添亂,誰能記得住普通函數this取值的那麼多條條框框啊。。。
另外,MDN文檔絕對是一個寶藏,你們能夠多看看。