摘要:前提中閉包無處不在,你只需要能夠識別并擁有它。一實質問題當函數可以記住并訪問所在的詞法作用域是,就產生了閉包。依然持有該作用域的引用。延遲函數的回調會在循環結束時才執行。每個延遲函數都會講在每次迭代中創建的作用域封閉起來。
前提:JavaScript中閉包無處不在,你只需要能夠識別并擁有它。閉包是基于詞法作用域書寫代碼時自然產生的結果。
一、實質問題當函數可以記住并訪問所在的詞法作用域是,就產生了閉包。有的人會很好奇,什么是詞法作用域,接下來我給大家普及一下什么是詞法作用域。
詞法作用域簡單的來說詞法作用域就是定義在詞法階段的作用域,換就話說,詞法作用域是由你在寫代碼時將變量和塊作用域寫在哪里來決定的
function foo(a){ var b = a*2; function bar(c){ console.log(a,b,c); } bar (b*3); } foo(2);
在這個例子中包含了三個逐級嵌套的作用域
1、包含整個全局作用域,foo
2、包含著foo所創建的作用域,a , bar , b
3、包含著bar所穿件的作用域 ,c
關于詞法作用域我們就現講這么多,接下來還是回到我們的正文,作用域閉包
function foo(){ var a=2; function bar(){//bar()的詞法作用域能夠訪問foo()的內部作用域 console.log(a); } return bar;//將bar()函數當做一個值類型進行傳遞 } var baz =foo(); baz(2);
foo()內部作用域依然存在,沒有被回收。bar()依然持有該作用域的引用。這個引用就叫閉包
function foo(){ var a=2; function baz(){ console.log(a); } bar(baz); } function bar(fn){ fn(); } foo(); //把內部函數baz傳遞給bar, // 當調用這個內部函數, // 他涵蓋的foo()內部作用域的閉包就可以觀察到了,因為它能夠訪問a
var fn; function foo(){ var a =2; function baz(){ console.log(a); }; fn = baz; } function bar(){ fn(); } foo(); bar();
無論通過何種手段將內部函數傳遞到所在的詞法作用域以外,他都會持有對原始定義作用域的引用,無論在何處執行這個函數都會使用閉包。
二、提升function wait(message){ setTimeout(function timer(){ console.log(message) },1000); }; wait("hello world");
在引擎內部,內置的工具函數setTimeout()持有對一個參數的引用,引擎會調用這個函數,在這個例子中就是內部的timer函數,而詞法作用域就在這個過程中保持完整。這就是閉包。
三、循環和閉包for(var i=0;i<=5;i++){ setTimeout(function timer() { console.log(i); }, i*1000); } //大家猜猜結果會是啥?
正常情況下會分別輸出數字1~5,但實際會輸出五次6。
延遲函數的回調會在循環結束時才執行??梢韵胂笠幌庐惒郊虞d機制。因此settimeout每次要等到循環結束后才顯示值,這樣就得到了我們的結果,輸出了五次6。
代碼中有什么缺陷導致它的行為通語義所暗示的不一致呢?
我們需要更多的作用域,特別是在循環的過程中每個迭代都要一個閉包作用域,因此想到了立即執行函數
for( var i=0;i<=5;i++){ (function(){ setTimeout(function timer() { console.log(i); }, i*1000); })(); }
這樣子為什么還不行呢?我們顯然擁有了更過的詞法作用域。
每個延遲函數都會講IIFE在每次迭代中創建的作用域封閉起來。
如果作用域是空的話,我們的IIE只是一個什么都沒用的空作用域。
for( var i=1;i<=5;i++){ (function(){ var j =i; setTimeout(function timer() { console.log(j); }, j*1000); })(); }重返塊作用域
for(let i =1;i<=5;i++){ setTimeout(function timer() { console.log(i); }, i*1000); }
let欺騙此法作用域,每次在迭代都去創建一個新的作用域,然后執行完后被銷毀,這樣每個迭代都有自己的作用域就可以達到我們的預期效果,輸出1~5。
四、模塊function coolModule(){ var something = "cool"; var another = [1,2,3]; function doSomething(){ console.log(something); } function doAnother(){ console.log(another.join("!")); } return { doSomething: doSomething, doAnother: doAnother }; } var foo = coolModule(); foo.doAnother(); foo.doSomething();
這個模式JavaScript中被稱為模塊,保護私有屬性,只提供公共方法。
模塊模式需要具備兩個必要條件:
1、必須有外部的封閉函數
2、封閉函數必須返回至少一個內部函數
現代的模塊機制大多數模塊依賴加載器/管理器本質上都是將這種模塊定義封裝進一個友好的API。
var MyModules = (function Manager(){ var modules = {}; function define(name,deps,impl){ for(var i=0;i
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107700.html
摘要:本期推薦文章從作用域鏈談閉包,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。推薦理由這是一篇譯文,深入淺出圖解作用域鏈,一步步深入介紹閉包。作用域鏈的頂端是全局對象,在全局環境中定義的變量就會綁定到全局對象中。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周開始前端進階的第二期,本周的主題是作用域閉包,今天是第6天。 本...
摘要:閉包面試題解由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第8天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了...
摘要:下面我們就羅列閉包的幾個常見問題,從回答問題的角度來理解和定義你們心中的閉包。函數可以通過作用域鏈相互關聯起來,函數內部的變量可以保存在其他函數作用域內,這種特性在計算機科學文獻中稱為閉包。 寫這篇文章之前,我對閉包的概念及原理模糊不清,一直以來都是以通俗的外層函數包裹內層....來欺騙自己。并沒有說這種說法的對與錯,我只是不想擁有從眾心理或者也可以說如果我們說出更好更低層的東西,逼格...
摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...
閱讀 738·2021-10-09 09:44
閱讀 2005·2021-09-22 15:54
閱讀 5043·2021-09-22 10:55
閱讀 1435·2019-08-29 18:41
閱讀 771·2019-08-29 11:24
閱讀 2099·2019-08-28 18:20
閱讀 1025·2019-08-26 11:51
閱讀 3043·2019-08-26 11:00