天天看點

ECMAScript6-ES6箭頭函數:箭頭函數文法、箭頭函數裡的this指向一、通常函數的定義方法二、箭頭函數的定義方法三、this指向四、箭頭函數的弊端五、總結

ES6标準新增了一種新的函數:Arrow Function(箭頭函數)。

一、通常函數的定義方法

var fn1 = function(a, b) {
    return a + b
}
 
function fn2(a, b) {
    return a + b
}
           

二、箭頭函數的定義方法

使用ES6箭頭函數文法定義函數,将原函數的“function”關鍵字和函數名都删掉,并使用“=>”連接配接參數清單和函數體。

var fn1 = (a, b) => {
    return a + b
}
 
(a, b) => {
    return a + b
}
           

當函數參數隻有一個,括号可以省略;但是沒有參數時,括号不可以省略。

// 無參
var fn1 = function() {}
var fn1 = () => {}
 
// 單個參數
var fn2 = function(a) {}
var fn2 = a => {}
 
// 多個參數
var fn3 = function(a, b) {}
var fn3 = (a, b) => {}
 
// 可變參數
var fn4 = function(a, b, ...args) {}
var fn4 = (a, b, ...args) => {}
           

箭頭函數相當于匿名函數,并且簡化了函數定義。箭頭函數有兩種格式:

  • 一種隻包含一個表達式,省略掉了{ … }和return。
    () => return 'hello'
    (a, b) => a + b
               
  • 還有一種可以包含多條語句,這時候就不能省略{ … }和return
    (a) => {
      a = a + 1
      return a
    }
               

如果傳回一個對象,需要特别注意,如果是單表達式要傳回自定義對象,不寫括号會報錯,因為和函數體的{ … }有文法沖突。注意,用小括号包含大括号則是對象的定義,而非函數主體

x => {key: x} // 報錯
x => ({key: x}) // 正确
           

三、this指向

1、非箭頭函數

在非箭頭函數裡,this的指向在函數定義的時候是确定不了的,隻有函數執行的時候才能确定this到底指向誰,實際上this的最終指向的是那個調用它的對象

var Person = {
	firstName:'Tom',
	lastName:'Lee',
	getFullName:function(){
		console.log('this01 = ')
		console.log(this)
		var first = this.firstName
		var fn = function(){
			console.log('this02 = ')
			console.log(this)
			return this.firstName + this.lastName
		}
		return fn()
	}
}
Person.getFullName()
           

列印結果:

this01 = {firstName: "Tom", lastName: "Lee", getFullName: ƒ}
this02 = Window {0: global, window: Window, self: Window, document: document, name: "", location: Location, …}
NaN
           

2、箭頭函數

箭頭函數看上去是匿名函數的一種簡寫,但實際上,箭頭函數和匿名函數有個明顯的差別:箭頭函數内部的this是詞法作用域,由上下文确定。(詞法作用域就是定義在詞法階段的作用域。換句話說,詞法作用域是由你在寫代碼時将變量和塊作用域寫在哪裡來決定的,是以當詞法分析器處理代碼時會保持作用域不變 。)

現在,箭頭函數完全修複了this的指向,this總是指向詞法作用域,也就是外層調用者Person

var Person = {
	firstName:'Tom',
	lastName:'Lee',
	getFullName:function(){
		console.log('this01 = ')
		console.log(this)
		var first = this.firstName
		var fn = () => {
			console.log('this02 = ')
			console.log(this)
			return this.firstName + this.lastName
		}
		return fn()
	}
}
Person.getFullName()
           

列印結果:

this01 = {firstName: "Tom", lastName: "Lee", getFullName: ƒ}
this02 = {firstName: "Tom", lastName: "Lee", getFullName: ƒ}
"TomLee"
           

四、箭頭函數的弊端

JavaScript中的每一個Function對象都有一個apply()方法和一個call()方法

  • apply調用一個對象的一個方法,用另一個對象替換目前對象。例如:B.apply(A, arguments);即A對象調用B對象的方法。func.apply(thisArg, [argsArray])
  • call調用一個對象的一個方法,用另一個對象替換目前對象。例如:B.call(A, args1,args2);即A對象調用B對象的方法。func.call(thisArg, arg1, arg2, …)

由于this在箭頭函數中已經按照詞法作用域綁定了,是以,用call()或者apply()調用箭頭函數時,無法對this進行綁定,即傳入的第一個參數被忽略

1、非箭頭函數

var Person = {
	firstName:'Tom',
	lastName:'Lee',
	getFullName:function(firstName){
		console.log('this01 = ')
		console.log(this)
		var first = this.firstName
		var fn = function(f){
			console.log('this02 = ')
			console.log(this)
			return f + this.lastName
		}
		return fn.call({firstName:'hh'},firstName)
	}
}
Person.getFullName('hi')
           

列印結果:

this01 = {firstName: "Tom", lastName: "Lee", getFullName: ƒ}
this02 = {firstName: "hh"}
"hiundefined"
           

2、箭頭函數

var Person = {
	firstName:'Tom',
	lastName:'Lee',
	getFullName:function(firstName){
		console.log('this01 = ')
		console.log(this)
		var first = this.firstName
		var fn = (f) => {
			console.log('this02 = ')
			console.log(this)
			return f + this.lastName
		}
		return fn.call({firstName:'hh'},firstName)
	}
}
Person.getFullName('hi')
           

列印結果:

this01 = {firstName: "Tom", lastName: "Lee", getFullName: ƒ}
this02 = {firstName: "Tom", lastName: "Lee", getFullName: ƒ}
"hiLee"
           

使用箭頭函數之後,不再需要以前hack的寫法,var that = this。但不能盲目的使用ES6箭頭函數。

五、總結

  • 類似于匿名函數,在某些情況下使用,可減少代碼量
  • 代碼簡潔,this提前定義
  • 代碼太過簡潔,導緻不好閱讀
  • this提前定義,導緻無法使用js進行一些在ES5裡面看起來非常正常的操作(若使用箭頭函數,在監聽點選事件的回調函數中,就無法擷取到目前點選的元素咯,詳見《正确使用箭頭函數——什麼時候不該用ES6箭頭函數》
  • 總的來說,箭頭函數隻是一種函數的簡寫,有其利弊,可用可不用,看大家心情,當然也得用的正确

參考資料:

ES6新特性箭頭函數文法、如何正确使用箭頭函數

繼續閱讀