---
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>