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新特性箭頭函數文法、如何正确使用箭頭函數