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

JavaScript中閉包的作用和應(yīng)用場(chǎng)景

 更新時(shí)間:2023年09月19日 08:50:25   作者:紅豆泥豆紅  
這篇文章將給大家詳細(xì)介紹JavaScript?中閉包是什么,有哪些應(yīng)用場(chǎng)景,文章通過代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下

閉包是什么?

  • 閉包是指一個(gè)函數(shù)可以訪問并操作其詞法作用域外的變量的能力。
  • 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。
  • 例如在javascript中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,所以閉包可以理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)“。
  • 在本質(zhì)上,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來的橋梁。

特點(diǎn):函數(shù)嵌套,并返回子函數(shù),子函數(shù)訪問了外變量。

//外部函數(shù)
function outerFunction() {
    //內(nèi)部函數(shù)外的變量
    var outerVariable = 'I am from outer function'; 
    //返回內(nèi)部函數(shù)
    function innerFunction() { 
        console.log(outerVariable); 
    } 
    return innerFunction; 
} 
// outerFunction執(zhí)行完之后被銷毀,但是outerVariable被引用著所以仍然活著
var closure = outerFunction(); 
closure(); // 輸出:I am from outer function

閉包的作用?

  • 封裝私有變量:閉包可以用于創(chuàng)建私有變量和方法。通過在函數(shù)內(nèi)部定義變量,并返回一個(gè)內(nèi)部函數(shù),外部無法直接訪問這些變量,從而實(shí)現(xiàn)了封裝的效果。這樣可以避免全局變量的污染,提高代碼的可維護(hù)性和安全性。
  • 延遲執(zhí)行:閉包可以用于實(shí)現(xiàn)延遲執(zhí)行的效果。通過在函數(shù)內(nèi)部定義一個(gè)定時(shí)器或事件監(jiān)聽器,并返回一個(gè)內(nèi)部函數(shù),可以在需要的時(shí)候觸發(fā)執(zhí)行。
  • 記憶化/保持狀態(tài):閉包可以用于實(shí)現(xiàn)記憶化的效果,即將函數(shù)的計(jì)算結(jié)果緩存起來,以便在后續(xù)調(diào)用時(shí)直接返回緩存的結(jié)果,提高函數(shù)的執(zhí)行效率。
  • 回調(diào)函數(shù):閉包可以用于實(shí)現(xiàn)回調(diào)函數(shù)。通過將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),并在內(nèi)部函數(shù)中調(diào)用該函數(shù),可以實(shí)現(xiàn)異步操作的回調(diào)機(jī)制。
  • 模塊化開發(fā):閉包可以用于實(shí)現(xiàn)模塊化開發(fā)。通過將一組相關(guān)的變量和方法封裝在一個(gè)閉包中,可以避免全局命名空間的污染,實(shí)現(xiàn)模塊的獨(dú)立性和復(fù)用性。

閉包的缺陷?

  • 內(nèi)存占用:閉包會(huì)導(dǎo)致外部函數(shù)的變量無法被垃圾回收,從而增加內(nèi)存占用。如果閉包會(huì)長(zhǎng)時(shí)間存在,那么外部變量將無法被釋放,可能導(dǎo)致內(nèi)存泄漏。
  • 性能損耗:閉包涉及到作用域鏈的查找過程,會(huì)帶來一定的性能損耗。在性能要求高的場(chǎng)景下,需要注意閉包的使用。

閉包的應(yīng)用場(chǎng)景?

參考鏈接:js閉包的6種應(yīng)用場(chǎng)景總結(jié)_javascript技巧_腳本之家 (jb51.net)

1. 自執(zhí)行函數(shù)(可以實(shí)現(xiàn)單例模式)

let say = (function(){
  let val = 'hello world';
  function say(){
    console.log(val);
  }
  return say;
})()
var Singleton = (function () {
        var instance;
        function createInstance() {
          var object = new Object("I am the instance");
          return object;
        }
        return {
          getInstance: function () {
            if (!instance) {
              instance = createInstance();
            }
            return instance;
          },
        };
      })();

