函式與作用域

函式屬於物件的一種,分為「具名函式」和「匿名函式」,包含程式碼片段,可帶入參數,並可被呼叫。


具名函式 Named Function

具名函式顧名思義必須要有函式名稱。
而具名函式能夠在函式內被調用,但是函式中的具名函式無法在函式以外被調用。

1
2
3
4
5
6
7
8
9
10
11
function sayHello () {
function inner () {
return console.log('inner')
}
return console.log('Hello!')
}
function callSayHello () {
sayHello() // 具名函式能夠在函式內被調用
}
callSayHello() // Hello!
inner() // inner is not defined 無法被調用

匿名函式 Anonymous Function

函式名稱是可以被忽略的,也就是匿名函式,通常會用表達式來宣告匿名函式,另外立即函式(IIFE)也是屬於匿名函式。

1
2
3
4
5
6
7
8
9
var sayHello = function () {
console.log('Hello!')
;(function () {
console.log('Hey!')
})()
}
sayHello()
// Hello!
// Hey!

陳述式與表達式

  • 陳述式:Statement
1
2
// 函式陳述式、具名函式
function fn() { ... }
  • 表達式:Expression(運算式、表示式)
1
2
// 函式表達式、匿名函式
var fn = function() { ... }

函式作用域 Function Scope

函式有屬於自己的作用域,在 ES6 之前,「JavaScript 切分變數有效範圍的最小單位是 function」,所以在這個範圍內的變數只屬於這個函式,一旦離開函式範圍,記憶體就會被釋放掉。

1
2
3
4
5
6
7
8
var a = 3
function fn () {
var a = 6
var b = 10
}
fn()
console.log(a) // a = 3
console.log(b) // b is not defined

如果在函式裡面沒有重新宣告變數,那 function 就會向外一層一層找。
function 可以從內層讀取外層宣告的變數,但是外層沒辦法讀取內層宣告的變數,這種行為稱作「範圍鏈(Scope Chain)」。

1
2
3
4
5
6
7
8
9
10
11
var msg = 'global'
function outer() {
var msg = 'local'
function inner () {
return msg
}
return inner
}
var innerFunc = outer()
var result = innerFunc()
console.log(result) // local

範例中加了一段 var innerFunc = outer() ,呼叫 outer 回傳的 inner 結果,取得原本從外層無法讀取的 inner,看似好像把 inner 獨立出來,msg 向外查找所以結果是的外層 global
但有個重要觀念:範圍鏈是在函式被定義當下決定的,不是被呼叫的時候。
所以在「定義函式之後,呼叫函式之前」範圍鏈就已經被建立,msginner 外層的 local


參考文章