程式導師實驗計畫 [第二週] JavaScript 最後一塊拼圖:函式


基礎的函式與作用域理解可以參考這篇

[JavaScript 函式與作用域]


下列紀錄一些函式的理解

使用函式宣告而不是函式表達式

陳述句 vs 表達式

首先要先理解什麼是 Statement(陳述句)與 Expression (表達式))

  • Expression 表達式

    • 程式碼最終會產生一個數值

打開瀏覽器開發者工具的 console

  • a = 3 ; 回傳 3 代表這是 Expression

  • 10 + 5 ; 回傳 15 代表這是 Expression

  • a === 3 回傳 true 代表這是 Expression

  • a = { name: ‘Luke Lin’} 代表這是 Expression

  • Statement 陳述句

    • 程式碼不會產生一個數值

if()中的(),需要boolean來決定這個程式會不會成立,所以()之中會是表達式,但if(){}這段程式碼本身不會回傳數值,因此為 Statement 陳述句,。

1
2
3
if (a === 3) {
console.log(a);
}

函式陳述句 vs 函式表達式

函式也有分陳述句(Statement)表達式(Expression)

  • Function Statement函式陳述句

函式陳述句的程式碼本身不會回傳數值,除非執行它。
這種先宣告定義,等待被呼叫的寫法,也就是 Function Declation 函式宣告 ,在電腦創造他的階段就會被設定進記憶體,發生 提升Hoisting 的現象。

所以下面這段程式裡,function foo先執行才宣告也不會報錯,因為在創造階段function foo就已經被設定進記憶體中了。

1
2
3
4
foo();
function foo() {
console.log("test");
}
  • Function Expression函式表達式

function 會賦值到變數test中,而function本身沒有名字,也稱作匿名函式

1
2
3
4
5
const test = function () {
console.log("test");
};

test();

因為在電腦的創造階段被設定的是test的記憶體,因此當test在宣告function之前被執行,test之中是沒有function的,所以會報錯,這個規則使得箭頭函式可以完全取代函式表達式。

參考資料

使用預設參數的語法,而不是變動函式的參數

絕對不要變動參數裡原有的資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// really bad
function handleThings(opts) {
// Double bad: 如果 opt 是 false ,那們它就會被設定為一個物件,
// 或許你想要這麼做,但是這樣可能會造成一些 Bug。
opts = opts || {};
// ...
}

// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}

// good
function handleThings(opts = {}) {
// ...
}

不要將參數命名為 arguments,這樣會將覆蓋掉函式作用域傳來的 arguments

arguments: 指的是函式被呼叫時,真正傳入的參數值,指的是已經內建有一個了,不要再命名一個了。

1
2
3
4
5
6
7
8
9
// bad
function nope(name, options, arguments) {
// ...stuff...
}

// good
function yup(name, options, args) {
// ...stuff...
}

使用預設參數時請避免副作用

副作用是什麼?
函式的副作用並不代表好壞,具有副作用代表著可能會更動到外部環境,或是更動到傳入的參數值。

在使用預設參數時產生了副作用容易造成思緒混淆。

1
2
3
4
5
6
7
8
9
10
11
var b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 1
count(); // 1
count(); // 1

console.log(b); //傳入的參數值變成 5 了

切勿變更參數

直接更動作為參數的資料可能會產生呼叫者不期望的的副作用

1
2
3
4
5
6
7
8
9
// bad,變動到傳入的參數數值
function f1(obj) {
obj.key = 1;
}

// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, "key") ? obj.key : 1;
}

永遠將預設參數放在最後

1
2
3
4
5
6
7
8
//bad
function handleThings(opts = {}, name) {
//...
}
//good
function handleThings(name, opts = {}) {
//...
}

切勿重新賦值給參數

1
2
3
4
5
6
7
8
9
// bad
function f1(a) {
a = 1;
}

// good
function f3(a) {
const b = a || 1;
}

 以上就是這篇的筆記內容

推推的參考資料:

程式導師實驗計畫第三期