JavaScript 函數之 ------------------ 閉包

来源:http://www.cnblogs.com/czhyuwj/archive/2016/06/26/5618680.html
-Advertisement-
Play Games

談到閉包,人們常常會把匿名函數和閉包混淆在一起。閉包是指由權訪問另一個函數作用域中的變數的函數。創建閉包的常見方式,就是在一個函數內部創建另一個函數,仍以前面的 createComparisonFunction()函數為例 在標識的部分,它訪問了外部的變數 propertyName 即使這個函數被返 ...


      談到閉包,人們常常會把匿名函數和閉包混淆在一起。閉包是指由權訪問另一個函數作用域中的變數的函數。創建閉包的常見方式,就是在一個函數內部創建另一個函數,仍以前面的

createComparisonFunction()函數為例

  

 1           function createComparisonFunction(propertyName){
 2                     return function(object1,object2){
 3                         var value1 = object1[propertyName];
 4                         var value2 = object2[propertyName];   
 5                         if(value1<value2){
 6                             return -1;
 7                         }else if(value1>value2){
 8                             return 1;
 9                         }else{
10                             return 0;
11                         }
12                     }
13                 };

  在標識的部分,它訪問了外部的變數 propertyName 即使這個函數被返回後,仍然可以訪問到這個變數(propertyName);這是應為 匿名函數作用域鏈中包含  createComparisonFunction() 的作用域。

    要理解必須掌握作用域的幾個概念

  作用域鏈:

    什麼時候會生成?:當代碼在一個執行環境中執行時,就會創建變數對象的一個作用域鏈。

    作用:保證對執行環境有權訪問的所以函數和變數的有序訪問。作用域的前端永遠是當前的執行環境所對應的變數對象;

  執行環境:定義了變數或函數有權訪問其他數據,決定它們各自的行為。 每個環境都有一個與之對應的變數對象(variable object)。環境中定義的變數和函數都保存在這個對象中。 當函數執行完成後其執行環境就會被銷毀

  變數對象:保存執行環境中的變數和函數。

  活動對象:如果執行環境是函數,則將其活動對象作為變數對象。活動對象在最開始時只包含一個變數。

   

   在函數執行過程中,為讀取和寫入變數的值,就需要的作用域鏈中查找對應的變數。先看看一個實例來瞭解下每個概念對應部分: 

   

 1  function compare(value1,value2){
 2  
 3     if(value1<value2){
 4         return -1;
 5     }else if(value1>value2){
 6         return 1;
 7     }else{
 8         return 0;
 9     }
10   }   
   var result = compare(5,10);
  

   

  先定義了 compare 函數,後又在全局作用域中調用,在這個compare 執行環境為函數的時候,當前活動對象則為變數對象。 活動對象預設是只有 arguments 但是此時卻不一樣(this,arguments,value1,value2);

而全局作用域中對應變數對象(compare 、result);來看看下圖吧!

 

  <1>在定義compare函數的時候,會創建一個預先包含全局變數對象作用域鏈,這個作用域鏈保存在內部的[[Scope]]屬性中。

  <2>當在調用 compare 函數的時候,會為函數創建一個執行環境,然後通過賦值函數的[[Scope]]屬性中的對象構建起執行環境的作用域鏈。此後,又有一個活動對象被創建並推入執行環節作用域鏈的前端。

對於compare函數的執行環境而言,其作用域鏈中包含兩個變數對象(本地活動對象和全局變數對象)。顯然,作用域鏈本質上是一個指向變數對象的指針列表,它引用但不實際包含變數對象。

所以無論什麼時候,訪問一個變數時都會從作用域鏈中搜索具有相應名字的變數。一般來講當函數執行完畢後。局部活動對象就會被銷毀,記憶體中僅保存全局作用域。但是閉包所有不同。

 

  在閉包中,當函數內部定義一個內部函數,該內部函數會把外部函數的活動對象添加到自己的作用域鏈中;因此createComparisonFunction()定義的匿名函數,其作用於域會包含外部函數的作用域。

 1           function  createComparisonFunction(propertyName){
 2                     return function(object1,object2){
 3                         var value1 = object1[propertyName];
 4                         var value2 = object2[propertyName];   
 5                         if(value1<value2){
 6                             return -1;
 7                         }else if(value1>value2){
 8                             return 1;
 9                         }else{
10                             return 0;
11                         }
12                     }
13                 };    

