---
tags: JavaScript,第四章,ES6
---
# JavaScript ES6第四章
## 函數定義


```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 1.具名函數
function fn() {}
// 2.匿名函數
var fun = function () {};
// 3. new Function('參數1','參數2','函數體')
var f = new Function('a', 'b', 'console.log(a+b)');
f(1, 2);
console.dir(f);
console.log(f instanceof Object); // true
</script>
</body>
</html>
```
## 函數調用
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button>123</button>
<script>
// 1.普通函數
function fn() {
console.log('安安');
}
fn();
fn.call();
// 2.對象的方法
var o = {
sayHi: function () {
console.log('hi');
}
};
o.sayHi();
// 3.構造函數
function Star() {}
new Star();
// 4.綁定事件函數
var btn = document.querySelector('button');
btn.onclick = function () {}; // 點擊按鈕就調用
// 5.定時器函數
setInterval(function () {
console.log(1);
}, 1000); // 定時器自動1秒調用一次
// 6.立即執行函數
(function () {
console.log('瞬間');
})();
</script>
</body>
</html>
```

## call
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 1. call()
var o = {
name: 'andy'
};
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn.call(o, 1, 2);
// 繼承用法
function Father(uname, age, sex) {
this.uname = uname;
this.age = age;
this.sex = sex;
}
function Son(uname, age, sex) {
Father.call(this, uname, age, sex);
}
var son = new Son('劉德華', 18, '男');
console.log(son);
</script>
</body>
</html>
```
## apply

```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var o = {
name: 'andy'
};
function fn(arr) {
console.log(this);
console.log(arr); // 打印會變字符串
}
fn.apply(o, ['pink']);
var arr = [1, 66, 3, 99, 4];
var max = Math.max.apply(Math, arr);
var min = Math.min.apply(Math, arr);
console.log(max, min);
</script>
</body>
</html>
```
## bind

