ES6 — 箭頭函數

一 爲何要有箭頭函數

咱們在平常開發中,可能會須要寫相似下面的代碼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

三 和普通函數的區別

從上面的例子中,咱們已經能夠看出箭頭函數的優點。
和普通函數相比,箭頭函數主要就是如下兩個方面的特色緩存

  1. 不綁定this,arguments
  2. 更簡化的代碼語法

第二個特色不須要過多贅述,下面咱們來看看不綁定this和arguments這兩個特色ide

3.1 不綁定this

什麼叫不綁定this,我我的的理解爲箭頭函數的this其實就是在定義的時候就肯定好的,之後無論怎麼調用這個箭頭函數,箭頭函數的this始終爲定義時的this
咱們仍是之前面的那個setInterval代碼爲例函數

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的值和調用這個函數的上下文有關。(注意是調用)
咱們用箭頭函數重寫上訴函數this

const Person = {
    'name': 'little bear',
    'age': 18,
    'sayHello': () => {
      setInterval(() => {
        console.log('我叫' + this.name + '我今年' + this.age + '歲!')
      }, 1000)
    }
Person.sayHello()

你們猜猜結果是什麼???
輸出的是我叫'little bear',今年18歲嘛?
哈哈,太天真了,我開始也是這樣想的,後面輸出以後發現結果不對,輸出的仍是undefined。爲何呢??
由於我把方法寫在了對象裏,而對象的括號是不能封閉做用域的。因此此時的this仍是指向全局對象。
因此,經過以上的錯誤能夠提醒咱們,最好不要用箭頭函數做爲對象的方法。
咱們須要從新舉一個例子,以下prototype

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,且與在哪裏調用沒有關係。

3.2 不綁定arguments

箭頭函數還有一個比較有特色的地方就是其不綁定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,最好仍是不要使用箭頭函數了。因此永遠沒有一個解決方案能解決全部事情,只有合適的應用場景。

相關文章
相關標籤/搜索