當下麵代碼執行時,外部函數與內部函數包含的作用域鏈, 如下圖

1 var compare = createComparisonFunction("name");
2 var result = compare({name:"Nicholas"},{name:"Greg"});

 

在代碼執行過程中,用變數 compare 保存了其返回的內部匿名函數,而作用域鏈中包含了三個變數對象,(全局變數對象,外部函數-活動對象,匿名函數-活動對象);

所以即使返回後,也還是可以訪問到對應的變數; 因為外部函數(createComparisonFunction) 執行完成時,其活動對象依然存在,並不會銷毀,因為其被內部函數作用域鏈中引用了;

雖然 外部函數返回到,其執行環境對應作用域鏈被銷毀,但是其活動對象依然存在。直到匿名函數被銷毀,其createComparisonFunction對應的活動對象才會被銷毀。

1 var compare = createComparisonFunction("name");
2 var result = compare({name:"Nicholas"},{name:"Greg"});
3 compare = null;  //主要是手動賦值為空,通知系統 進行垃圾處理; 隨著其作用域鏈被銷毀(除全局作用域鏈之外)。

由於閉包會攜帶包含它的函數的作用域,因此會比其他函數占用更多的記憶體。過度使用閉包可能會導致內部占用過多。

    


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一次完整看一遍(JavaScript設計模式)該模式的介紹,感覺這不就是繼承而已嗎,只不過可能是部分繼承。 混入(Mixin)模式 定義: Mixin是可以輕鬆被一個子類或一組子類繼承功能的類,目的是函數復用。繼承Mixin是擴展功能的方式,另外也可能從多個Mixin類進行繼承。 繼承方式: 這個 ...
  • 最近公司作為眾多外部廠商之一,需要依托一個大型平臺系統( 這裡簡稱為Big-S) 給特定用戶提供一些服務。 作為外部廠商開發的 Web 應用(這裡簡稱 Small-S),需要提取 Big-S 中的基礎數據,包括用戶、組織結構、代碼表......部分欄位到本地數據表中。 融合 Small-S 自己特點 ...
  • RPC(Remote Procedure Call Protocol)遠程過程調用協議,它是一種通過網路,從遠程電腦程式上請求服務,而不必瞭解底層網路技術的協議。說的再直白一點,就是客戶端在不必知道調用細節的前提之下,調用遠程電腦上運行的某個對象,使用起來就像調用本地的對象一樣。目前典型的RPC ...
  • 回到目錄 本文來自於實踐中的不足 在最近開始過程中,遇到了一個問題,之前設計的工作單元UoW只支持Insert,Update,Delete三種操作,即開發人員可以將以上三種操作同時扔進工作單元,由工作單元UoW負責事件的處理,這種設計已經出現很多年了,大叔感覺也是不錯,思路就是在工作單元里添加三個字 ...
  • Vue.js介紹 Vue.js是當下很火的一個JavaScript MVVM庫,它是以數據驅動和組件化的思想構建的。相比於Angular.js,Vue.js提供了更加簡潔、更易於理解的API,使得我們能夠快速地上手並使用Vue.js。 如果你之前已經習慣了用jQuery操作DOM,學習Vue.js時... ...
  • 使用js製作一個簡單的產品放大圖 購物網站的產品頁經常會放有一個產品展示圖區。該圖區有一個功能就是產品圖的放大功能,移動左側的焦點區域,可以放大細節部分觀看,詳情如下圖。實現該功能的方法也非常簡單。 實驗:製作產品焦點放大圖。 所需技能:1、基本的獲取頁面元素的方法; 2、幾個簡單的事件; 3、會使 ...
  • 簡介:jQuery Lightbox圖片放大預覽代碼是一款可以在用戶點擊頁面中的小圖片時,將該圖片的高清版本以Lightbox的方式放大顯示在頁面的中間,提高用戶的體驗度。效果展示 http://hovertree.com/texiao/jqimg/6/效果圖如下: 源碼下載:http://hove ...
  • 1.Ajax:readyState(狀態值)和status(狀態碼)的區別readyState,是指運行AJAX所經歷過的幾種狀態,無論訪問是否成功都將響應的步驟,可以理解成為AJAX運行步驟,使用“ajax.readyState”獲得status,是指無論AJAX訪問是否成功,由HTTP協議根據所 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...