摘要:閉包確實是一個說爛了的概念,校招社招都會被問到,今天總結一番。先下定義,閉包是函數和該函數的詞法作用域的組合。在這個栗子里,函數以及它對變量的引用就構成了閉包。閉包和作用域對于閉包和作用域的關系,我的理解是閉包其實就是作用域的延伸。
閉包確實是一個說爛了的概念,校招社招都會被問到,今天總結一番。
先下定義,閉包是函數和該函數的詞法作用域的組合。其實這個定義是比較教條的,可以直白的理解為閉包是一個函數,且這個函數使用了既沒在它內部聲明且不是它的參數的變量。
舉個栗子,
function foo() { var a = 2; function bar() { console.log( a ); } return bar; } var baz = foo(); baz(); // 2
按照常理,foo函數在執行完畢之后會銷毀掉其內部的變量a,但是bar函數內部保持著對a的引用,所以通過調用foo()把bar的引用賦給了baz,運行baz()依然可以打印出a。在這個栗子里,函數bar以及它對變量a的引用就構成了閉包。
閉包和作用域對于閉包和作用域的關系,我的理解是閉包其實就是作用域的延伸。
由于在JavaScript中函數內部可以使用函數外部的變量,所有有時候會不知不覺的產生閉包,假如在上面那個代碼片段中,不允許函數內部使用函數外部的變量,閉包也就無從談起了。
模擬私有變量和私有方法
var Dog = (function(){ var privateVal = "dog" function doing(val) { console.log(privateVal + " " + val) } return { run: function(){ doing("run") }, bark: function(){ doing("bark") } } })() Dog.run() // dog run Dog.bark() // dog bark
可以看到的是,run和bark這兩個閉包分享了同一個詞法作用域,且都引用了私有方法doing。這樣,我們就可以只向外暴露run和bark兩個公共接口而隱藏私有的變量和方法。
閉包與循環或許這是面試中出現最多的問題...
for(var i = 1;i <= 5;i++) { setTimeout(function() { console.log(i) }, i*1000) } // 每隔一秒打印一個6,共打印5次
為什么事與愿違,而不是按照我們所想的依次的間隔1秒打印出1,2,3,4,5呢?首先,這段循環產生了5個閉包,而且最重要的是這5個閉包都處在同一個作用域中,也就是說它們引用的是同一個i,當for循環結束時,i變成了6。所以,5個匿名函數執行時會依次的去打印那同一個i,所以就打印出了5個6。
如何解決?
之前也說了讓這5個閉包處于不同的作用域且讓它們在各自的作用域中擁有它們各自的i即可。
可以使用自執行函數來創建一個新的作用域
for(var i = 1;i <= 5;i++) { (function(k){ setTimeout(function() { console.log(k) }, k*1000) })(i) }
在這個代碼片段中,每一個setTimeout都處于一個獨立的作用域中,且都引用了它們各自的k,并不是指向了外層作用域的i,所以就會打印出1,2,3,4,5
也可以使用let
for(let i = 1;i <= 5;i++) { setTimeout(function() { console.log(i) }, i*1000) }
for 循環頭部的 let 不僅將 i 綁定到了 for 循環的塊中,事實上它將其重新綁定到了循環的每一個迭代中,確保使用上一個循環迭代結束時的值重新進行賦值。
其實使用let的本質是
for(let i = 1;i <= 5;i++) { let i = 上次迭代結束的i setTimeout(function() { console.log(i) }, i*1000) }
其實閉包就這么多東西,而且主要是作用域的概念,作用域明白了,閉包也就明白了。
that"s all, thank you.
參考資料
深入理解JavaScript系列-閉包
MDN-閉包
《你不知道的JavaScript-上卷》
「每日一題」JS 中的閉包是什么?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94942.html
摘要:函數式編程前端掘金引言面向對象編程一直以來都是中的主導范式。函數式編程是一種強調減少對程序外部狀態產生改變的方式。 JavaScript 函數式編程 - 前端 - 掘金引言 面向對象編程一直以來都是JavaScript中的主導范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數式編程越來越多得受到開發者的青睞。函數式編程是一種強調減少對程序外部狀態產生改變的方式。因此,...
摘要:插件開發前端掘金作者原文地址譯者插件是為應用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內優雅的實現文件分片斷點續傳。 Vue.js 插件開發 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應用添加全局功能的一種強大而且簡單的方式。插....
摘要:本文最早為雙十一而作,原標題雙大前端工程師讀書清單,以付費的形式發布在上。發布完本次預告后,捕捉到了一個友善的吐槽讀書清單也要收費。這本書便從的異步編程講起,幫助我們設計快速響應的網絡應用,而非簡單的頁面。 本文最早為雙十一而作,原標題雙 11 大前端工程師讀書清單,以付費的形式發布在 GitChat 上。發布之后在讀者圈群聊中和讀者進行了深入的交流,現免費分享到這里,不足之處歡迎指教...
閱讀 3256·2023-04-26 02:10
閱讀 2880·2021-10-12 10:12
閱讀 4557·2021-09-27 13:35
閱讀 1519·2019-08-30 15:55
閱讀 1058·2019-08-29 18:37
閱讀 3423·2019-08-28 17:51
閱讀 1954·2019-08-26 13:30
閱讀 1191·2019-08-26 12:09