---
# System prepended metadata

title: JS 核心 16 - 函式參數
tags: [' 函式參數', 'JS 核心 ', 'JS ', ' JavaScript']

---

---
title: 'JS 核心 16 - 函式參數'
tags: JS 核心 ,JS , JavaScript, 函式參數
description: 2021/02/13
---

JS 核心 -- 函式參數
===

## 函式在運行時會帶入的變數

```
var globalVariable = '全域變數';  // 定義了全域變數
var obj = {                      // 在此物件下，定義了另一段函式
  aFunction: function(para) {    // 帶入三個參數，只取其中一個參數
    var localVariables = '區域變數';　// 定義的區域變數　
    console.log(para, localVariables, arguments, this, globalVariable);
  }
}
obj.aFunction('一段描述', 2, 3);   // 執行物件內的函式，同時也有帶參數進來
```

* para : 傳入的參數。外層傳入三個參數，但函式內層只會接收第一個參數。
* localVariables :　在 aFunction 環境下定義的區域變數。
* arguments ： 是一個類陣列。無論傳入多少參數，都可全部接收。
* this ： 執行函式時會自動帶入的變數。執行物件內函式的 this 會與一般函式有所不同。
* globalVariable : 全域變數。
    * 並非來自於函式本身，是來自於外層的變數。
    * 在函式內無法取得此變數，所以函式會向外層尋找，並找到此變數為止。
    * 可參考[範圍鏈章節](https://hackmd.io/U0vADI2zR76UYnGXMaklAQ)。
    
![](https://i.imgur.com/mlrtX0g.png)

### :pencil2: **範例**

```
function callName(a) {  // 在傳入參數時已定義好值了，變數 a 已存在
  console.log(a);       // 小明

  var a;                // 宣告一個變數時，若此變數已經存在，則重複宣告是無作用的
  console.log(a);       // 小明

  a = '杰倫';           // 若要改變 a 的值，要使用重新賦予值的方式覆蓋掉
  console.log(a);      // 杰倫
}
callName('小明')
```


## 函式的陳述式 在執行 hositing 時，會把整個代碼移到最前方

```
function callName(a) {  // 在傳入參數時已定義好值了，變數 a 已存在
  console.log(a);   // 小明
  function a() {}   // 定義一個函式陳述式

  var a;            // 宣告一個變數時，若此變數已經存在，則重複宣告是無作用的
  console.log(a);   // 小明
  a = '杰倫';       // 若要改變 a 的值，要使用重新賦予值的方式覆蓋掉
  console.log(a);   // 杰倫
}
callName('小明')
```
執行結果為變數 a 被函式陳述式所取代了。  
函式陳述式 function a( ){ } 移到 console.log(a); 之前，但不會比參數更前方。  
> <span class="red">**變數 a 在參數一傳入時就已定義好了，hositing 不會影響變數 a 的值。**</span>  

```
function callName(a) { // 在傳入參數時已定義好值了，變數 a 已存在
  function a(){};      // 函式陳述式 hositing 移到前方，變數 a 被函式陳述式取代
  console.log(a);      // ƒ a(){}
 
  var a;           
  console.log(a);      // ƒ a(){}
  a = '杰倫';       
  console.log(a);      // 杰倫
}
callName('小明')
```

## 參數名稱可以自己定義

1. <span class="red">**參數名稱和傳入的值沒有關聯性**</span>  
2. 只重視參數有幾個值、順序是怎樣...，不會受到外層的名稱所影響
3. 若傳入的參數數量不足，會在後方補上 undefined ( 如同變數未給值，也是呈現 undefined )

```
function callMore(d, c, b, a) {
  console.log(d, c, b, a);
}
var a = 'a';
var b = 'b';
var c = 'c';
callMore(a, b, c);  // a b c undefined
```

## 若參數是物件，有傳參考的特性

> 物件透過參數傳遞，也會維持傳參考的特性  
> 很多程式碼規範都會建議不要去調整裡面的屬性參數，會導致原有的物件屬性被作調整

```
function callObject(obj) {
  obj.name = '杰倫家';　　// 修改物件內的屬性值
}
var family = {
  name: '小明家'
}
callObject(family);  // 執行 callObject 函式時，把物件傳進去
console.log(family); // {name: '杰倫家'}
```

## 回呼函式　Callback Function 
* 把函式當作另一個函式的參數，透過另一個函式來呼叫它
* 這個函式只會在滿足了某個條件才會被動的去執行
* 定義一段函式，並把函式傳進來


### 函式直接寫在參數內

> fn 是在 functinoB 內建立的一個參數，在這邊是要說明函式傳入的參數也可以是一個 function，並且在函式中呼叫傳入函式，而這也就是所謂的 callback function。

1. functinoB 執行時將函式作為參數傳入 fn，並在 functinoB 內執行。
2. fn 的小明做為參數傳遞給 functinoB 執行時的函式。

```
function functionB(fn) {  // 直接意義一段函式，並透過參數把函式傳進來
  fn('小明'); 　　　　　　　// 裡面執行的此段函式，會把參數傳遞到外層來
}
functionB(function(a){console.log(a)})    // 小明
// 執行這段函式時就可帶入另一段函式　(可以是匿名的)
```

### 預先把函式定義好

1. 直接把 callSomeone 函式帶入，等同說執行另外一段表達式。
2. 把 callSomeone 函式賦予到 fn 變數上，所以 callSomeone 函式不用帶參數。
3. 首先在這邊函式 callSomeone 被當作參數傳入到 functionB，所以 functionB 的 fn 其實就是 callSomeone 的參數。 
4. 直接在 functionB 中使用 fn (  ) 呼叫並傳入參數執行 functionB。
```
function callSomeone(name, a){  // 預先定義好另一段函式
  console.log(name + '你好', a)
}
function functionB(fn) {  // 直接定義一段函式，並透過參數把函式傳進來
  fn('小明', 1);          // 實際執行的是此段函式，會把參數回傳到外層
}
functionB(callSomeone);   // 小明你好 1
// 呼叫 functionB，然後傳入的參數是一個 function，也就是 callSomeone
// 注意傳入的函式並沒有執行
// 傳入 functionB 的是一個完整的函式
```

## arguments 變數 

* arguments 是專有名稱，不需另外定義，執行函式時就會自動帶上
* arguments 為類陣列 (物件)，可以做基本的陣列操作
    * 可使用 for 迴圈取值。
    * 沒有大多數陣列可使用的方法，會報錯。
* arguments 可自動帶上傳入所有參數的值

### arguments 類陣列可使用 for 迴圈取值。
```
function callArg(a) {
  console.log(a, arguments); 
  // 1  Arguments(4) [1, 2, 3, "4", callee: ƒ, Symbol(Symbol.iterator): ƒ]

  for (let index = 0; index < arguments.length; index++) {   // 試著使用 for 迴圈把值取出
    console.log(arguments[index]);      // 1, 2, 3, '4'
  }
}
callArg(1, 2, 3, '4')
```

### arguments 為類陣列不是純陣列，沒有大多數陣列可使用的方法，會報錯。
```
function callArg(a) {
  console.log(a, arguments);

  arguments.forEach(function() {  // 無法使用陣列方法
    
  })
}
callArg(1, 2, 3, '4')             // 跳錯，arguments.forEach is not a function
```














## :memo: 學習回顧  
:::info
* 函式在運行時會帶入的變數
    * para : 傳入的參數。若傳入參數很多，函式內層只會接收第一個參數。
    * localVariables :　在函式環境內定義的區域變數。
    * arguments ： 是一個類陣列。無論傳入多少參數，都可全部接收。
    * this ： 執行函式時會自動帶入的變數。執行物件內函式的 this 會與一般函式有所不同。
    * globalVariable : 全域變數。
        * 並非來自於函式本身，是來自於外層的變數。
        * 範圍鏈 : 在函式內無法取得此變數，所以函式會向外層尋找，並找到此變數為止。  
* 「函式的陳述式」在執行 hositing 時，會把整個代碼移到最前方，但不會比參數更前方。
    * 變數 a 在參數一傳入時就已定義好了，hositing 不會影響變數 a 的值。
* 參數名稱可以自己定義
    * 參數名稱和傳入的值沒有關聯性
    * 只重視參數有幾個值、順序是怎樣…，不會受到外層的名稱所影響
    * 若傳入的參數數量不足，會在後方補上 undefined
* 若參數是物件，有傳參考的特性
    * 建議不要去調整裡面的屬性參數，會導致原有的物件屬性被調整
* arguments 變數
    * arguments 是專有名稱，不需另外定義，執行函式時就會自動帶上
    * arguments 為類陣列 (物件)，可以做基本的陣列操作
    * 可使用 for 迴圈取值。
    * 沒有大多數陣列可使用的方法，會報錯。
    * arguments 可自動帶上傳入所有參數的值
:::

## :+1: 相關參考文件 
:::info
[JavaScript 什麼是Callback函式 (Callback Function)？](https://matthung0807.blogspot.com/2019/05/javascript-callback-callback-function.html)  
[你懂 JavaScript 嗎？#23 Callback](https://cythilya.github.io/2018/10/30/callback/)
:::

<style>
.red {
  color: red;
}
.green {
  color: green;
}
</style>