---
# System prepended metadata

title: 函式 & ES6語法介紹
tags: [HyUI4.0]

---

---
type: slide
---
# 函式 & ES6語法介紹

###### tags: `HyUI4.0`

---

# 函式 與 作用域

---

一個函式會包含三個部分

* 函式的名稱 (也可能沒有名稱，稍後會提到)
* 在括號 中的部分，稱為 參數，參數與參數之間會 用逗號 , 隔開
* 在大括號 { } 內的部分，內含需要重複執行的內容，是函式功能的主要區塊

---

``` javascript=

function square(number) {
  return number * number;
}

square(2);        // 4
square(3);        // 9
square(4);        // 16
```

---

定義函式的方式


* 函式宣告（Function Declaration）
* 函式運算式（Function Expressions）
* 透過 new Function 關鍵字建立函式

---

函式宣告/ 函式陳述式
（Function Declaration）

``` javascript=
function 名稱([參數]) {
  // 做某事
}
```
note:
函式宣告 是屬最常見的用法

---

函式運算式/函式表達式
（Function Expressions）

---

```javascript=
var square = function (number) {
  return number * number;
};
```

像這類沒有名字的函式在 JavaScript ，
通常稱它為「匿名函式」

---

透過 new Function 關鍵字建立函式

```javascript=
// 透過 new 來建立 Function "物件"
var square = 
    new Function('number', 'return number * number');
```

note:
透過 new Function 所建立的函式物件，每次執行時都會進行解析「字串」(如 'return number * number' ) 的動作，運作效能較差，所以通常實務上也較少會這樣做。

---


參考影片 
3.1_function 的寫法
3.2_function 帶參數

---

練習一下
[動手寫函式](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/write-reusable-javascript-with-functions)

---

### 變數的有效範圍 
  (Scope)

---

在 ES6 之前，JavaScript <br>變數有效範圍的最小單位
是以 function 做分界的
 
 
<!-- <small>
ES6 之後有 let 與 const。<br> 
與 var 不同的是，它們的 scope <br>是透過大括號 { } 來切分的。<br>
ex:區域變數： if、else、for、while
</small> -->

---

下列印出來會是？？

```javascript=
var x = 1;

var doSomeThing = function(y) {
  var x = 100;
  return x + y;
};

console.log( doSomeThing(50) );   // ?
console.log( x );                 // ?

```

<span>    
150<!-- .element: class="fragment" data-fragment-index="1" -->
</span> <br/> 
<span>    
1<!-- .element: class="fragment" data-fragment-index="2" -->
</span> 


---

如果 function 內部沒有 var x 呢？

---

自己的 function 內如果找不到，

就會一層層往外找，直到全域變數為止

```javascript=
var x = 1;
var doSomeThing = function(y) {
  // 內部找不到 x 就會到外面找，直到全域變數為止。
  // 都沒有就會報錯：ReferenceError: x is not defined
  return x + y;
};

console.log( doSomeThing(50) );   
```
<span>    
 51<!-- .element: class="fragment" data-fragment-index="1" -->
</span> <br/> 

---

### 沒有 var 宣告的變數很危險！

---

下列印出來會是？？
```javascript=
var x = 1;
var doSomeThing = function(y) {
  x = 100;
  return x + y;
};

console.log( doSomeThing(50) );   // ?
console.log( x );                 // ?

```
<span>    
 150<!-- .element: class="fragment" data-fragment-index="1" -->
</span><br/> 

<span>    
 100<!-- .element: class="fragment" data-fragment-index="2" -->
</span> 

note:
因為 function 內沒有重新宣告 x 變數，使得 x = 100 跑去變更了外層的同名變數 x



---


參考影片 
3.3_全域與區域變數

---

### 提升 (Hoisting)

---

變數和函數的宣告時
會在編譯階段中先被放入記憶體

---

下列印出來會是？？

```javascript=
var x = 1;

var doSomeThing = function(y) {
  console.log(x);   // 會出現什麼？

  var x = 100;
  return x + y;
    
};

```
<span>    
 undefined<!-- .element: class="fragment" data-fragment-index="1" -->
</span><br/> 

note:
雖然透過 var 對變數 x 來重新做宣告，但是呢，要是不小心在宣告前就使用了這個變數，這時候 JavaScript
就會開始尋找變數 x 了，在自己的 scope 找

雖然是在下面，但可以確認的是自己的 scope 裡面有宣告，於是就 很貼心地 「只會把宣告的語法」拉到這個 scope 的「最上面」


---

瀏覽器 (或者編譯器) 的眼中 
是長這樣

```javascript [2|3|4]

var doSomeThing = function(y) {
  var x;
  console.log(x);   // undefined

  x = 100;
  return x + y;
};
```

---

 JavaScript 的這種特性，稱作「變數提升」 
 
 強烈建議所有可能用到的變數
 都盡量在 scope 的最上面先宣告
 完成後再使用。

---

除了變數以外，函式也有提升

---

回憶一下 函式的定義有分 

<span>
「函式運算式」
<!-- .element: class="fragment" data-fragment-index="1" -->