```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="button" value="點擊" />
<button>按我</button>
<button>按我</button>
<button>按我</button>
<script>
var o = {
name: 'andy'
};
function fn(a, b) {
console.log(this);
console.log(a + b);
}
var f = fn.bind(o, 1, 2);
f();
// 案例
var input = document.querySelector('input');
input.onclick = function () {
this.disabled = true;
setTimeout(
function () {
this.disabled = false;
}.bind(this),
1000
);
};
// 案例2
var btn = document.querySelectorAll('button');
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
this.disabled = true;
setTimeout(
function () {
this.disabled = false;
}.bind(this),
1000
);
};
}
</script>
</body>
</html>
```
[demo網站](https://hackmd.io/a-KWROXGTimx5KrbsjAlUQ)
[面向對象tab欄製作](https://github.com/bahigabu/OOP_tabbar)
## 函數三方法總結

## 嚴格模式
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode

```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
'use strict';
</script>
<script>
(function () {
'use strict';
})();
</script>
<script>
function fn() {
'use strict';
// 下面按照嚴格模式
}
function fun() {
// 下面按照普通模式
}
</script>
</body>
</html>
```
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
'use strict';
// 1.變量必須先聲明再使用
// num = 10;
// console.log(num); // 報錯
// 2.不能隨意刪除聲明好的變量
// var num = 10;
// console.log(num);
// delete num; // 報錯
// 3.全局作用域的函數this指向undefined
function fn() {
console.log(this);
}
fn(); // undefined
// 4.構造函數不加new調用,this會報錯
function Star() {
this.sex = '男';
}
// Star(); // 報錯
var ldh = new Star();
console.log(ldh.sex);
// 5.定時器this還是指向window
setTimeout(function () {
console.log(this);
}, 1000);
// 6.函數裡的參數不准有重名
// function fun(a, a) { // 重名報錯
// console.log(a + a);
// }
// fun(1, 2);
// 7.if(){}for(){}花括號裡不准寫函數
// 8.但是函數包函數是可以的
</script>
</body>
</html>
```
## 高階函數

短路運算
參考"轉換為布林值"
只用值或表達式參與邏輯運算
```
//1.邏輯與
//如果第一個表達式為真,則返回表達式2
//如果第一個表達式為假,則返回表達式1
console.log(123 && 456); //456
console.log(0 && 456); //0
console.log(0 && 1 + 2 && 456 * 56789); //0
```
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./jQuery.min.js"></script>
<style>
div {
position: absolute;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div></div>
<script>
function fn(a, b, callback) {
console.log(a + b);
callback && callback();
}
fn(1, 2, function () {
console.log('最後調用');
});
$('div').animate({ left: 500 }, function () {
$('div').css('backgroundColor', 'purple');
});
</script>
</body>
</html>
```
## 閉包
變量所在的函數就是閉包
主要作用:延伸了變量的作用範圍


```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function fn() {
var num = 10;
function fun() {
console.log(num);
}
fun();
}
fn();
</script>
</body>
</html>
```
檢查斷點
在sources頁籤
在最後一行調用函數設斷點
然後看右邊欄位Scope
一步步經過後
裡面會有Local
還有Closure
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function fn() {
var num = 10;
// function fun() {
// console.log(num);
// }
// return fun;
return function () {
console.log(num);
};
}
var f = fn();
f();
// 類似於
// var f = function fun() {
// console.log(num);
// }
</script>
</body>
</html>
```
## 閉包應用
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul class="nav">
<li>000</li>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
<script>
var lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
lis[i].index = i;
lis[i].onclick = function () {
console.log(i);
console.log(this.index);
};
}
for (var i = 0; i < lis.length; i++) {
// 用for循環創建4個立即執行函數
// 立即執行函數成為小閉包,讓點擊事件函數可以打印i
// 此寫法複雜又浪費電腦效能
// i是實參,a是型參
(function (a) {
lis[a].onclick = function () {
console.log(a);
};
})(i);
}
</script>
</body>
</html>
```
異步任務三情況
1.定時器回調函數
2.事件回調函數
3.AJAX回調函數
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul class="nav">
<li>000</li>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
<script>
var lis = document.querySelector('.nav').querySelectorAll('li');
// for (var i = 0; i < lis.length; i++) {
// setTimeout(function () {
// console.log(lis[i].innerHTML);
// }, 3000);
// }
for (var i = 0; i < lis.length; i++) {
(function (a) {
setTimeout(function () {
console.log(lis[a].innerHTML);
}, 3000);
})(i);
}
</script>
</body>
</html>
```
## 打車案例
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 打車起步價13(3公里內),之後多一公里+5元
// 如果塞車總價就+10元
var car = (function () {
var start = 13; // 起步價 局部變量 閉包變量
var total = 0; // 總價 局部變量 閉包變量
return {
price: function (n) {
if (n <= 3) {
total = start;
} else {
total = start + (n - 3) * 5;
}
return total;
},
jam: function (flag) {
return flag ? total + 10 : total;
}
};
})();
console.log(car.price(5)); // 23
console.log(car.jam(true)); // 33
console.log(car.price(1)); // 13
console.log(car.jam(false)); // 13
</script>
</body>
</html>
```
:::danger
思考題待補完
:::
## 遞歸

```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var num = 1;
function fn() {
console.log('我要打印6句話');
if (num == 6) {
return; // 必須加退出條件
}
num++;
fn();
}
fn();
</script>
</body>
</html>
```
## 1到n階乘
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function fn(n) {
if (n == 1) {
return 1;
}
return n * fn(n - 1);
}
console.log(fn(3));
// 詳細思路,輸入3時
// return 3 * fn(2)
// return 3 * (2 * fn(1))
// return 3 * (2 * 1)
// return 3 * 2 * 1 = 6
</script>
</body>
</html>
```
## 費波那契數列
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 1、1、2、3、5、8、13、21
function fb(n) {
if (n === 1 || n === 2) {
return 1; // 可決定第一第二項的值
}
return fb(n - 1) + fb(n - 2);
}
console.log(fb(6));
// 詳細思路,輸入6時
// fb(5) + fb(4)
// (fb(4) + fb(3)) + (fb(3) + fb(2))
// ((fb(3) + fb(2)) + (fb(2) + fb(1))) + ((fb(2) + fb(1)) + (1))
// 用其他方法做
function fibonacci(n) {
var fib = [0, 1];
for (var i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib;
}
console.log(fibonacci(10)); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
</script>
</body>
</html>
```
## 遞歸遍歷數據
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var data = [
{
id: 1,
name: '家電',
goods: [
{
id: 1.1,
gName: '冰箱'
},
{
id: 1.2,
gName: '洗衣機'
}
]
},
{
id: 2,
name: '服飾'
}
];
function getID(json, id) {
json.forEach(function (item) {
if (item.id == id) {
console.log(item);
} else if (item.goods && item.goods.length > 0) {
getID(item.goods, id);
} // forEach本身自帶退出條件,遍歷完每個數組元素後退出
});
}
getID(data, 1);
getID(data, 2);
getID(data, 1.1);
</script>
</body>
</html>
```
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var data = [
{
id: 1,
name: '家電',
goods: [
{
id: 1.1,
gName: '冰箱'
},
{
id: 1.2,
gName: '洗衣機'
}
]
},
{
id: 2,
name: '服飾'
}
];
function getID(json, id) {
var o = {};
json.forEach(function (item) {
if (item.id == id) {
o = item;
} else if (item.goods && item.goods.length > 0) {
o = getID(item.goods, id); // 外層o = return 遞歸o
} // forEach本身自帶退出條件,遍歷完每個數組元素後退出
});
return o;
}
console.log(getID(data, 1));
console.log(getID(data, 2));
console.log(getID(data, 1.1));
console.log(getID(data, 1.2));
</script>
</body>
</html>
```
## 淺拷貝
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 淺拷貝只拷貝一層,更深層次對象只拷貝引用
// 深拷貝拷貝多層,每一級別的數據都會拷貝
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
var o = {};
for (var k in obj) {
// k屬性名
// obj[k]屬性值
o[k] = obj[k];
}
console.log(o);
o.msg.age = 20;
console.log(obj);
console.log('------');
Object.assign(o,obj);
console.log(o);
</script>
</body>
</html>
```

## 深拷貝
```javascript=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 淺拷貝只拷貝一層,更深層次對象只拷貝引用
// 深拷貝拷貝多層,每一級別的數據都會拷貝
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
// 封裝函數
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判斷是簡單數據類型還是複雜數據類型
// 1.獲取屬性值oldobj[k]
var item = oldobj[k];
// 2.判斷是否為數組(順序一定要先於對象)
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item);
// 3.判斷是否為對象
} else if (item instanceof Object) {
newobj[k] = {};
deepCopy(newobj[k], item);
// 4.剩下簡單數據類型
} else {
newobj[k] = item;
}
}
}
deepCopy(o, obj);
console.log(o);
var arr = [];
console.log(arr instanceof Object); // true
o.msg.age = 20;
console.log(obj);
</script>
</body>
</html>
```

