欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

js中的函數(shù)嵌套和閉包詳情

 更新時間:2021年11月11日 09:16:37   作者:飛鷹  
這篇文章主要介紹了js中的函數(shù)嵌套和閉包,在聊閉包這個問題之前,先了解一下變量的定義域,在js中,變量定義域有全局作用域和局部作用域之說,文章主要介紹函數(shù)的作用域,需要的朋友可以參考一下

前言:

今天就先和大家一起聊一聊我理解的閉包。在聊這個問題之前,先了解一下變量的定義域。
在js中,變量定義域有全局作用域和局部作用域之說。es6中新出現(xiàn)的變量聲明關(guān)鍵字,就是為了解決部分變量作用域混亂引入的。全局作用域在這就不談了。主要說說函數(shù)的作用域。

一、作用域

簡單一點(diǎn)說,函數(shù)的作用域,就是函數(shù)的花括號內(nèi)部,先看兩個例子,或許能對這個概念理解的更好一點(diǎn)

function f1(){
  let n = 999
  console.log(n)
}
f1() // 999

function f2(){
  let n = 999
}
alert(n); // 報錯

二、函數(shù)的返回值

要說閉包之前,我得先說一下函數(shù)返回值。關(guān)于函數(shù)的返回值,小編也是年初才有了一個更深層次的理解。沒有返回值的函數(shù),執(zhí)行之后會返回undefined,有返回值的函數(shù),執(zhí)行之后就變成了對應(yīng)的返回值。就像這樣

// 沒有返回值的函數(shù)
function f1(){
  alert(666)
}
console.log(f1()) // 出現(xiàn)彈窗之后,在控制臺輸出undefind

// 存在返回值
function f2(){
  alert(666)
  return 'over'
}
console.log(f2()) // 出現(xiàn)彈窗之后,在控制臺輸出over。當(dāng)然,可以返回字符串,也可以返回Bealon,還可以返回函數(shù)。

三、函數(shù)嵌套

在《重構(gòu)——改善既有代碼的設(shè)計(jì)》中,提出了js語法是允許函數(shù)內(nèi)部嵌套函數(shù)的,但并不是所有的編程語言都可以的,所謂代碼嵌套,就是在函數(shù)內(nèi)部又有函數(shù)聲明,

就像這樣:

function outer(){
  let name = 'lilei'
  function inner(){
    console.log(name)
  }
}  

四、閉包

前面說明了在js中的局部變量作用域的問題,在實(shí)際項(xiàng)目中,就是需要在函數(shù)外部,訪問函數(shù)內(nèi)部的變量,這個時候,按照局部變量作用域的問題。似乎是不可能的,閉包的出現(xiàn),解決了這個問題。

function outer(){
  let name = 'lilei'
  function inner(){
    return name
  }
  return inner
}

上面是一個典型的閉包函數(shù),在使用這個閉包函數(shù)的時候,我們可以這樣:

let g = outer()
console.log(g()) // lilei


至此,已經(jīng)解決了在全局訪問函數(shù)內(nèi)的局部變量。但是小編在回家的路上在想,為了實(shí)現(xiàn)這個功能,是不是不用這個麻煩,我通過這樣的函數(shù),也是可以滿足需求的。

function outer(){
  let name = 'lilei'
  return name
}

console.log(outer()) // lilei  


確實(shí)上面的代碼和通過閉包最終在控制臺輸出的內(nèi)容是一樣的,那為什么還要引入閉包呢?小編也是想了接近一周才明白的,這就好比變量->函數(shù)->類,每層往上都是逐步提升的過程,通過函數(shù)可以實(shí)現(xiàn)更多的邏輯,比如對數(shù)據(jù)進(jìn)行處理,僅僅靠變量是不能實(shí)現(xiàn)的。

五、閉包的實(shí)際應(yīng)用

上面小編介紹了閉包,那么在實(shí)際項(xiàng)目中有什么應(yīng)用呢?先看下面代碼:

1、隱藏內(nèi)部變量名稱和函數(shù)執(zhí)行暫停

function outer() {
    let name = 1
    function inner() {
        return name ++
    }
    return inner
}
let g = outer()
console.log(g()) // 2
console.log(g()) // 3
console.log(g()) // 4
console.log(g()) // 5

2、setTimeout函數(shù)傳遞參數(shù)

默認(rèn)的setTimeout是這樣的:

小編也曾經(jīng)這樣試驗(yàn)過

function f1(p) {
    console.log(p)
}
setTimeout(f1(666),3000) // 并沒有延時,直接輸出666

要想通過延時來實(shí)現(xiàn)對函數(shù)傳遞參數(shù),這時候,閉包的作用就顯現(xiàn)出來了。

function f1(a) {
    function f2() {
        console.log(a);
    }
    return f2;
}
var fun = f1(1);
setTimeout(fun,1000); // 一秒之后打印出1

3、回調(diào)

  定義行為,然后把它關(guān)聯(lián)到某個用戶事件上(點(diǎn)擊或者按鍵)。代碼通常會作為一個回調(diào)(事件觸發(fā)時調(diào)用的函數(shù))綁定到事件。就像下面這塊代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>測試</title>
</head>
<body>
    <a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  id="size-12">12</a>
    <a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  id="size-20">20</a>
    <a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  id="size-30">30</a>

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

        var size12 = changeSize(12);
        var size14 = changeSize(20);
        var size16 = changeSize(30);

        document.getElementById('size-12').onclick = size12;
        document.getElementById('size-20').onclick = size14;
        document.getElementById('size-30').onclick = size16;
</script>
</body>
</html>

4、函數(shù)防抖

  在事件被觸發(fā)n秒后再執(zhí)行回調(diào),如果在這n秒內(nèi)又被觸發(fā),則重新計(jì)時。

   實(shí)現(xiàn)的關(guān)鍵就在于setTimeout這個函數(shù),由于還需要一個變量來保存計(jì)時,考慮維護(hù)全局純凈,可以借助閉包來實(shí)現(xiàn)。就像下面這樣:

/*
* fn [function] 需要防抖的函數(shù)
* delay [number] 毫秒,防抖期限值
*/
function debounce(fn,delay){
    let timer = null    //借助閉包
    return function() {
        if(timer){
            clearTimeout(timer) //進(jìn)入該分支語句,說明當(dāng)前正在一個計(jì)時過程中,并且又觸發(fā)了相同事件。所以要取消當(dāng)前的計(jì)時,重新開始計(jì)時
            timer = setTimeOut(fn,delay) 
        }else{
            timer = setTimeOut(fn,delay) // 進(jìn)入該分支說明當(dāng)前并沒有在計(jì)時,那么就開始一個計(jì)時
        }
    }
}

六、使用類實(shí)現(xiàn)類似閉包中隱藏內(nèi)部變量功能

上面是一個關(guān)于閉包的實(shí)際應(yīng)用,小編在晚上睡不著覺的時候,想起同樣的需求,是不是也可以通過類來實(shí)現(xiàn)呢?最后經(jīng)過一頓折騰,答案是肯定的,就像這樣:

class Adder{
    constructor(c){
        this._c = c
    }
    increace(){
        this._c ++ 
    }
    decreace(){
        this._c --
    }
    get finalNum(){
        return this._c
    }
}
let c = new Adder(1)
c.increace()
console.log(c.finalNum) // 2
c.increace()
console.log(c.finalNum) // 3
c.increace()
console.log(c.finalNum) // 4
c.decreace()
console.log(c.finalNum) // 3

參考文章:

https://www.cnblogs.com/gg-qq...

https://www.cnblogs.com/pikac...

https://developer.mozilla.org...

相關(guān)文章

最新評論