日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

作用域闭包

發布時間:2024/4/13 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 作用域闭包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

再看閉包定義

閉包的概念看了幾十回不止了,但是讓我描述一遍,我應該還是說不出個什么東西。下面就再來看看閉包的概念:

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

下面配合一個例子來更好的理解

function foo() {var a = 2;function bar() {console.log(a) // 2}bar() } foo() 復制代碼

看了這段代碼,很容易有個疑惑,這就是閉包嗎?這不應該是作用域的例子嗎?對,這就是詞法作用域的查找規則。但是,這些規則就是閉包的一部分。

通過這段代碼,我們不能清晰的理解閉包的意義,卻可以很容易的理解詞法作用域。下面我們來稍加修改一下,來看看到底閉包應該什么樣子,和詞法作用域有什么聯系?

function foo() {var a = 2function bar() {console.log(a)}return bar } var baz = foo() baz() // 2 復制代碼

再結合定義來看,就很容易理解了。

bar函數可以訪問所在函數foo的詞法作用域。這就產生了閉包。而bar函數本身作為返回值進行傳遞,并且賦值給了baz,在foo的詞法作用域外,我們執行baz,依然可以執行。

下面我們來進一步的理解閉包。

依據JavaScript的垃圾回收機制,當var baz = foo()執行之后,理論上來說foo的內容不會再被使用,所以應該釋放所在的內存空間,但是這時候卻不會被回收,這就是閉包的神奇的地方。

bar()依然持有該作用域的引用。這個引用就是閉包。

所以當我們執行baz時,以然可以訪問到a。

下面再來幾個例子,加深我們對閉包的理解

function foo() {var a = 2function baz() {console.log(a)}bar(baz) } function bar(fn) {fn() } 復制代碼

這個例子和之前的區別在于,前面一個是返回一個函數作為調用的值,而這一個是直接傳遞函數給另一個函數作為變量的值。這都達到了閉包的效果。

另外,傳遞也可以是間接的,我們可以直接賦值給一個全局變量。并在其他地方調用。

var fn function foo() {var a = 2function baz() {console.log(a)}fn = baz } function bar() {fn() } foo() bar() 復制代碼

循環和閉包

我第一次接觸到閉包的這個概念是在這樣一次使用之后:

for(var i = 0; i < 5;i++){setTimerout(function timer(){console.log(i)}, i * 1000) } 復制代碼

天真的我等待這每秒輸出一個0-4的數字,等結果出現的時候,我直接蒙了,這是JavaScript出bug了啊。

現在看來但是的自己是多么的無知。。。

解決辦法對現在的自己來說很簡單了

for (var i=1; i<=5; i++) {(function() {var j = i;setTimeout( function timer() {console.log( j );}, j * 1000 );})(); } 復制代碼

或這樣

for (var i=1; i<=5; i++) {(function(j) {setTimeout( function timer() {console.log( j );}, j * 1000 );})( i ); } 復制代碼

原因也是很簡單的,

  • 閉包
  • 更多的詞法作用域
  • 塊作用域

    es6的出現讓我們有了解決上面問題的更簡單的方法。那就是利用塊作用域。

    for (let i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 ); } 復制代碼

    模塊

    在大規模使用es6的模塊機制的現在,我們對模塊已經有了也許詳細的認識。但是,具體的模塊是怎么實現的呢?我們來看一下。

    function Foo() {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 = Foo() foo.doSomething() foo.doAnother() 復制代碼

    上面的這個模式就是最基本的模塊了,很顯然,我們利用了閉包的知識。

    Foo函數對外暴漏了一個對象,這個對象包含了doSomething和doAnother兩個函數。

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

  • 必須有外部的封閉函數, 該函數必須至少被調用一次(每次調用都會創建一個新的模塊 實例)。
  • 封閉函數必須返回至少一個內部函數, 這樣內部函數才能在私有作用域中形成閉包, 并 且可以訪問或者修改私有的狀態。
  • 上面的模塊我們可以調用很多次,每次都會創建一個新的模塊實例。如果我們只需要使用一次時,我們可以這么做

    var foo = (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}; })(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3 復制代碼

    看,閉包是不是無處不在。

    當然,模塊還可以接受參數,根據參數來設置一些模塊內的內容,這都是很簡單的應用,很容易理解。

    es6的使用,使我們對模塊的使用更加的方便。es6會將文件作為獨立的模塊來處理,每一個暴露的函數都可以用關鍵詞export來導出。使用模塊暴露出來的函數時,我們用import來引入。

    通過這一次學習,對閉包有個更加深入的認識,我么再來看一下閉包的定義:

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

    另一個重要的概念就是模塊:

  • 為創建內部作用域而調用了一個包裝函數;
  • 包裝函數的返回值必須至少包括一個對內部函數的引用, 這樣就會創建涵蓋整個包裝函數內部作用域閉包
  • 閉包無處不在,以后的工作學習中能熟練的運用閉包,一眼認出來是閉包就是真正的掌握了

    轉載于:https://juejin.im/post/5be15446f265da6174644e36

    總結

    以上是生活随笔為你收集整理的作用域闭包的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。