函式
什麼是函式
「函式」指的是將一或多段程式指令包裝起來,可以重複使用,也方便維護。
函式是物件的一種
一個函式會有以下特性:
- 函式是可被呼叫的。
- 函式的名稱 (也可能沒有名稱)。
- 在括號
( )
中的部分,稱為「參數 (arguments) 」,參數與參數之間會用逗號,
隔開。 - 在大括號
{ }
內的部分,內含需要重複執行的內容,是函式功能的主要區塊。
宣告函式的方法
- 具名函式
使用function 名稱(參數) { ... };
的方式
function functionA() { |
-
匿名函式
透過變數名稱 = function(參數){ ... };
的方式,將一個函式透過=
指定給某個變數。var functionB = function () {
console.log('匿名函式', '函式表達式');
console.log(functionB)
}
functionB()在匿名函式中,如果想要在 function 後面加上一個名字也是可以的,但是要注意的是,這個名字只在「自己函式的區塊內」有效。
脫離了函式自身區塊後,變數functionD
就不存在了。var functionC = function functionD() {
console.log(functionC, functionD)
//具名函式能在函式內被調用
}
functionC()
console.log(functionC)
console.log(functionD) //functionD is not definedvar num = 1 ;
var giveMeMoney = function giveMoreMoney(coin) {
num += 1;
console.log('執行 giveMeMoney', num, coin);
return coin > 100 ? coin : giveMoreMoney(num*coin);
}
console.log(giveMeMoney(30))function callSomeOne(fn) {
fn()
}
callSomeOne(function() {console.log('執行函式')}) -
透過
new Function
關鍵字建立函式
使用new Function
(注意 F 大寫) 這個關鍵字來建立函式物件。
使用時將參數與函式的內容依序傳入Function
// 透過 new 來建立 Function "物件" |
透過
new Function
所建立的函式物件,每次執行時都會進行解析「字串」(如'return number * number'
) 的動作,運作效能較差,所以通常實務上也較少會這樣做。
- 箭頭函式 The arrow function expression (=>)
ES6新增的箭頭函式,使程式碼更為精簡。
將function
改成=>
,並移至()
的後方。
Arrow() => { |
立即函式(IIFE)
IIFE
IIFE (Immediately Invoked Function Expression) 是一個定義完馬上就執行的 JavaScript function,是一種常見的設計模式。
又可稱為 Self-Executing Anonymous Function。
IIFE包含兩部分
- 使用 Grouping Operator
()
包含的匿名函式。 - 馬上執行 function 的 expression
()
,JavaScript 引擎看到它就會立刻轉譯該 function。
(function(參數){ ... })()
特性:
- 定義完立刻就執行
- 無法於函式外再次被執行
(function IFFE() {
console.log('立即函式', IFFE)
})();
console.log(IFFE) - 限制變數的作用域:function scope 內的變數在外面是無法存取的。
(function () {
var Name = 'IFFE';
console.log(Name) //IFFE
})();
console.log(Name) //Name is not defined - 可以傳遞參數
(function (para) {
console.log('IFFE' + para) //IFFE可以傳遞參數
})('可以傳遞參數');
// 把 IIFE 設定變數並儲存它的結果
var result = (function (parameter) {
return parameter
})('return IFFE 結果')
console.log(result) //return IFFE 結果 - 須符合ASI規則:因立即函示不包含在ASI的規則內,故於2個函式間須插入
;
,否則會出現錯誤。
(function () { |
(function () { |
- function間傳遞參數
利用物件傳參考的特性,讓不同的function可以互相傳遞。
var a = {}; |
透過全域物件傳遞變數,常使用在大型框架上,如 Vue.js,此方式可以確保框架可以正確的掛載於全域物件上。
(function (global) { |
其它形式
- JSLint:符合 JSLint 的版本,須將 expression
()
包進外層的 grouping operator()
內。
(function () { |
- Arrow function:ES6新增的箭頭函式,使程式碼更為精簡,但行為一致。
(() => { |
- Async function:ES7新增的
async
,目前主要為了 top level await 而使用。
(async function () { |
參數
什麼是參數(parameter)?
參數其實就是我們會帶入函式的變數。
var globalVariable = '全域變數'; |
Hoisting與參數的關係
- function的變數在傳入前已經定義完成,故function內無法重複宣告變數。
- Hoistion並無會影響傳入的參數
- 範例一:
function callFunction(a) { |
- 範例二:
function callFunction(a) { |
參數與傳入值之間的關聯性
function callMore (d, c, b, a) { |
callback function
function helloWorld(para) { |
arguments
arguments會包含所有你放入function中的參數值。
arguments回傳的值是斜體的 [ ] ,它並不是真的陣列而是一個 類陣列。
註:類陣列是指以數值索引的值所成的群集,它可能是串列但並非真正的陣列。可使用
for
但不能使用indexOf
、concat
、forEach
等操作。
function callArg(a) { |
展開運算子spread(…)
JavaScript於ES6中另外提供了一個展開運算子(spread),由3個 .
組成 「…」。
可以把函數中許多的參數(arguments)或陣列中許多的元素(elements)展開(expand)成個別數值的速寫語法,簡單來說,就是把陣列裡面的值,拆解成一個一個。
function newFunction(a, b, ...other) { |
閉包 Closure
閉包(Closure)是函式以及該函式被宣告時所在的作用域環境(lexical environment)的組合。
- 運作原理:呼叫 Function 內的 Function。
- 內層 Function 作用域變數只會存在內層。
- 內層 Function 變數可以不被釋放,重複使用。
- 理解作用域。
大多數人會利用一個全域變數來儲存變數的資訊。但是,當程式碼開始變多了,過多的全域變數會造成不可預期的錯誤,像是變數名稱衝突、沒用到的變數無法回收等等的。
這時候改用閉包的做法就可以避免這些問題。
function storeMoney() { |
function counter() { |
function makeAdder(x) { |
參考:閉包 MDN
參考:閉包 重新認識 JavaScript
參考:閉包 邁向 JavaScript 勇者之路
延伸
因為作用域的關係,因為 var
會直接將 i
宣告成全域變數,不斷透過 for
迴圈累加,只會得到 3 這個數值。
function arrFun() { |
使用立即函示來限制作用域。
function arrFun() { |
使用ES6新增變數 let
。
因為 let
是屬於 block
變數,i
會被緊緊的鎖在 for…
後方的 {}
內。
function arrFun() { |
工廠模式
某些情形下函式的預設值是未知的,此時透過 ||
來加入預設值,在沒有輸入任何值的情況下會使用預設值代替。
function storeMoney(initValue) { |
透過物件的方式對初始值做不同的操作,可大幅增加函式的可用性。
function storeMoney(initValue) { |
this
What’s this?
this
是 JavaScript 的一個關鍵字。this
是 function 執行時,自動生成的一個內部物件。- 影響
this
的是在於函式的呼叫方法。 - 在大多數的情況下,
this
代表的就是呼叫 function 的物件 (Owner Object of the function)。
基本觀念
- 每一個執行環境都有屬於自己的
this
。 this
與函式如何宣告沒有關聯性,僅與呼叫方法有關。- 嚴格模式下,簡易呼叫會有很大改變。
this
的調用方式
- 簡易呼叫(大多數的呼叫方式)
- 物件方式(最常運用
this
的方法) bind
、apply
、call
方法。- new
- DOM 事件處理器
- 箭頭函式(Arrow functions)
Global context(全域環境)
In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.
在全域執行環境下,this
指向全域物件,瀏覽器中是Window
。
console.log( this === window ) //true |
Function context
Inside a function, the value of this depends on how the function is called.
簡易呼叫 (Simple call)
盡可能不要使用 Simple call 的 this直接調用函式,此函式的
this
會指向window
。範例一
無論在哪一層,簡易呼叫的方式this
都會指向window
。範例二
簡易呼叫的本質其實是function.prototype.call()
代入undefined
。call()
function f1() { |
window.a = '我是window' |
window.b = '我還是window' |
物件的調用(As an object method)
如果一個函式是以物件的方法呼叫,它的
this
會設為該呼叫函式的物件。
this
與函式如何宣告沒有關聯性,僅與呼叫方法有關。- 物件的調用,僅需要關注是在哪一個物件下呼叫。
var name = '我是window' |
var name = '我是window' |
bind
、 apply
、 call
方法
函式未以物件的方法呼叫,它的 this
會指向全域物件 window
。
此時可使用bind
、 apply
、 call
將 this
以特定的物件 or 純值傳入。
差異:
- call
- 函式會立刻執行。
- 語法大致上與
apply()
相同,不同處只有call()
接受一連串的參數。
- apply
- 函式會立刻執行。
- 語法大致上與
call()
相同,不同處只有apply()
使用單一的array作為參數。
- bind
- 函式不會立刻執行,須另外呼叫。
語法:
fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg
呼叫fun時提供的this值。可以為物件 or 純值。
在非嚴苛模式( non-strict mode ),null
、undefined
將會被置換成全域變數,而原生型態(純值)的值將會使用建構式方式建立。arg1
arg2
其他參數。call()
接受一連串的參數。
var obj = { name: '我是物件' } |
代入純值的情況下,純值(原生型態)的值將會使用建構式方式建立。
var name = '我是字串' |
非嚴苛模式( non-strict mode )下,代入null
、undefined
的情況下, this
將會被置換成全域變數。
function fn(para1, para2) { |
語法
fun.apply(thisArg, [argsArray])
thisArg
呼叫fun時提供的this值。可以為物件 or 純值。
在非嚴苛模式( non-strict mode ),null
、undefined
將會被置換成全域變數,而原生型態(純值)的值將會使用建構式方式建立。argsArray
一組陣列形式的參數(array-like object)。
如果沒有需要提供,可以傳入null
或undefined
。
var obj = { name: '我是物件' } |
代入純值的情況下,純值(原生型態)的值將會使用建構式方式建立。
var number = 100 |
非嚴苛模式( non-strict mode )下,代入null
、undefined
的情況下, this
將會被置換成全域變數。
function fn(para1, para2) { |
bind()
方法,會建立一個新函式。當該函式被呼叫時,會將 this
傳遞给 bind()
的第一個參數。
語法
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
當綁定的函式被調用時,該參數會做為this
而被指向。
當使用new
調用綁定的函式,此參數無效。arg1
arg2
當綁定的函式被調用時,這些參數加上綁定函數本身的參數會按照順序作為原函數運行時的參數。
如果傳入了多餘函式設定的參數,也只會取函式本身設定參數的數量。
var obj = { name: '我是物件' } |
代入純值的情況下,純值(原生型態)的值將會使用建構式方式建立。
var boolean = true |
非嚴苛模式( non-strict mode )下,代入null
、undefined
的情況下, this
將會被置換成全域變數。
window.x = 100 |
嚴謹模式 (strict mode)
- 加入
'use strict'
即可運作。 - 並不會影響不支援嚴謹模式的瀏覽器。
- 可依據執行環境設定
'use strict'
。 - 透過拋出錯誤的方式消除一些安靜的錯誤(意指不再靜默地忽略某些錯誤)。
- 禁止使用一些有可能被未來版本 ECMAScript 定義的語法。
In strict mode, however, if the value of this
is not set when entering an execution context, it remains as undefined
.
在嚴謹模式下,未定義的 this
不會指向執行環境的 window
,而是 undefined
。
function f2() { |
在嚴謹模式下,代入純值不會將純值以建構式方式建立,而是維持原來的型別。
var number = 100 |
代入 undefined
不會將 this
指向 window
,而是維持原來的型別。
function fn(para1, para2) { |
DOM (Document Object Model)
於空頁面下建立一個清單。
(function(){ |
var fn = function() { |
Arrow functions
待更新。