JavaScript:閉包

来源:http://www.cnblogs.com/xiaoxiaoyihan/archive/2016/06/30/5630649.html
-Advertisement-
Play Games

閉包 閉包: 指有權訪問另一個函數作用域中的變數的函數。 創建閉包的常見方式就是在一個函數內部創建另一個函數: function createComparisonFunction(propertyName) { return function (obj1, obj2) { // 訪問了外部函數中的變 ...


閉包

閉包:指有權訪問另一個函數作用域中的變數的函數。

創建閉包的常見方式就是在一個函數內部創建另一個函數:

function createComparisonFunction(propertyName) {
    return function (obj1, obj2) {
        // 訪問了外部函數中的變數
        var value1 = obj1[propertyName];
        var value2 = obj2[propertyName];

        if (value1 < value2) {
            return -1;
        } else if (value1 > value2) {
            return 1;
        } else {
            return 0;
        }
    };
}

上面的obj1、obj2訪問了外部函數的變數propertyName。之所以能訪問到這個變數,是因為內部函數的作用域中包含createComparisonFunction()的作用域。

當某個函數被調用時,會創建一個執行環境及相應的作用域鏈。然後,使用arguments和其他命名參數的值來初始化函數的活動對象。

在函數執行過程中,為讀取和寫入變數的值,就需要在作用域鏈中查找變數。

function compare(value1, value2) {
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
        return 1;
    } else {
        return 0;
    }
}

var result = compare(5, 10);

上面先調用了compare()函數,然後又在全局作用域調用了它,當調用compare()時,會創建一個包含arguments、value1和value2的活動對象。全局執行環境的變數對象在compare()執行環境的作用域鏈中則處於第二位。

compare()函數執行時的作用域鏈:

在另一個函數內部定義的函數會將包含函數(即外部函數)的活動對象添加到它的作用域鏈中。因此createComparisonFunction()函數內部定義的匿名內部函數的作用域鏈中,實際上將會包含外部函數createComparisonFunction()的活動對象。

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

下圖展示了代碼執行時,包含函數與內部匿名函數的作用域鏈。

匿名函數從createComparisonFunction()中被返回後,它的作用域鏈被初始化為包含createComparisonFunction()函數的活動對象和全局變數對象。這樣,匿名函數就可以訪問在createComparisonFunction()中定義的所有變數。另外,在createComparisonFunction()執行完,它的活動對象不會被銷毀,從圖中可以看出,匿名函數還引用了這個活動對象。當createComparisonFunction()函數返回時,其執行環境的作用域鏈會被銷毀,但它的活動對象仍會留在記憶體中;匿名函數被銷毀後,createComparisonFunction()的活動對象才會銷毀。

// 創建函數
var compareNames = createComparisonFunction("name");

// 調用函數
var result = compareNames({name: "Nicholas"}, {name: "Greg"});

// 解除對匿名函數的引用(釋放記憶體)
compareNames = null;

首先,創建的比較函數被保存在compareNames,將compareNames設置為null,解除了該函數的引用,就可以進行清除了。

閉包與變數

閉包保存了整個變數對象,但只能取得包含函數中任何變數的最後一個值。

示例:

function createFunctions() {
    var result = new Array();
    
    for (var i = 0; i < 10; i++) {
        result[i] = function () {
            return i;
        };
    }
    return result;
}

上面的例子中看似每個函數都返回自己的索引值,實際上,每個函數都返回10。因為每個函數的作用域鏈中都保存著createFunctions()函數的活動對象,所以它們引用的都是同一個變數i。

通過創建另一個匿名函數強制讓閉包的行為符合預期,如下:

function createFunctions() {
    for (var i = 0; i < 10; i++) {
        return [i] = function (num) {
            return function () {
                return num;
            };
        }(i);
    }
    return result;
}

this對象

this對象在運行時是基於函數的執行環境進行綁定的,在全局函數中,this等於window;當某個對象的方法調用時,this等於那個對象。但是,匿名函數的執行環境具有全局性,其this對象指向window。

看一個例子:

var name = "The Window";

var object = {
    name: "My Object",

    getNameFunc: function () {
        return function () {
            return this.name;
        };
    }
};

alert(object.getNameFunc()());  // "The Window"

上面的例子中首先創建了一個全局變數name,又創建了一個包含name屬性的對象。這個對象包含一個方法:getNameFunc(),它返回一個匿名函數,而匿名函數又返回this.name。由於getNameFunc()返回一個函數,因此調用object.getNameFunc()()就會調用它返回的函數,結果為:this.name。然而,返回的字元串是"The Window"。

為什麼匿名函數沒有取得其包含作用域的this對象呢?

每個函數在函數在被調用時都會獲取兩個變數:this和arguments。內部函數在搜索這兩個變數時,只會搜索到其活動對象為止,不可能訪問到外部函數中的這兩個變數。

把外部作用域中的this對象保存到一個閉包能夠訪問到的變數里,就可以讓閉包訪問該對象了。

var name = "The Window";

var object = {
    name: "My Object",

    getNameFunc: function () {
        var that = this;
        return function () {
            return that.name;
        };
    }
};

alert(object.getNameFunc()());  // "The Window"

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

-Advertisement-
Play Games
更多相關文章
  • 手機端web網頁項目 1,angluar js 1.4.6 網頁項目開發過程中,使用PC瀏覽器能正常訪問,IOS設備瀏覽器也能正常訪問,但是使用Android部分瀏覽器進行訪問的時候,鏈接偶爾不跳轉,點擊完沒有任何反應(本人使用angluar js route進行單頁面應用跳轉),此時地址欄的路徑已 ...
  • http://www.100sucai.com/tool/css3/#/css3-3D-transform ...
  • 以上內容轉自:網路愛上點擊 ...
  • 今天在學習js中的數組時,遇到的輸出一個數組中最大、最小值以及它們的下表,以下是自己的解決方法! <script type="text/javascript"> var arr = [14, 14, 53, 14, 14, 53, 67, 67]; var max = arr[0],min = ar ...
  • 一、理解web標準含義--為什麼採用web標準*****將內容與樣式分離1、web標準是一系列標準,就是一系列技術標準在使用時,是組合應用【1】、結構化內容 xhtml【2】、表現化內容 css【3】、行為化內容 JavaScript2、網頁開發的小工具--火狐瀏覽器中的firebug工具--附加組 ...
  • 說到JavaScript中的分支結構,我們就不得不提到流程式控制制這個詞,我們所有的程式都是由數據和演算法組成的。程式=數據+演算法通常我們所說的演算法都可以通過"順序","分支","迴圈"三種結構來組合完成。 在ECMA中規定了一些語句(也稱為流程式控制制語句,分支結構語句),從本質上來說,這些語句定義了ECM ...
  • 在一些網站進行上傳時,當單擊了“瀏覽”按鈕之後會彈出【選擇文件】的對話框。想要實現這一功能,用input的file控制項來實現就好啦~ 效果圖是醬嬸的: 註意!別以為這個是由一個text和一個button組合成的,其實它就是一個file控制項哦 今天工作中遇到要求:不顯示“未選擇任何文件”,搗鼓夠一個小 ...
  • 【問題產生】 Webview 通過 addjavascriptInterface 傳遞對象給前端,一切正常。但是 Android官方已提醒此功能是有安全風險,改用 safe-java-js-webview-bridge 做java和js交互。 官方的用法正常: 但如果我們在body里的<script ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...