```javascript=
var xxx = function() {...} 
```
</span>
 <span>   
<!-- .element: class="fragment" data-fragment-index="2" --> 
「函式宣告」

```javascript=
function xxx() {...}
```    
</span>

Note:
差別在於 函式宣告 提升 整個函式
而透過「函式運算式」只有提升宣告的變數

---

函式宣告

```javascript
square(2);    // 4

function square(number) {
  return number * number;
}
```

---


函式運算式

```javascript
square(2);    // TypeError: square is not a function

var square = function (number) {
  return number * number;
};
```

note:
函式宣告與函式運算式除了呼叫的時機不同外 執行上沒有明顯差異
為了避免錯誤 最好還是養成習慣 在不



---

參考影片 
3.4_hoisting 、var 觀念




---

# 重點回顧

---

* var宣告的變數有效範圍 (scope) 的最小切分單位是 function
 
* 即使是寫在函式內，沒有 var 宣告的變數會變成「全域變數」
 
* 變數都盡量在scope的最上方做宣告

* 「函式宣告」會提升 整個函式 而透過「函式運算式」只有提升宣告的變數


---

# ES6中的新特性

---

主要介紹有以下幾點

* let ＆ const
* 箭頭函式
* 樣板字面值

---

# let & const 

---

## 常數與變數

在ES6 之前 只有定義變數 沒有定義常數

* 常數 const
* 變數 let

---

const 一旦被賦值後，就不能被更動
let 則可以

```javascript=
//這個a是不可變的(常數)
const a = 10
//這行程式碼會發生錯誤: "a" is read-only(只能讀不能寫)
a = 11

//這個b是可變的(變數)
let b = 5
//b可以再改變其中的值
b = 6

```

---

const在宣告時，就要給它值，否則會報錯

```javascript=
const v10;
//Uncaught SyntaxError: Missing initializer 
//in const declaration
```

---

    
## 變量提升(Hoisting)


---

var在宣告前使用是可以的，不會報錯

```javascript=
console.log(v4); // undefined
var v4 = 5 ;
```

---

在 ES6 let 及 const
移除這個不直覺的現象，在宣告前不能使用

```javascript=
console.log(v4); 
//Uncaught ReferenceError: v4 is not defined at ES6.js:19
let v4 = 5 ;
console.log(v5);
//Uncaught ReferenceError: v5 is not defined at ES6.js:23
const v5 = 5 ;

```


---


## 不允許重複宣告

---

使用 var 即使重複宣告也不會報錯，
只會被後面宣告者覆蓋

```javascript=
var v6 = 5;
var v6 = 7;
console.log(v6); //7
```


---

使用 ES6移除這個不嚴謹的邏輯，

每個變數/常數在特定區塊下應該爲獨立的

```javascript=
let v7 = 5;
let v7 = 7;
console.log(v7);
//Uncaught SyntaxError: Identifier 'v7' has already been declared
const v8 = 5;
const v8 = 7;
console.log(v8);
//Uncaught SyntaxError: Identifier 'v8' has already been declared

```

---

## let 與 var 作用域


---

var 的變數範圍在 function，
而 let 的作用域在 block

note:
block 意指 {} 大括號)，除了 function 以外
if、for 的 {} 都屬於 let 的作用域。

---

用 var 宣告
```javascript=
function varMing () {
  var ming = '小明';
  if (true) {
    var ming = '杰哥';  
    // 這裡的 ming 依然是外層的小明，所以小明即將被取代
  }
  console.log(ming);  // '杰哥'
}
varMing(); 
```

---

用 let 宣告
```javascript=
function letMing () {
  let ming = '小明';
  if (true) {
    let ming = '杰哥';  
    // 這裡的 ming 是不同的，只有在這個 if block 才有作用
  }
  console.log(ming);  // '小明'
}
letMing();
```

---

參考影片 

3.5_let - if、function 用法
3.6_let、const 注意事項與使用時機

---

## 樣板字面值

---

把過去的 “字串與變數” 做串接時，
都必須使用「加號」做連結。

當文字比較多或是需要換行時就難以閱讀
「樣板字面值」
就是用來解決這樣的問題


---

傳統字串串接

```javascript=

const cash = 10;
const string = '氣氣氣氣';
const sentence = '我的 ' + cash + ' 元掉到水溝裡了，真是' + string;
console.log(sentence);  // 我的 10 元掉到水溝裡了，真是氣氣氣氣

```

---

使用「樣板字面值」

1. 文字內容外圍使用「反引號」(ㄅ左邊那個按鍵)把字串頭尾包起來

3. 使用 $ { 「變數」 或 「表達式內容」 }
   在 $ { } 內插入「變數」

---

```javascript=
const cash = 10;
const string = '氣氣氣氣';
const sentence =
`我的 ${ cash } 元掉到水溝裡了，真是${ string }`;

console.log(sentence);  
// 我的 10 元掉到水溝裡了，真是氣氣氣氣
```

---

多行字串

---

在普通的字串中，
我們需要使用如下的語法以達到換行的效果
(需要加上“\n” 來換行)

