# 閉包題目補充 閉包: 1.發生在execuation context 的 creation phase 2.在function execuation context,若一變數沒有在函式中被宣告,會向外查找外層的變數 (有權訪問另一個函式作用域中變數的函式) ## [通過閉包返回區域變數] [閉包調用方式01] ```+ function sayHi() { let name = 'coco'; return function () { return name + " says hi"; } } console.log(sayHi()()); ``` [閉包調用方式02] ```+ function sayHi() { let name = 'coco'; return function () { return name + " says hi"; } } let s = sayHi(); console.log(s()); ``` ## [閉包累加題目們] **[01以全域變數進行累加]** ```+ let age = 100; function getAge() { age++; } getAge(); console.log(age); getAge(); console.log(age); ``` **[02以區域變數進行累加]** ```+ function getAge() { let age = 100; age++; return age; } console.log(getAge()); console.log(getAge()); //以局部變數無法累加 因為每執行一次 100被初始化了 ``` **[03結合匿名函式&閉包進行累加]** ```+ function getAge() { let age = 100; return function () { age++; return age; } } console.log(getAge()()); console.log(getAge()()); //這樣就調用死了不會累加 重複調用了getAge() 還是會初始化 var s = getAge(); console.log(s()); console.log(s()); //普通函式getAge()只執行一遍 重複呼叫內層匿名函式即可 ``` ## [循環裡的閉包&匿名函式的取值問題們] [01] ```+ function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = function () { return i; }; } return arr; } var b = box(); for (var i = 0; i < 5; i++) { console.log(b[i]()); } ``` [題目解釋](https://1drv.ms/p/s!Ar8ou6d-D88lgTvX8U4HqbQPGjs9?e=STtpbD) [02 通過匿名函式及時自我執行] ```+ function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function (num) { return num; })(i); } return arr; } var b = box(); for (var i = 0; i < 5; i++) { console.log(b[i]); } ``` [03] ```+ function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function (num) { return function () { return num; }; })(i); } return arr; } var b = box(); for (var i = 0; i < 5; i++) { console.log(b[i]()); } ``` [04] ```+ function box() { var arr = []; for (let i = 0; i < 5; i++) { arr[i] = function () { return i; }; } return arr; } var b = box(); for (var i = 0; i < 5; i++) { console.log(b[i]()); } ``` ## [結合閉包&this的問題們] [01:this指定的對象是基於函數執行的環境所決定的,但**閉包中的this指向全域**] (可背!) ```+ var user="the window"; var box={ user:"the box", getUser:function(){ return function(){ return this.user; } } } console.log(box.getUser()()); ``` [02 讓閉包指向區域變數方法1:對象冒充] ```+ var user="the window"; var box={ user:"the box", getUser:function(){ return function(){ return this.user; } } } console.log(box.getUser().call(box)); ``` [03 讓閉包指向區域變數方法2:在作用域鏈上調整] ```+ var user="the window"; var box={ user:"the box", getUser:function(){ //這裡this的作用域指向box var that = this; return function(){ //這裡this的作用域指向window return that.user; } } } console.log(box.getUser()()); ``` ## [閉包通常和匿名函式結合-匿名函式常見型態] ```+ //1.把匿名函數賦值給變數 var hi = function () { return 'hi'; }; console.log(hi()); //2.通過自我執行來執行匿名函數 (function () { console.log("hi"); })(); //3.把匿名函數自我執行的返回值賦值給變數 var hi = (function () { return 'hi'; })(); console.log('hi'); //4.匿名函數自我執行傳參數 (function (age) { console.log(age); })(100); ``` ## 參考資料 很推薦的文章: [談談JavaScript中closure的概念系列1-4] https://pjchender.blogspot.com/2016/05/javascriptclosures.html https://pjchender.blogspot.com/2016/05/javascriptclosure.html https://pjchender.blogspot.com/2016/05/javascriptclosure-part-3.html https://pjchender.blogspot.com/2016/05/javascriptclosure-part-4.html [codepen](https://codepen.io/phoebe4561/pen/LYybaOL?editors=0012) ## 面試練習題們: (可以自己練習) [01] ```+ function makeAdder(x) { return function(y) { return x + y; }; } var add5 = makeAdder(5); var add10 = makeAdder(10); console.log(add5(2)); console.log(add10(2)); ``` [02] ```+ let x = 1 function A(y) { let x = 2 function B(z) { console.log(x + y + z) } return B } let C = A(2) C(3) ``` [03] ```+ let x = 5 function fn(x) { return function (y) { console.log(y + (++x)) } } let f = fn(6) f(7) fn(8)(9) f(10) console.log(x) ``` [04] ```+ let a = 0, b = 0 function A(a) { A = function (b) { console.log(a + b++) } console.log(a++) } A(1) A(2) ``` ![](https://i.imgur.com/OCvSafw.png) 答案: [1]7,12 [2]7 [3]14,18,18,5 [4]1,4 ```+ let myName="wilson"; function sayHi(){ let myName = "coco"; console.log(myName); function sayHi2(){ console.log(myName); } sayHi2(); } sayHi(); ```