咱們在平常開發中,可能會須要寫相似下面的代碼javascript
const Person = { 'name': 'little bear', 'age': 18, 'sayHello': function () { setInterval(function () { console.log('我叫' + this.name + '我今年' + this.age + '歲!') }, 1000) } } Person.sayHello()
上例的輸出結果是什麼呢?可能對javascript特性不是很熟悉的同窗(我本身也是)會認爲輸出固然是
我叫little bear,今年18歲咯。若是你的答案是這個的話,那麼我要恭喜你,答錯了。其實上例的輸出結果是我叫undefined,今年我undefined歲。爲何會輸出這種結果呢?
這是由於setInterval執行的時候,是在全局做用域下的,全部this指向的是全局window,而window上沒有name和age,因此固然輸出的是undefined咯。不明白的同窗能夠去看看this的工做原理this。
那麼,咱們怎麼要解決這個問題呢?
一般的寫法是緩存this,而後在setInterval中用緩存的this進行操做,以下java
const Person = { 'name': 'little bear', 'age': 18, 'sayHello': function () { let self = this setInterval(function () { console.log('我叫' + self.name + '我今年' + self.age + '歲!') }, 1000) } } const sayHelloFun = Person.sayHello sayHelloFun()
使用上敘方法,輸出的結果就是你們所期待的我叫little bear,我今年18歲了。
那麼,你們可能會以爲這樣不科學,明明是寫在對象裏面的方法,爲何還要使用緩存這個對象才能正確使用。ECMA組織以爲這確實是個問題,以後在es6的新特性裏添加了箭頭函數,它能很好的解決這個問題。另外箭頭函數還用簡化代碼量的特色。git
箭頭函數的語法很是簡單,看一下最簡單的箭頭函數表示法() => console.log('Hello')
以前沒有接觸過箭頭函數的人可能會驚訝於其代碼的簡潔。對比以前若是要寫一個這樣的函數es6
function(){ console.log('hello') }
箭頭函數的簡潔性一目瞭然。
更多關於箭頭函數語法可點擊箭頭函數語法github
從上面的例子中,咱們已經能夠看出箭頭函數的優點。
和普通函數相比,箭頭函數主要就是如下兩個方面的特色segmentfault
第二個特色不須要過多贅述,下面咱們來看看不綁定this和arguments這兩個特色緩存
什麼叫不綁定this,我我的的理解爲箭頭函數的this其實就是在定義的時候就肯定好的,之後無論怎麼調用這個箭頭函數,箭頭函數的this始終爲定義時的this
咱們仍是之前面的那個setInterval代碼爲例ide
const Person = { 'name': 'little bear', 'age': 18, 'sayHello': function () { setInterval(function () { console.log('我叫' + this.name + '我今年' + this.age + '歲!') }, 1000) } Person.sayHello()
當Person.sayHello()去執行setInterval的時候,是在全局做用下執行的全部setInterval回調函數的this就爲全局對象。es3-5中的函數this的值和調用這個函數的上下文有關。(注意是調用)
咱們用箭頭函數重寫上訴函數函數
const Person = { 'name': 'little bear', 'age': 18, 'sayHello': () => { setInterval(() => { console.log('我叫' + this.name + '我今年' + this.age + '歲!') }, 1000) } Person.sayHello()
你們猜猜結果是什麼???
輸出的是我叫'little bear',今年18歲嘛?
哈哈,太天真了,我開始也是這樣想的,後面輸出以後發現結果不對,輸出的仍是undefined。爲何呢??
由於我把方法寫在了對象裏,而對象的括號是不能封閉做用域的。因此此時的this仍是指向全局對象。
因此,經過以上的錯誤能夠提醒咱們,最好不要用箭頭函數做爲對象的方法。
咱們須要從新舉一個例子,以下ui
function Person () { this.name = 'little bear', this.age = 18 let self = this setInterval(function sayHello () { console.log('我叫' + self.name + '我今年' + self.age + '歲!') }, 1000) } let p = new Person()
緩存this,而後輸出,能達到咱們想要的結果。
把上述例子改成箭頭函數的形式以下
function Person () { this.name = 'little bear', this.age = 18 setInterval(() => { console.log('我叫' + this.name + '我今年' + this.age + '歲') },1000) } let p = new Person()
咱們能夠看到,箭頭函數使用了定義時上下文的this,且與在哪裏調用沒有關係。
箭頭函數還有一個比較有特色的地方就是其不綁定arguments,即若是你在箭頭函數中使用arguments參數不能獲得想要的內容。
let arrowfunc = () => console.log(arguments.length) arrowfunc() //output arguments is not defined
因此在箭頭函數中咱們是不能直接使用arguments對象的,可是若是咱們又想得到函數的參數怎麼辦呢?
咱們可使用剩餘參數來取代arguments剩餘參數詳情
let arrowfunc = (...theArgs) => console.log(theArgs.length) arrowfunc(1,2) //output 2
前面咱們已經看到了不少關於es6箭頭函數的好處,也看到了箭頭函數的一些不足。那麼咱們應該在何時使用箭頭函數,而何時最好不要使用呢?
1.做爲對象的方法
在寫這篇博客的例子時,因爲本人的水平確實有限,致使了篇頭出現的錯誤。不過我也想由此告訴你們,最好不要在對象的方法中使用箭頭函數,這樣可能會致使一些問題的產生。除非你很熟悉箭頭函數。
2.不能做爲構造函數
因爲箭頭函數的this不綁定的特色,因此不能使用箭頭函數做爲構造函數,實際上若是這樣作了,也會報錯。
3.定義原型方法
function Person (name){ this.name = name } Person.prototype.sayHello = () => { console.log(this) } var p1 = new Person() p1.sayHello() //output window對象
這裏的this指向的是window對象,這點和在對象方法中定義有點像
箭頭函數因爲其代碼的簡潔性和不綁定調用者this的特色,在非方法函數中使用是最合適的,而在方法函數中使用,須要特別注意它的this綁定問題,若是須要動態的修改this,最好仍是不要使用箭頭函數了。因此永遠沒有一個解決方案能解決全部事情,只有合適的應用場景。
轉自:https://segmentfault.com/a/1190000009410939