欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

分享JavaScript閉包

本篇內(nèi)容主要講解“分享JavaScript閉包”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“分享JavaScript閉包”吧!

從事達(dá)州主機托管,服務(wù)器租用,云主機,虛擬主機,空間域名,CDN,網(wǎng)絡(luò)代維等服務(wù)。

1. 概述

閉包(closures),在 MDN 解釋為:

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created.

閉包是指那些能夠訪問獨立(自由)變量的函數(shù) (變量在本地使用,但定義在一個封閉的作用域中)。換句話說,這些函數(shù)可以“記憶”它被創(chuàng)建時候的環(huán)境。

閉包是 JavaScript 語言的一個特色,當(dāng)然也是它的一大難點,很多高級應(yīng)用都要依靠閉包實現(xiàn),或者我們平常編碼過程中,也在有意無意間使用到閉包。

2. 作用域鏈

在理解閉包,首先就要理解 JavaScript 中的作用域鏈。

在 JavaScript 中有兩種作用域:全局作用域和函數(shù)作用域(在 ES6 中引入了塊級作用域)。

在函數(shù)中定義的變量只能在本函數(shù)體中使用到,在函數(shù)外部不能直接調(diào)用函數(shù)體內(nèi)部定義的變量,但函數(shù)中可以調(diào)用到全局作用域中定義的變量。

如果函數(shù)中有內(nèi)嵌函數(shù)的定義,則在內(nèi)嵌函數(shù)中可以訪問到外部函數(shù)中定義的變量,也可訪問到全局作用域中的變量,但在外部函數(shù)中不能訪問內(nèi)嵌函數(shù)中定義的變量。這樣,就形成了作用域鏈,即內(nèi)嵌函數(shù)可調(diào)用父級或祖先級函數(shù)中定義的變量,但父級函數(shù)不能調(diào)用子級或后代函數(shù)中定義的變量。

function outer(){

var outVar = 10;

function inner(){

var inVar = 20;

console.log("inner 中調(diào)用外部函數(shù)變量 outVar = " + outVar);

}

inner();

console.log("outer 中調(diào)用內(nèi)嵌函數(shù)變量 inVar = " + inVar);

}

outer();

執(zhí)行結(jié)果:

inner 中調(diào)用外部函數(shù)變量 outVar = 10

ReferenceError: Can't find variable: inVar

在 JavaScript 中,變量的作用域是由它在源代碼中所處位置決定的,并且嵌套的函數(shù)可以訪問到其外層作用域中聲明的變量。

3. 閉包

如果有這樣一種需求,我們需要在外部使用到函數(shù)內(nèi)的變量,但正常情況下,通過直接調(diào)用的方式是不能訪問到的,這就需要變通的方法了。

function outer() {

var i = 1;

var inner = function(){

return ++i;

}

return inner;

}

var result = outer();

console.log("第一次調(diào)用:" + result());

console.log("第二次調(diào)用:" + result());

console.log("第三次調(diào)用:" + result());

執(zhí)行結(jié)果:

第一次調(diào)用:2

第二次調(diào)用:3

第三次調(diào)用:4

上例中,我們要使用到 outer 函數(shù)內(nèi)部的變量 i,每次打印是在原有數(shù)值基礎(chǔ)上自增 1。因在函數(shù)外部不能直接通過變量名對其進(jìn)行訪問,而嵌套在內(nèi)部的 inner 函數(shù)則能夠訪問到外部函數(shù)變量 i,所以返回了內(nèi)部函數(shù)的引用 inner,這樣,當(dāng) outer 函數(shù)調(diào)用結(jié)束后,放置在 result 中的實際為內(nèi)嵌函數(shù)的引用,這樣就可以繼續(xù)使用到在 outer 函數(shù)內(nèi)部定義的變量 i 了。這就是閉包。

以前常用到的定時器,相信大家寫過類似的代碼片段:

function fn(){

var i = 0;

var timer = setInterval(function(){

console.log(i++);

if(i > 10)

clearInterval(timer);

}, 50);

}

fn();

fn 函數(shù)調(diào)用結(jié)束后,按理說在 fn 函數(shù)內(nèi)部的局部變量 i、timer 作用域該結(jié)束了,但 setInterval()函數(shù)的異步執(zhí)行過程中,仍然可以使用到這兩個變量的值。這也是典型的閉包使用情況。

4. 一個故事

來說明閉包可以有哪些適用場景前,我喜歡下面這個例子。

很久很久以前:

有一位公主......

function princess() {

她住在一個充滿冒險的奇妙世界里,遇到了她的白馬王子。白馬王子帶著她騎著獨角獸開始周游世界,與巨龍戰(zhàn)斗,巧遇會說話的動物,還有很多其他的不可思議的新奇事物。

var adventures = [];

function princeCharming() { /* ... */ }

var unicorn = { /* ... */ },

dragons = [ /* ... */ ],

squirrel = "Hello!";

但她不得不回到自己乏味的王國里,例行去見那些成年人。

return {

她會經(jīng)常給大人分享她最近作為公主時的充滿奇幻的冒險經(jīng)歷。

sayStory: function() {

return adventures[adventures.length - 1];

}

};

}

但在大人的眼里,公主僅僅只是一個小女孩兒......

var littleGirl = princess();

