JavaScript面試題:一般函式與箭頭函式區別
也是考爛的一題,一定要會吧!
一般函式可以寫成函數陳述句或函數表示式:
//函數陳述句
function greet(){
console.log('hi')
}
//函數表示式
var anonymousGreet = function(){
console.log('hi')
}
詳細解釋可參考我之前寫的:Function statement & Function expression|函數陳述句 & 函數表示式 IIFE
而箭頭函式(arrow function expression)顧名思義就是長得像箭頭的函數,JavaScript ES6後開始支援,雖然被稱為箭頭函式,但其實是一種表示式:
const greetFn = (greet) => {
console.log(greet +' Wendy')
}
greetFn('hi')
//hi Wendy
除了看起來簡潔之外,兩者還有什麼差異?
this指向不同
一般函式的this指向「呼叫方式」
// 有一個一般函式叫做fn
const fn = function(){
console.log(this)
}
//把fn裝進一個物件中
let obj = {
fn: fn
}
fn()
用全域呼叫fn()
→ 印出全域物件window
obj.fn()
用物件呼叫fn()
→印出obj
箭頭函式的this指向「箭頭函數被宣告的父層所在位置」
有夠拗口。反正就是箭頭函數沒有this
的觀念,所以要往上找父層,看父層在哪裡。
const fnArrow = ()=>{
console.log(this)
}
let obj = {
fnArrow: fnArrow
}
fnArrow()
obj.fnArrow()
fnArrow()
直接呼叫fnArrow()
→fnArrow()
位在全域中 → 印出全域物件window
obj.fnArrow()
呼叫物件內的fnArrow()
→fnArrow()
的父層是obj
→obj
在全域中 → 印出全域物件window
就算是在obj
內宣告箭頭函式:
let obj = {
fnArrow: ()=> (console.log(this))
}
obj.fnArrow()
fnArrow()
的父層是obj
→ obj
在全域環境中 → 印出全域物件window
讓人發瘋的變化題
let obj = {
func: function(){
let funcArrow =() => {
console.log('funcArrow',this)
}
funcArrow()
}
}
obj.func()
因為func:
後的函式是一般函式,所以是看呼叫的方法,this
會指向obj
這個物件。
變化題二
let obj = {
func: ()=>{
let funcArrow =() => {
console.log('funcArrow',this)
}
funcArrow()
}
}
obj.func()
因為func:
後的函式是箭頭函式,所以是看箭頭函式的父層所處的位置,此箭頭函式的父層是obj
,而obj
處在全域環境中,故this
指向全域物件window
。
箭頭函式不能使用call, apply, bind方法
.call(), .apply(), .bind()
是三個JS內建的方法,在一般函式中可以直接使用,而這三個方法的重點都是可以明確指定this
是誰。
fn.call(this, arg1, arg2..., argn)
fn.apply(this, [arg1, arg2..., argn])
fn.bind(this, arg1, arg2..., argn)
(本篇重點不是這三個方法怎麼使用故直接附上別人的解釋:https://hackmd.io/@VicSun/ryyG9x6dw)
大概是這樣嚕!!
參考資料:
https://medium.com/schaoss-blog/%E5%89%8D%E7%AB%AF%E4%B8%89%E5%8D%81-10-js-%E4%B8%80%E8%88%AC%E5%87%BD%E5%BC%8F%E8%88%87%E7%AE%AD%E9%A0%AD%E5%87%BD%E5%BC%8F%E7%9A%84%E5%B7%AE%E7%95%B0-32ce9455ff1a
https://www.casper.tw/javascript/2017/12/21/javascript-es6-arrow-function/
https://ithelp.ithome.com.tw/articles/10221214