```javascript=

console.log('string text line 1\n' +
'string text line 2');
// "string text line 1
// string text line 2"

```

---

但使用樣板字面值，只需要撰寫
如下所示的程式碼，就能達到同樣的效果
(直接斷行)

```javascript=
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
```

---

$ { } 內插入「表達式」

---

使用 || 來設定「預設值」

當 “前面的值” 為 “假值 falsy” 時，
則使用「預設值」

---

```javascript=
const cash = 10;
const string = '';
const sentence = 
      `我的 ${cash} 元掉到水溝裡了，真是${ string ||'好生氣啊'}`;
console.log(sentence);  //我的 10 元掉到水溝裡了，真是好生氣啊

```

---

課程參考

3.7_樣板字面值（Template literals）基本介紹



---

# 箭頭函式
<small> arrow function）</small>

---

### 箭頭函式基本寫法

---

首先 看一下原本寫函式的方法
```javascript=
function greeting() {
  console.log('Hello, JavaScript!!');
}

greeting();

```

---

ES6 之後，我們可以把它改成箭頭函式的寫法

```javaascript=
const greeting = () => {
  console.log('Hello, JavaScript!!');
};

greeting();

```

---

如果只有一行 可以省略 { }
```javascript=
const greeting = () => console.log('Hello, JavaScript!!');
greeting();
```

---

如果我們的函式本身只是要回傳某個值的話，
可以把 return 這個字省略掉

```javascript=
const greeting = () => 'Hello, JavaScript!!';
console.log(greeting()); // 'Hello, JavaScript!!'

// 等同於這樣寫
const greeting = function () {
  return 'Hello, JavaScript!!';
};
```

---

在大括號內的 { } 是需要自行加入 return，
如果沒有傳入值則會出現 undefined

```javascript=
var callSomeone = (someone) => { someone + '吃飯了' }
console.log(callSomeone('小明')) // undefined

```

---

### 箭頭函式帶入參數值


---

如果有兩個以上參數，需要使用括號

```javascript=
const add = (a, b) => a + b;
console.log(add(3, 5));

// 等同於這樣寫
const add = function (a, b) {
  return a + b;
};
```


---

當函式只有一個參數時，不需要使用括號

```javascript=
const greeting = person => `Hello, ${person}`;
greeting('Aaron'); // Hello, Aaron

// 等同於這樣寫
const greeting = function (person) {
  return `Hello, ${person}`;
};

```

---

當函式沒有參數時，則一定要有括號

```javascript=
var callSomeone = () => '小明' + '吃飯了'
console.log(callSomeone())
```

---

參考影片

3.8_箭頭函式簡介

---


# 重點回顧

---

### let / var / const
1. const 一旦被賦值後，就不能被更動 let 則可以。
1. const 在宣告時，就要給它值，否則會報錯。
1. var 在宣告前使用是可以的，不會報錯，但是 let 和 const 則不行。
1. var 即使重複宣告也不會報錯，但是 let 和 const 則不行。
1. var 的變數範圍在 function，而 let 的作用域在 block。

---


| 宣告方式   | var    | let  | const |
| ---------- | ------ | ---- | ----- |
| 類型       | 沒有分 | 變數 | 常數  |
|  宣告給值   |  不用      | 不用     | 要給值      |
|  宣告後變更值   |  可以      | 可以     | 不行      |
| 重複宣告   | 可以   | 不行 | 不行  |
| 作用域範圍   | function   | block | block |
| 宣告前使用 | 可以   | 不行 | 不行 |


---

### 樣板字面值
1. 樣板字面值，文字內容外圍使用「反引號」，在 $ { } 內插入「變數」。
1. 樣板字面值支援多行字串，可以直接斷行。
1. 樣板字面值可以在 $ { } 內插入「表達式」，使用 || 來設定「預設值」。


---

### 箭頭函式

1. 當箭頭函式如果只有一行 可以省略 { }
1. 當箭頭函式如果只有一行 
   可以把 return 這個字省略掉
1. 但如果在大括號內的 { } 是需要自行加入 return，如果沒有傳入值則會出現 undefined
3. 如果只有帶一個參數 可以省略()
4. 沒有參數時則一定要有括號

---

## 參考資料

[函式 Functions 的基本概念](https://ithelp.ithome.com.tw/articles/10191549)

[從ES6開始的JavaScript學習生活](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part3/var_const_naming.html)

[MDN樣板字面值](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Template_literals)


[var 與 ES6 let const 差異](https://ithelp.ithome.com.tw/articles/10209121)

[ES6 章節：Template Literial](https://medium.com/vicky-notes/es6-%E7%AB%A0%E7%AF%80-template-literial-7309b9e3bebb)

[箭頭函式（arrow function）和它對 this 的影響](https://pjchender.dev/javascript/js-arrow-function/)

---


[控制判斷](https://hackmd.io/EwAG4WaqRy-t1Me5ySmv-g#/)

---

<style>
    .reveal h1{
        font-size:2em;
    }
    .reveal h1,.reveal h2 {
         color:#c9f2ff;
}
    .reveal{
        font-size:26px;
    }
</style>