最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解JavaScript作用域 閉包

 更新時間:2020年07月29日 15:28:49   作者:看云  
這篇文章主要介紹了JavaScript作用域 閉包的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下

JavaScript閉包,是JS開發(fā)工程師必須深入了解的知識。3月份自己曾撰寫博客《JavaScript閉包》,博客中只是簡單闡述了閉包的工作過程和列舉了幾個示例,并沒有去刨根問底,將其弄明白!

現在隨著對JavaScript更深入的了解,也剛讀完《你不知道的JavaScript(上卷)》這本書,所以乘機整理下,從底層和原理上去刨一下。

JavaScript并不具有動態(tài)作用域,它只有詞法作用域。詞法作用域是在寫代碼或者說定義時確定的,而動態(tài)作用域是在運行時確定的。了解閉包前,首先我們得知道什么是詞法作用域(作用域是由書寫代碼時函數聲明的位置來決定的)。

一、何為閉包

示例1:

function foo(){
	var a = 2;
	function bar(){
		console.log(a);
	}
	return bar;
}
var baz = foo();
bzz(); //2

在foo()執(zhí)行后,通常認為垃圾回收機制會將foo()的整個內部作用域都被銷毀;而閉包可以阻止這樣事情發(fā)生,讓其內部作用域依然存在。因為bar()處于foo()內部,它擁有涵蓋foo()作用域的閉包,使得該作用域能夠一直存活,以供bar()在之后任何時間進行引用。

bar()依然持有對該作用域的引用,而這個引用就叫作閉包。

簡言之:當函數可以記住并訪問所在的詞法作用域,即使函數是在當前詞法作用域之外執(zhí)行,這時就產生了閉包。

示例2:

無論使用何種方式對函數類型的值進行傳遞,當函數在別處被調用時都可以觀察到閉包。

function foo(){
	var a = 2;
	function baz(){
		console.log(a);
	}
	bar(baz);
}

function bar(fn){
	fn();	// 這就是閉包
}

示例3:

將一個內部函數(timer)傳遞給setTimeout。timer具有涵蓋wait()作用域的閉包,保有對變量message的引用。

wait()執(zhí)行1000毫秒后,它的作用域并不會消失,timer依然保有wait()作用域的閉包。

function wait(message){
	setTimeout( function timer(){
		console.log(message);
	},1000);
}
wait("Hello,ligang");

示例4:

下述activator()具有涵蓋setupBot()作用域的閉包!

function setupBot(name, selector){
	$(selector).click(function activator(){
		console.log("Activating: "+ name);
	});
}
setupBot("Closure Bot 1", "#bot_1");
setupBot("Closure Bot 2", "#bot_2");

二、循環(huán)和閉包

for(var i=1; i<=5; i++){
	setTimeout(function timer(){
		console.log(i);
	}, i*1000);
}
// 期望:每秒一次的頻率輸出1~5
// 結果:每秒一次的頻率輸出五次6

先解釋一下:“i*1000”,5個定時分別在1s、2s、3s、4s、5s后執(zhí)行,并不是1s、3s、6s、10s、15s。也就是頻率為1s,不是每次間隔增加1s。如果去掉i寫成“1000”,會在for執(zhí)行完1s后直接輸出五次6。

回調函數在循環(huán)結束后才被執(zhí)行,因此輸出的是循環(huán)終止條件是i值。事實上,當定時器運行時即使每個迭代中執(zhí)行的是setTimeout(..., 0),所有的回調函數依然是在循環(huán)結束后才被執(zhí)行。

根據作用域的工作原理,盡管五個函數是在各個迭代中分別定義的,但是它們都被封閉在一個共享的全局作用域中,因此實際上只有一個i。

解決方案1:

for(var i=0; i<=5; i++){
	(function(j){
		setTimeout(function timer(){
			console.log(j);
		}, j*1000 );
	})(i);
}
// 結果:每秒一次的頻率輸出1~5

每個迭代都生成一個新的作用域,使得延遲函數的回調可以將新的作用封閉在每個迭代內部,每個迭代中都會含有一個具有正確值的變量供我們訪問。

解決方案2(ES6):

for(var i=0; i<=5; i++){
	let j = i;
	setTimeout(function timer(){
		console.log(j);
	}, j*1000 );
}
// 結果:每秒一次的頻率輸出1~5
for(let i=0; i<=5; i++){
	setTimeout(function timer(){
		console.log(i);
	}, i*1000 );
}
// 結果:每秒一次的頻率輸出五次6

