摘要:前端芝士樹中的閉包是怎么一回事筆試問題集錦為什么會有閉包的出現這涉及到作為變量聲明的關鍵詞時所出現的一些問題。另一方面,在函數外部自然無法讀取函數內的局部變量。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
【前端芝士樹】Js中的閉包是怎么一回事 && 筆試問題集錦 為什么會有閉包的出現?
這涉及到var作為變量聲明的關鍵詞時所出現的一些問題。
比如,var 的 變量提升 以及 函數級作用域
Javascript語言的特殊之處,就在于函數內部可以直接讀取全局變量。
另一方面,在函數外部自然無法讀取函數內的局部變量。
需要注意的是,如果在函數內部聲明變量時沒有使用var關鍵詞,實際上聲明的是一個全局變量,如下:
function f1(){ n = 999; } //console.log(n); // ReferenceError: n is not defined f1(); console.log(n); // 999
這里為什么第一處會報錯呢?關于這個問題下面有比較基礎的解釋:
JS的解析過程分為兩個階段:預編譯期(預處理)與執行期。
預編譯期 JS會對本代碼塊(兩個script塊互不影響)中的所有var聲明的變量和函數進行處理(類似與C語言的編譯)
此時處理函數的只是聲明式函數,而且變量也只是進行了聲明但未進行初始化以及賦值。>執行期 會按照代碼塊的順序筑行執行
正因為從外部訪問在函數內部進行聲明的局部變量是不可能的,所以出現了閉包這種形式,在函數內部再定義一個函數。
閉包(Closure)是什么?查閱了一些文章和資料,發現還是下面的定義最容易理解:
閉包:定義在函數內部的一個函數。
擴展一些講,可以參考一下阮一峰的講解:
閉包:能夠讀取其他函數內部變量的函數。
俗話說的好,看定義不如看代碼更直觀一些,如下
function f1(){ var n=999; function f2(){ console.log(n); } return f2; } var result=f1(); result(); // 999
如此段代碼所示,f2()就是其中的閉包函數,通過f2()我們可以訪問到f1()內部的n。
更常見的一種簡寫形式:
function f1(){ var n=999; return function(){ console.log(n); }; } var result=f1(); result(); // 999閉包的優缺點
優點:
可以讀取函數內部的變量
讓這些變量的值始終保持在內存中。
缺點:
由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
閉包面試題集錦(持續更新) 問題一、簡單閉包var a = 1; function foo(){ var a = 2; c = 0; return function () { console.log(a); console.log(b++); console.log(c); } } console.log(a);// 1 //console.log(c); // Reference Error var b = 3; var x = foo(); x(); //2 3 0 console.log(a); // 1 console.log(b); // 4 console.log(c); // 0問題二、閉包的鏈式調用
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3); var b = fun(0).fun(1).fun(2).fun(3); var c = fun(0).fun(1); c.fun(2); c.fun(3);
看解答前先思考一下會輸出什么哦
【解答】: 首先對函數進行分析,這個函數其實是返回了一個對象,{fun:function(){}},里面有一個函數作為屬性,這個函數就是閉包,使得函數內部的變量保留在內存中。
注意,這里會有一個可能誤解的地方,return {fun:...}里面的fun是fun(n,o)嗎?明白這個區別后后面就容易多了。
好了,明白大概的原理后,我們來分析這個問題:
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
執行a = fun(0),0是作為n傳入的,o沒有參數傳入,所以輸出undefined,之后,
a = { fun:function(m){ return fun(m,0);//這里的n應該變成了第一次調用時的參數n,也就是0 } } 也就是 a = { fun:function(m){ return function(n = m, o = 0) { console.log(o) //輸出0 return { fun:function(m){ return fun(m,n); } }; }; } }
所以無論傳入的m是什么,輸出永遠都是0
最后,輸出結果如下
var a = fun(0); a.fun(1); a.fun(2); a.fun(3); undefined 0 0 0
搞清楚第一個的過程,第二個的破解關鍵就在于閉包讓函數內部的變量始終保存在內存之中。
//b undefined 0 1 2 //c undefined 0 1 1參考文章
《學習Javascript閉包(Closure) - 阮一峰的網絡日志》
《閉包 - 廖雪峰的官方網站》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108532.html
摘要:提供了糟糕的支持,而雖然接近標準,但依舊未能完全正確的支持標準。盡管修復了許多的問題,但是依然延續實現中的其它故障主要是盒模型問題。因此大部分的聲明將觸發嚴格模式即依據標準的規則渲染網頁。 深入理解CSS盒模型、BFC、OffsetWidth&ClientWidth&ScrollWidth 本文將從盒模型開始,一步步涉及一些常見的前端筆試和面試點 主要參考自第一篇文章,然而筆者在讀的時...
摘要:在創建對象不論是普通對象還是函數對象的時候,都有一個叫做的內置屬性,用于指向創建它的構造函數的原型對象,也就是。因為一個普通對象的構造函數所以原型鏈原型鏈的形成是真正是靠而非。參考文章最詳盡的原型與原型鏈終極詳解,沒有可能是。 【前端芝士樹】Javascript的原型、原型鏈以及繼承機制 前端的面試中經常會遇到這個問題,自己也是一直似懂非懂,趁這個機會整理一下 0. 為什么會出現原型和...
本文不會過多講解基礎知識,更多說的是在使用useRef如何能擺脫 這個 閉包陷阱 ? react hooks 的閉包陷阱 基本每個開發員都有遇見,這是很令人抓狂的。 (以下react示范demo,均為react 16.8.3 版本) 列一個具體的場景: functionApp(){ const[count,setCount]=useState(1); useEffect(()=...
摘要:今天同學去面試,做了兩道面試題全部做錯了,發過來給道典型的面試題前端掘金在界中,開發人員的需求量一直居高不下。 排序算法 -- JavaScript 標準參考教程(alpha) - 前端 - 掘金來自《JavaScript 標準參考教程(alpha)》,by 阮一峰 目錄 冒泡排序 簡介 算法實現 選擇排序 簡介 算法實現 ... 圖例詳解那道 setTimeout 與循環閉包的經典面...
閱讀 890·2021-10-25 09:44
閱讀 1260·2021-09-23 11:56
閱讀 1183·2021-09-10 10:50
閱讀 3130·2019-08-30 15:53
閱讀 2132·2019-08-30 13:17
閱讀 616·2019-08-29 18:43
閱讀 2490·2019-08-29 12:57
閱讀 854·2019-08-26 12:20