......在講著一些神奇的、充滿幻想的故事。

littleGirl.sayStory();

即便所有大人都知道他們眼前的小女孩是真的公主,但是他們絕不相信有巨龍或獨角獸,因為他們自己從來沒有見到過。大人們說它們只存在于小女孩的想象之中。

但是我們卻知道小女孩述說的是事實......

5. 閉包適用場景

通常閉包有如下兩種適用場景:

· 在內(nèi)存中維持變量,如緩存數(shù)據(jù)

· 保護(hù)函數(shù)體內(nèi)變量的安全,如為對象設(shè)置私有屬性

5.1 緩存數(shù)據(jù)

一個比較常用到的例子就是,利用循環(huán)為元素綁定事件。

讓每個 div 元素被點擊時,都能正確彈出當(dāng)前被點擊的 div 的索引:

div-1

div-2

div-3

div-4

div-5

如果使用如下寫法:

這時,在每個 div 上點擊時彈出的結(jié)果都是你點擊的 div 索引為:5。這是因為事件處理是異步的,但事件綁定是同步的,會先執(zhí)行完循環(huán)體的 5 次操作,為每個 div 綁定上 onclick 事件。

這個過程中,變量 i 的值一直在遞增變化,當(dāng)所有 div 元素都被遍歷后,i 的值自增到 5 退出循環(huán)結(jié)構(gòu)。函數(shù) handle 調(diào)用結(jié)束后,由于在事件響應(yīng)程序中仍然存在變量 i 的引用,如果釋放變量 i 的資源,會導(dǎo)致事件響應(yīng)程序執(zhí)行錯誤,所以為了保證事件響應(yīng)程序中仍然能正確使用到變量 i,會將變量 i 的值一直保留在內(nèi)存中,但保留的 i 的值為 5。

如果要正確輸出索引值,可使用閉包修改如下:

在為每個 div 綁定事件時,調(diào)用 clk() 函數(shù)將與 div 關(guān)聯(lián)的變量值 i 傳遞到 clk() 函數(shù)內(nèi)部使用,因為內(nèi)部返回了一個內(nèi)嵌函數(shù)的引用,該內(nèi)嵌函數(shù)功能的實現(xiàn)依賴于外部函數(shù)中的局部變量 index,所以 index 變量的值會在內(nèi)存中得以緩存。

由于每個 div 綁定事件時,都調(diào)用了 clk() 函數(shù)來實現(xiàn)事件綁定操作,所以與之對應(yīng)的變量索引 i 的數(shù)值也都在內(nèi)存中得以緩存,只是這個值不是以 i 的名稱來緩存。當(dāng)我們再次測試時,就可以正確打印出所點擊 div 的索引了。

當(dāng)然以上功能的實現(xiàn)也可以通過自定義屬性方式實現(xiàn):

或是通過 let 命令來實現(xiàn):

5.2 為對象設(shè)置私有屬性

如果有一個對象,擁有年齡這樣一個屬性,我們要限定年齡的取值范圍在 18~25 歲之間,以類似 Java 面向?qū)ο蟮姆绞絹韺崿F(xiàn),可模擬如下:

age 表示學(xué)生的年齡,這樣的一個變量如果對于任何人都可以修改值,那么如果給定一個負(fù)值,比如 -35,雖然就語法上來說沒問題,但就實際邏輯來說,一個人不可能年齡為 -35 歲,所以為了保障這種數(shù)據(jù)的安全,可以使用閉包來解決。

對 Student 函數(shù)內(nèi)部的局部變量 age 來說,本應(yīng)該在 Student() 函數(shù)通過 new 調(diào)用結(jié)束后就釋放掉資源,但在對象的 getAge/setAge 方法中仍然有對其的引用,釋放資源會導(dǎo)致 getAge/setAge 功能不能正常完成,所以其值會保存在內(nèi)存中。但要修改 age 年齡值時,由于它的作用域問題,我們沒法在 Student 函數(shù)外直接通過調(diào)用 age 的方式來修改,僅能使用提供的 setAge 方法接口修改 age 值,這就保證了對 age 修改賦值的安全性。

6. 一點誤解

以前在查閱資料時,經(jīng)常見到說不要輕易使用閉包,否則容易造成內(nèi)存泄漏的說法。

直到看到這篇文章:《js閉包測試》

閉包里面的變量是我們需要使用到的變量(lives),而內(nèi)存泄漏通常是指訪問不到的變量依然占據(jù)內(nèi)存空間,不能夠?qū)ζ湔紦?jù)的空間再次利用。顯然閉包是不屬于訪問不到的內(nèi)存空間。

之所以有這樣的說法,大概是因為 IE,特別是 IE6 的 bug 吧。當(dāng)然這是 IE 瀏覽器的問題,不是閉包的問題。

現(xiàn)代瀏覽器在 JavaScript 引擎中大都優(yōu)化處理了閉包情形下的垃圾回收,所以關(guān)于內(nèi)存泄漏的說法,我們大可不必再理會了。

到此,相信大家對“分享JavaScript閉包”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

本文標(biāo)題:分享JavaScript閉包
文章路徑:http://www.chinadenli.net/article40/ipppeo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)微信小程序手機網(wǎng)站建設(shè)軟件開發(fā)電子商務(wù)網(wǎng)站營銷

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化