JavaScript面試題:一般函式與箭頭函式區別

Wendy Chang
Wendy Loops
Published in
5 min readJan 17, 2023

也是考爛的一題,一定要會吧!

一般函式可以寫成函數陳述句或函數表示式:

//函數陳述句
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

--

--

Wendy Chang
Wendy Loops

什麼都寫ㄉ前端工程師 / 影片剪輯師 / 自媒體經營者