javascript之閉包七(閉包的應用場景)

1. 閉包應用場景之setTimeout

原生的setTimeout傳遞的第一個函數不能帶參數,經過閉包能夠實現傳參效果bash

setTimeout(function(param){
        alert(param)
    },1000)

    //經過閉包能夠實現傳參效果
    function func(param){
        return function(){
            alert(param)
        }
    }
    var f1 = func(1);
    setTimeout(f1,1000);
複製代碼

2. 閉包應用場景之回調

咱們定義行爲,而後把它關聯到某個用戶事件上(點擊或者按鍵)。咱們的代碼一般會做爲一個回調(事件觸發時調用的函數)綁定到事件上閉包

<body>
    <p>哈哈哈哈哈哈</p>
    <h1>hhhhhhhhh</h1>
    <h2>qqqqqqqqq</h2>
    <a href="#" id="size-12">12</a>
    <a href="#" id="size-14">14</a>
    <a href="#" id="size-16">16</a>

<script>
    function changeSize(size){
        return function(){
            document.body.style.fontSize = size + 'px';
        };
    }

    var size12 = changeSize(12);
    var size14 = changeSize(14);
    var size16 = changeSize(16);

    document.getElementById('size-12').onclick = size12;
    document.getElementById('size-14').onclick = size14;
    document.getElementById('size-16').onclick = size16;
</script>
</body>
複製代碼

3. 閉包應用場景之封裝變量

用閉包定義能訪問私有函數和私有變量的公有函數app

var counter = (function(){
        var privateCounter = 0; //私有變量
        function change(val){
            privateCounter += val;
        }
        return {
            increment:function(){   //三個閉包共享一個詞法環境
                change(1);
            },
            decrement:function(){
                change(-1);
            },
            value:function(){
                return privateCounter;
            }
        };
    })();

    console.log(counter.value());//0
    counter.increment();
    counter.increment();//2
複製代碼
  1. 共享的環境建立在一個匿名函數體內,當即執行。
  2. 環境中有一個局部變量一個局部函數,經過匿名函數返回的對象的三個公共函數訪問。
封裝一個私有變量另外一個例子:用JavaScript建立一個計數器:
'use strict';
function create_counter(initial) {
    var x = initial || 0;
    return {
        inc: function () {
            x += 1;
            return x;
        }
    }
}
複製代碼

運行結果:函數

var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
複製代碼

在返回的對象中,實現了一個閉包,該閉包攜帶了局部變量x,而且,從外部代碼根本沒法訪問到變量x。換句話說, 閉包就是攜帶狀態的函數,而且它的狀態能夠徹底對外隱藏起來。ui

4. 閉包應用場景之爲節點循環綁定click事件

function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push(function () {
            return i * i;
        });
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
複製代碼

在上面的例子中,每次循環,都建立了一個新的函數,而後,把建立的3個函數都添加到一個Array中返回了。spa

你可能認爲調用f1(),f2()和f3()結果應該是 1 4 9, 但實際結果是:.net

f1(); // 16
f2(); // 16
f3(); // 16
複製代碼

所有都是16!緣由就在於返回的函數引用了變量i,但它並不是馬上執行。等到3個函數都返回時,它們所引用的變量i已經變成了4,所以最終結果爲16。code

返回閉包時牢記的一點就是:返回函數不要引用任何循環變量,或者後續會發生變化的變量。對象

若是必定要引用循環變量怎麼辦?方法是再建立一個函數,用該函數的參數綁定循環變量當前的值,不管該循環變量後續如何更改,已綁定到函數參數的值不變:blog

function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i));
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

f1(); // 1
f2(); // 4
f3(); // 9
複製代碼

注意這裏用了一個「建立一個匿名函數並馬上執行」的語法:

(function (x) {
    return x * x;
})(3); // 9
複製代碼

5. ES6不經意中閉包的應用

有時候閉包會在你不經意的時候出現,你可能已經看到了咱們稱之爲局部應用程序的示例,以下面的代碼所示。

let c = 4
const addX = x => n => n + x
const addThree = addX(3)
let d = addThree(c)
console.log('example partial application', d)
複製代碼

若是不使用箭頭函數,等效的代碼以下:

let c = 4
function addX(x) {
  return function(n) {
     return n + x
  }
}
const addThree = addX(3)
let d = addThree(c)
console.log('example partial application', d)
複製代碼

咱們聲明瞭一個通用加法函數 addX,它接受一個參數(x)並返回另外一個函數。

返回的函數也接受一個參數並將其與變量 x 相加。

變量 x 是閉包的一部分,當在本地上下文中聲明變量 addThree 時,它會分配到一個函數定義和一個閉包,閉包含變量 x。

因此,當調用並執行 addThree 時,它能夠從閉包中訪問變量 x 和變量 n(做爲參數傳遞進去),並返回相加的和。

在這個示例中,控制檯將打印數字 7。

參考文章連接:

  1. blog.csdn.net/qq_21132509…
  2. www.liaoxuefeng.com/wiki/102291…
相關文章
相關標籤/搜索