---
# System prepended metadata

title: JavaScript ES6第四章
tags: [第四章, ES6, JavaScript]

---

---
tags: JavaScript,第四章,ES6
---
# JavaScript ES6第四章
## 函數定義
![](https://i.imgur.com/NxxtqOP.jpg)
![](https://i.imgur.com/137o7om.jpg)
```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>
```
![](https://i.imgur.com/nhfa1r2.jpg)
## 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
![](https://i.imgur.com/WxcbdIF.jpg)
```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
![](https://i.imgur.com/gpzyrFS.jpg)
```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://i.imgur.com/M4hY0dK.jpg)
## 嚴格模式
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode
![](https://i.imgur.com/tWiQ0WM.jpg)
```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>
```
## 高階函數
![](https://i.imgur.com/3vaStxl.jpg)
短路運算
參考"轉換為布林值"
只用值或表達式參與邏輯運算
```
//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>
```
## 閉包
變量所在的函數就是閉包
主要作用:延伸了變量的作用範圍
![](https://i.imgur.com/zanWrlE.jpg)
![](https://i.imgur.com/2XrXp34.jpg)
```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
思考題待補完
:::
## 遞歸
![](https://i.imgur.com/kMXcwVb.jpg)
```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>
```
![](https://i.imgur.com/eHuN4pn.jpg)
## 深拷貝
```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>
```
![](https://i.imgur.com/7tSohUh.jpg)
![](https://i.imgur.com/USMG5mX.jpg)