2. 防抖節(jié)流

// 節(jié)流函數(shù)封裝
function throttle(func, delay) {
  let timer = null;
  return function () {
    if (!timer) {
      timer = setTimeout(() => {
        func.apply(this, arguments);
        timer = null;
      }, delay);
    }
  };
}
// 防抖函數(shù)封裝
function debounce(func, delay) {
  let timer = null;
  return function () {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, arguments);
    }, delay);
  };
}

3. 函數(shù)柯里化

//柯里化前
function add(a, b, c) {
  return a + b + c;
}
console.log(add(1, 2, 3)); //6
//柯里化后
function addCurried1(a) {
  return function (b) {
    return function (c) {
      return a + b + c;
    };
  };
}
//箭頭函數(shù)簡(jiǎn)寫
const addCurried2 = (a) => (b) => (c) => a + b + c;
console.log(addCurried1(1)(2)(3)); //6
console.log(addCurried2(1)(2)(3)); //6

4. 發(fā)布訂閱

function createPubSub() {
  // 存儲(chǔ)事件及其對(duì)應(yīng)的訂閱者
  const subscribers = {};
  // 訂閱事件
  function subscribe(event, callback) {
    // 如果事件不存在,則創(chuàng)建一個(gè)新的空數(shù)組
    if (!subscribers[event]) {
      subscribers[event] = [];
    }
    // 將回調(diào)函數(shù)添加到訂閱者數(shù)組中
    subscribers[event].push(callback);
  }
  // 發(fā)布事件
  function publish(event, data) {
    // 如果事件不存在,則直接返回
    if (!subscribers[event]) {
      return;
    }
    // 遍歷訂閱者數(shù)組,調(diào)用每個(gè)訂閱者的回調(diào)函數(shù)
    subscribers[event].forEach((callback) => {
      callback(data);
    });
  }
  // 返回訂閱和發(fā)布函數(shù)
  return {
    subscribe,
    publish,
  };
}
// 使用示例
const pubSub = createPubSub();
// 訂閱事件
pubSub.subscribe("event1", (data) => {
  console.log("訂閱者1收到事件1的數(shù)據(jù):", data);
});
pubSub.subscribe("event2", (data) => {
  console.log("訂閱者2收到事件2的數(shù)據(jù):", data);
});
// 發(fā)布事件
pubSub.publish("event1", "Hello");
// 輸出: 訂閱者1收到事件1的數(shù)據(jù): Hello
pubSub.publish("event2", "World");
// 輸出: 訂閱者2收到事件2的數(shù)據(jù): World

5. 迭代器

function createIterator(arr) {
  let index = 0;
  return {
    next: function() {
      if (index < arr.length) {
        return {
          value: arr[index++],
          done: false
        };
      } else {
        return {
          done: true
        };
      }
    }
  };
}
const myIterator = createIterator([1, 2, 3]);
console.log(myIterator.next()); // { value: 1, done: false }
console.log(myIterator.next()); // { value: 2, done: false }
console.log(myIterator.next()); // { value: 3, done: false }
console.log(myIterator.next()); // { done: true }

如何釋放閉包?

釋放閉包通常是通過解除對(duì)閉包的引用來實(shí)現(xiàn)的。當(dāng)不再需要使用閉包時(shí),可以將閉包所在的變量設(shè)置為 null 或者將閉包所在的變量賦予其他值,從而斷開對(duì)閉包的引用。這樣,JavaScript 引擎在下一次垃圾回收時(shí)會(huì)判斷閉包不再被引用,從而釋放閉包占用的內(nèi)存空間。

相關(guān)概念

函數(shù)的詞法作用域(也叫靜態(tài)作用域/閉包作用域)

是指在函數(shù)定義時(shí)確定的作用域,而不是在函數(shù)調(diào)用時(shí)確定的作用域。它是由函數(shù)在定義時(shí)所處的上下文環(huán)境決定的,與函數(shù)的調(diào)用位置無關(guān)。