三、模塊

模塊需要具備兩個必要條件:

(1)必須有外部的封閉函數,該函數必須至少被調用一次(每次調用都會創(chuàng)建一個新的模塊實例)。

(2)封閉函數必須返回至少一個內部函數,這樣內部函數才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。

典型的模塊化:

function CoolMoudle(){
	var something = "cool";
	var doSomething = function(){
		console.log(something);
	}
	return{
		doSomething: doSomething
	};
}
var foo = CoolMoudle();	//如果不執(zhí)行外部函數CoolMoudle(),內部作用域和閉包都無法創(chuàng)建
foo.doSomething();	//cool

單例模式:

var foo = (function CoolModule(id){
	function change(){
		// 修改公共API
		publicAPI.identify = identify2;
	}
	function identify1(){
		console.log(id);
	}
	function identify2(){
		console.log(id.toUpperCase());
	}
	var publicAPI = {
		change: change,
		identify: identify1
	};
	return publicAPI;
})("foo module");
foo.identify();	//foo module
foo.change();
foo.identify(); //FOO MODULE

以上就是詳解JavaScript作用域 閉包的詳細內容,更多關于JavaScript作用域 閉包的資料請關注腳本之家其它相關文章!

相關文章

  • js數組方法reduce經典用法代碼分享

    js數組方法reduce經典用法代碼分享

    本文給大家整理了很多關于js數組方法reduce的經典代碼片段,能夠讓大家更好的理解reduce的實例用法,一起學習下吧。
    2018-01-01
  • JS判斷兩個時間大小的示例代碼

    JS判斷兩個時間大小的示例代碼

    本篇文章只要是對JS判斷兩個時間大小的示例代碼進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • 詳解JavaScript中的作用域鏈與閉包

    詳解JavaScript中的作用域鏈與閉包

    這篇文章主要為大家詳細介紹一下JavaScript中的作用域鏈與閉包的使用,文中的示例代碼講解詳細,對我們學習JavaScript有一定的幫助,需要的可以參考一下
    2022-11-11
  • 原生JS實現可拖拽登錄框

    原生JS實現可拖拽登錄框

    這篇文章主要為大家詳細介紹了原生JS實現可拖拽登錄框,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 在weex中愉快的使用scss的方法步驟

    在weex中愉快的使用scss的方法步驟

    這篇文章主要介紹了在weex中愉快的使用scss的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • 一個仿微博登陸郵箱提示框js開發(fā)案例

    一個仿微博登陸郵箱提示框js開發(fā)案例

    這篇文章主要為大家詳細介紹了一個仿郵箱登錄提示框js開發(fā)案例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • js鼠標按鍵事件和鍵盤按鍵事件用法實例匯總

    js鼠標按鍵事件和鍵盤按鍵事件用法實例匯總

    這篇文章主要介紹了js鼠標按鍵事件和鍵盤按鍵事件用法,結合實例形式總結分析了JavaScript針對鼠標與鍵盤事件的常用操作技巧,需要的朋友可以參考下
    2016-10-10
  • Bootstrap模態(tài)對話框中顯示動態(tài)內容的方法

    Bootstrap模態(tài)對話框中顯示動態(tài)內容的方法

    今天小編就為大家分享一篇Bootstrap模態(tài)對話框中顯示動態(tài)內容的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • javascript中的previousSibling和nextSibling的正確用法

    javascript中的previousSibling和nextSibling的正確用法

    這篇文章主要介紹了javascript中的previousSibling和nextSibling的正確用法的相關資料,需要的朋友可以參考下
    2015-09-09
  • JS實現點擊事件統計的簡單實例

    JS實現點擊事件統計的簡單實例

    下面小編就為大家?guī)硪黄狫S實現點擊事件統計的簡單實例。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07

最新評論

鲁甸县| 黑山县| 永丰县| 手游| 东丽区| 临桂县| 崇明县| 大连市| 绥阳县| 正镶白旗| 临高县| 朝阳区| 河源市| 龙山县| 江门市| 镇赉县| 太仓市| 沭阳县| 贵南县| 合作市| 额济纳旗| 西充县| 十堰市| 砀山县| 曲松县| 阿尔山市| 屏山县| 额尔古纳市| 高淳县| 北票市| 武汉市| 嘉兴市| 德惠市| 无为县| 鄂尔多斯市| 富川| 邯郸县| 广南县| 黄梅县| 通州区| 章丘市|