概述
在ECMAScript 6中允許使用箭頭(=>)定義函數(shù)洒擦。箭頭函數(shù)的語法多變论熙,根據(jù)實(shí)際的使用場景有多種形式
箭頭函數(shù)的語法
單一參數(shù)梦皮、函數(shù)體只有一條語句的箭頭函數(shù)定義如下
let welcome = msg => msg
/*
相當(dāng)于
function welcome(msg) {
return msg
}
*/
console.log(welcome("welcome you."))
如果一個(gè)函數(shù)有多個(gè)參數(shù)芹缔,則需要使用圓括號
let welcome = (user, msg) => `${user}, ${msg}`
/*
相當(dāng)于
function welcome(user, msg) {
return user + ", " + msg
}
*/
console.log(welcome("John", "welcome you."))
如果函數(shù)沒有參數(shù)驾孔,則需要使用一對空的圓括號表示
let welcome = () => "welcome you."
/*
相當(dāng)于
function welcome() {
return "welcome you."
}
*/
console.log(welcome())
如果函數(shù)體有多條語句秋度,則需要使用花括號包裹函數(shù)體
let add = (a, b) => {
let c = a + b
return c
}
/*
相當(dāng)于
function add(a, b) {
let c = a + b
return c
}
*/
console.log(add(4, 6))
如果要創(chuàng)建一個(gè)空函數(shù)炸庞,則需要使用一對圓括號來表示參數(shù)內(nèi)容并且使用一對花括號表示函數(shù)體部分
let emptyFunction = () => {}
/*
相當(dāng)于
function emptyFunction() {}
*/
如果箭頭函數(shù)的返回值是一個(gè)對象字面量,則需要將該字面量包裹在圓括號中
let createCar = (color, doors) => ({color : color, doors : doors})
/*
相當(dāng)于
function createCar(color, doors) {
return {
color : color,
doors : doors
}
}
*/
console.log(createCar("black", 4))
- 將對象字面量包裹在圓括號中是為了將其與函數(shù)體區(qū)分開
箭頭函數(shù)可以和對象解構(gòu)結(jié)合使用
let personInfo = ({name, age}) => `${name}'s age is ${age} years old.`
/*
相當(dāng)于
function personInfo({name, age}) {
return `${name}'s age is ${age} years old.`
}
*/
let person = {
name : John,
age : 18
}
console.log(personInfo(person))
箭頭函數(shù)與this
JavaScript中的this關(guān)鍵字與其他高級語言中的this引用或this指針不同荚斯,JavaScript中的this并不是指向?qū)ο蟊旧聿壕樱渲赶蚴强梢愿淖兊模鶕?jù)當(dāng)前執(zhí)行上下文的變化而改變事期。
代碼示例
<!DOCTYPE html>
<html>
<head>
<script>
var greeting = "Welcome"
function sayHello(user) {
alert(this.greeting + ", " + user)
}
var obj = {
greeting : "Hello",
sayHello : sayHello
}
// Welcome, John
sayHello("John")
// Hello, John
obj.sayHello("John")
var sayHi = obj.sayHello
// Welcome, John
sayHi("John")
</script>
</head>
</html>
下面來分析下上述代碼
- 調(diào)用sayHello("John")時(shí)滥壕,相當(dāng)于執(zhí)行window.sayHello("John"),因此函數(shù)內(nèi)部的this指向的是window對象兽泣,我們在代碼第一行定義的全局變量greeting將自動成為window對象的屬性绎橘,因此最后的結(jié)果是“Welcome, John”。
- 調(diào)用obj.sayHello("John")時(shí),函數(shù)內(nèi)部的this指向的是obj對象称鳞,而obj對象內(nèi)部定義了greeting屬性涮较,因此最后的結(jié)果時(shí)“Hello, John”。
- 調(diào)用sayHi("John")時(shí)冈止,雖然該函數(shù)是由obj.sayHello賦值得到狂票,但是在執(zhí)行sayHi()函數(shù)時(shí),當(dāng)前的執(zhí)行上下文對象時(shí)window對象熙暴,相當(dāng)于調(diào)用window.sayHi("John")闺属,因此最后的結(jié)果是“Welcome, John”。
再看這一段代碼
<!DOCTYPE html>
<html>
<head>
<script>
var obj = {
greeting : "Hello",
sayHello : function() {
setTimeout(function() {
alert(this.greeting)
}, 2000)
}
}
// undefined
obj.sayHello()
</script>
</head>
</html>
在這段代碼中周霉,調(diào)用obj.sayHello()時(shí)掂器,只是執(zhí)行了setTimeout()函數(shù),2s后才開始執(zhí)行setTimeout()函數(shù)參數(shù)中定義的匿名函數(shù)俱箱,而該匿名的執(zhí)行上下文對象是window唉匾,因此this指向的是window對象。顯然在window對象中并沒有定義greeting屬性匠楚,因此輸出的結(jié)果是undefined。
為了解決this指向問題厂财,可以使用函數(shù)對象的bind()方法芋簿,將this明確地綁定到某個(gè)對象上。
使用bind()方法綁定this對象
<!DOCTYPE html>
<html>
<head>
<script>
var greeting = "Welcome"
function sayHello(user) {
alert(this.greeting + ", " + user)
}
var obj = {
greeting : "Hello",
sayHello : sayHello
}
var sayHi = obj.sayHello.bind(obj)
// Hello, John
sayHi("John")
var obj = {
greeting : "Hello",
sayHello : function() {
setTimeout((function() {
alert(this.greeting)
}).bind(this), 2000)
}
// 或者用這種形式
/*
sayHello : function() {
var that = this
setTimeout(function() {
alert(that.greeting)
}, 2000)
}
*/
}
// Hello
obj.sayHello()
</script>
</head>
</html>
使用bind()方法實(shí)際上是創(chuàng)建了一個(gè)新的函數(shù)璃饱,稱為綁定函數(shù)与斤,該函數(shù)的this被綁定到參數(shù)傳入的對象。為了避免創(chuàng)建一個(gè)額外的函數(shù)荚恶,可以通過使用箭頭函數(shù)來更好的解決this問題撩穿。
箭頭函數(shù)中沒有this綁定,必須通過查找作用域來決定其值谒撼。如果箭頭函數(shù)被非箭頭函數(shù)包含食寡,則this綁定的是最近一層非箭頭函數(shù)的this;否則廓潜,this的值會被設(shè)置為全局對象抵皱。
使用箭頭函數(shù)修改上述代碼
<!DOCTYPE html>
<html>
<head>
<script>
var obj = {
greeting : "Hello",
sayHello : function() {
setTimeout(() => alert(this.greeting), 2000)
}
}
// Hello
obj.sayHello()
</script>
</head>
</html>
alert函數(shù)參數(shù)中的this與sayHello()方法中的this一致,而這個(gè)this指向的是obj對象辩蛋,因此最后調(diào)用obj.sayHello()的結(jié)果是Hello呻畸。
箭頭函數(shù)中的this值取決于該函數(shù)外部非尖頭函數(shù)的值,且不能通過call()悼院、apply()或bind()方法來改變this的值伤为。
箭頭函數(shù)在使用時(shí)需要注意以下幾點(diǎn)
- 沒有this、super据途、arguments和new.target綁定绞愚。在箭頭函數(shù)中 這些值由外圍最近一層非箭頭函數(shù)決定叙甸。
- 不要通過new關(guān)鍵字調(diào)用。因?yàn)榧^函數(shù)不能被用作構(gòu)造函數(shù)爽醋,所以使用new關(guān)鍵字調(diào)用箭頭函數(shù)會導(dǎo)致程序報(bào)錯(cuò)蚁署。
- 沒有原型蚂四。因?yàn)椴荒芡ㄟ^new關(guān)鍵字調(diào)用箭頭函數(shù)光戈,因此沒有構(gòu)造原型的需求,因此箭頭函數(shù)不存在prototype這個(gè)屬性遂赠。
- 不可以改變this的綁定。函數(shù)內(nèi)部的this值不可被改變筷弦,在函數(shù)的生命周期內(nèi)始終保持一致烂琴。
- 不支持arguments對象蜕乡。箭頭函數(shù)沒有arguments綁定奸绷,所以只能通過命名參數(shù)和rest參數(shù)這兩種形式訪問函數(shù)的參數(shù)。