規(guī)則 函數(shù)內(nèi)部可以訪問函數(shù)外部的變量 函數(shù)內(nèi)部的變量在函數(shù)外部不可訪問 函數(shù)內(nèi)部可以訪問函數(shù)外部的函數(shù) 函數(shù)內(nèi)部的函數(shù)可以訪問外部函數(shù)的變量

詞法作用域的優(yōu)勢(shì)在于它提供了更可靠和可預(yù)測(cè)的變量訪問方式。在函數(shù)定義時(shí),就確定了函數(shù)內(nèi)部可以訪問的變量,不會(huì)受到函數(shù)調(diào)用位置的影響。這種靜態(tài)作用域的特性使得代碼更易于理解和維護(hù),并且可以實(shí)現(xiàn)一些高級(jí)的編程技巧,如閉包和模塊化開發(fā)。

執(zhí)行上下文

每當(dāng) JavaScript 代碼執(zhí)行時(shí),都會(huì)創(chuàng)建一個(gè)執(zhí)行上下文(是 JavaScript 引擎內(nèi)部的一種數(shù)據(jù)結(jié)構(gòu),用于管理代碼的執(zhí)行環(huán)境、變量的作用域),并按照特定的規(guī)則進(jìn)行管理和銷毀。

執(zhí)行上下文可以分為三種類型:

  • 全局執(zhí)行上下文(Global Execution Context):全局執(zhí)行上下文是在整個(gè)腳本文件執(zhí)行時(shí)創(chuàng)建的,它是最外層的執(zhí)行上下文。在全局執(zhí)行上下文中,變量和函數(shù)聲明會(huì)被提升,并且會(huì)創(chuàng)建全局對(duì)象(如瀏覽器環(huán)境中的 window 對(duì)象)和全局變量。
  • 函數(shù)執(zhí)行上下文(Function Execution Context):每當(dāng)函數(shù)被調(diào)用時(shí),都會(huì)創(chuàng)建一個(gè)函數(shù)執(zhí)行上下文。函數(shù)執(zhí)行上下文中包含了函數(shù)的參數(shù)、局部變量、函數(shù)內(nèi)部的變量和函數(shù)聲明。每個(gè)函數(shù)執(zhí)行上下文都有自己的作用域鏈和 this 值。
  • Eval 執(zhí)行上下文(Eval Execution Context):在使用 eval() 函數(shù)執(zhí)行代碼時(shí),會(huì)創(chuàng)建一個(gè) eval 執(zhí)行上下文。它與全局執(zhí)行上下文類似,但是它有自己的詞法作用域。

執(zhí)行上下文的生命周期包括以下階段:

  • 創(chuàng)建階段(Creation Phase):在這個(gè)階段,JavaScript 引擎會(huì)創(chuàng)建執(zhí)行上下文,并進(jìn)行變量和函數(shù)的聲明。變量會(huì)被初始化為 undefined,函數(shù)會(huì)被存儲(chǔ)在內(nèi)存中。
  • 執(zhí)行階段(Execution Phase):在這個(gè)階段,JavaScript 引擎會(huì)按照代碼的順序執(zhí)行語(yǔ)句,給變量賦值,執(zhí)行函數(shù)調(diào)用等操作。

觀察和理解執(zhí)行上下文

執(zhí)行上下文的管理和切換由 JavaScript 引擎自動(dòng)完成,開發(fā)者可以通過了解執(zhí)行上下文的概念和規(guī)則,更好地理解代碼的執(zhí)行過程,以及變量和函數(shù)的作用范圍。

