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