盡管無法直接訪問或輸出執(zhí)行上下文,但我們可以通過一些間接的方式來觀察和理解執(zhí)行上下文的行為和特性:

  • 使用 console.log():可以在代碼中使用 console.log() 方法輸出變量的值、函數(shù)的執(zhí)行結(jié)果等信息,從而間接觀察到執(zhí)行上下文的影響。
  • 使用調(diào)試工具:現(xiàn)代的瀏覽器和開發(fā)工具提供了強(qiáng)大的調(diào)試功能,可以在代碼執(zhí)行過程中查看執(zhí)行上下文的變化、變量的值以及調(diào)用棧等信息。
  • 使用閉包:通過創(chuàng)建閉包,我們可以間接地觀察到執(zhí)行上下文的作用。閉包可以讓內(nèi)部函數(shù)訪問外部函數(shù)的變量,從而形成一個(gè)包含外部執(zhí)行上下文的閉包執(zhí)行上下文。

以上就是JavaScript中閉包的作用和應(yīng)用場(chǎng)景的詳細(xì)內(nèi)容,更多關(guān)于JavaScript閉包的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • HTML5游戲引擎LTweenLite實(shí)現(xiàn)的超帥動(dòng)畫效果(附demo源碼下載)

    HTML5游戲引擎LTweenLite實(shí)現(xiàn)的超帥動(dòng)畫效果(附demo源碼下載)

    這篇文章主要介紹了HTML5游戲引擎LTweenLite實(shí)現(xiàn)的超帥動(dòng)畫效果,詳細(xì)分析了LTweenLite的下載,動(dòng)畫效果的實(shí)現(xiàn)步驟,并附帶完整的demo實(shí)例源碼供讀者下載,需要的朋友可以參考下
    2016-01-01
  • 靜態(tài)頁(yè)面實(shí)現(xiàn) include 引入公用代碼的示例

    靜態(tài)頁(yè)面實(shí)現(xiàn) include 引入公用代碼的示例

    下面小編就為大家?guī)硪黄o態(tài)頁(yè)面實(shí)現(xiàn) include 引入公用代碼的示例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • JavaScript 語(yǔ)句之常用 for 循環(huán)詳解

    JavaScript 語(yǔ)句之常用 for 循環(huán)詳解

    這篇文章主要介紹了JavaScript 語(yǔ)句之常用 for 循環(huán),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Bootstrap每天必學(xué)之導(dǎo)航組件

    Bootstrap每天必學(xué)之導(dǎo)航組件

    Bootstrap每天必學(xué)之導(dǎo)航組件,制作面包屑式導(dǎo)航、導(dǎo)航加下拉菜單效果,感興趣的小伙伴們可以參考一下
    2016-04-04
  • javascript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能

    javascript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能

    這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能,實(shí)現(xiàn)四則運(yùn)算,小數(shù)點(diǎn),回退,歸0等功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • js實(shí)現(xiàn)小窗口拖拽效果

    js實(shí)現(xiàn)小窗口拖拽效果

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)小窗口拖拽效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • React中過渡動(dòng)畫的編寫方式實(shí)例詳解

    React中過渡動(dòng)畫的編寫方式實(shí)例詳解

    在開發(fā)中我們想要給一個(gè)組件的顯示和消失添加某種過渡動(dòng)畫,可以很好的增加用戶體驗(yàn),下面這篇文章主要給大家介紹了關(guān)于React中過渡動(dòng)畫的編寫方式,需要的朋友可以參考下
    2022-10-10
  • 用javascript實(shí)現(xiàn)倒計(jì)時(shí)效果

    用javascript實(shí)現(xiàn)倒計(jì)時(shí)效果

    這篇文章主要為大家詳細(xì)介紹了用javascript實(shí)現(xiàn)倒計(jì)時(shí)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-02-02
  • JS表單提交中onsubmit事件return的作用詳解

    JS表單提交中onsubmit事件return的作用詳解

    這篇文章主要為大家介紹了JS表單提交中onsubmit事件return的作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • JS中的防抖與節(jié)流及作用詳解

    JS中的防抖與節(jié)流及作用詳解

    這篇文章主要介紹了JS中的防抖與節(jié)流及作用詳解,本文通過文字說明加示例代碼的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-04-04

最新評(píng)論