摘要:對(duì)數(shù)組函數(shù)而言,相當(dāng)于產(chǎn)生了個(gè)閉包。關(guān)于對(duì)象在閉包中使用對(duì)象也會(huì)導(dǎo)致一些問題。不過,匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其對(duì)象通常指向。由于聲明函數(shù)時(shí)與聲明函數(shù)時(shí)的值是不同的,因此閉包與閉包貌似將會(huì)表示各自不同的值。
這幾天看到閉包一章,從工具書到各路大神博客,都各自有著不同的理解,以下我將選擇性的抄(咳咳,當(dāng)然還是會(huì)附上自己理解的)一些大神們對(duì)閉包的原理及其使用文章,當(dāng)作是自己初步理解這一功能函數(shù)的過程吧。
首先先上鏈接:
簡(jiǎn)書作者波同學(xué)的JS進(jìn)階文章系列: 前端基礎(chǔ)進(jìn)階系列 其他: JS秘密花園 javascript深入理解js閉包 阮一峰《JavaScript標(biāo)準(zhǔn)參考教程》 一不小心就做錯(cuò)的JS閉包面試題還有一些也很不錯(cuò),但主要是以應(yīng)用為主,原理解釋沒有上面幾篇深入,不過作為閉包的拓展應(yīng)用其實(shí)也可以看一看;
JavaScript中的匿名函數(shù)及函數(shù)的閉包
紅皮書《JS高程》的閉包:閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。創(chuàng)建閉包的常見方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。
從這句話我們知道:閉包是一個(gè)函數(shù)
function createComparisonFunction(propertyName) { return function(obj1,obj2) { var value1 = obj1[propertyName]; var value2 = obj2[propertyName]; if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } }; }
這段代碼,我們能直接看出,共存在三個(gè)作用域,Global、createComparisonFunction、匿名函數(shù)funciton,因其JS的作用域鏈特性,后者能訪問自身及前者的作用域。而返回的匿名函數(shù)即使在其他地方被調(diào)用了,但它仍可以訪問變量propertyName。之所以還能夠訪問這個(gè)變量,是因?yàn)閮?nèi)部函數(shù)的作用域鏈中包含createComparisonFunction的作用域。我們來深入了解一下,函數(shù)執(zhí)行時(shí)具體發(fā)生了什么?
當(dāng)?shù)谝粋€(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境(Execution Context,也叫執(zhí)行上下文)及相應(yīng)的作用域鏈,并把作用域鏈賦值給一個(gè)特殊的內(nèi)部屬性[[Scope]]。然后,使用this、arguments和其他命名參數(shù)的值來初始化函數(shù)的活動(dòng)對(duì)象(Activation Object)。但在作用域鏈中,外部函數(shù)的活動(dòng)對(duì)象處于第二位,外部函數(shù)的外部函數(shù)處于第三位,最后是全局執(zhí)行環(huán)境(Global Context)。
換一個(gè)栗子:
function createFunctions() { var result = new Array(); for (var i=0;i<10;i++) { result[i] = function() { return i; }; } return result; } var arr = createFunctions(); alert(arr[0]()); // 10 alert(arr[1]()); // 10
/這個(gè)函數(shù)返回一個(gè)函數(shù)數(shù)組。表面上看,似乎每個(gè)函數(shù)都應(yīng)該返回自己的索引值,位置0的函數(shù)返回0,位置1的函數(shù)返回1,以此類推。但但實(shí)際上,每個(gè)函數(shù)都返回10,為什么?
數(shù)組對(duì)象內(nèi)的匿名函數(shù)里的i是引用createFunctions作用域內(nèi)的,當(dāng)調(diào)用數(shù)組內(nèi)函數(shù)的時(shí)候,createFunctions函數(shù)早已執(zhí)行完畢。
這圖不傳也罷了,畫得忒丑了。
數(shù)組內(nèi)的閉包函數(shù)指向的i,存放在createFunctions函數(shù)的作用域內(nèi),確切的說,是在函數(shù)的變量對(duì)象里,for循環(huán)每次更新的i值,就是從它那兒來的。所以當(dāng)調(diào)用數(shù)組函數(shù)時(shí),循環(huán)已經(jīng)完成,i也為循環(huán)后的值,都為10;
有人會(huì)問,那result[i]為什么沒有變?yōu)?0呢?
要知道,作用域的判定是看是否在函數(shù)內(nèi)的,result[i] = function.......是在匿名函數(shù)外,那它就還是屬于createFunctions的作用域內(nèi),那result[i]里的i就依然會(huì)更新
那么如何使結(jié)果變?yōu)槲覀兿胍哪??也是通過閉包。
function createFunctions() { var result = []; for (var i=0;i<10;i++) { !function(i) { result[i] = function() {console.log(i)}; }(i); } return result; } var arr = createFunctions(); arr[0](); arr[1](); arr[2]();
function createFunctions() { var result = []; function fn(i) { result[i] = function() {console.log(i)} }; for (var i=0;i<10;i++) { fn(i); } return result; } var arr = createFunctions(); arr[0](); arr[1](); arr[2]();
var arr = []; function fn(i) { arr[i] = function() {console.log(i)} } function createFunctions() { for (var i=0;i<10;i++) { fn(i); } } fn(createFunctions()); arr[0](); arr[1](); arr[2]();
以第一種為例,通過一個(gè)立即調(diào)用函數(shù),將外函數(shù)當(dāng)前循環(huán)的i值作為實(shí)參傳入,并存放在立即調(diào)用函數(shù)的變量對(duì)象內(nèi),此時(shí),這個(gè)函數(shù)立即調(diào)用函數(shù)和數(shù)組內(nèi)的匿名函數(shù)就相當(dāng)于一個(gè)閉包,數(shù)組的匿名函數(shù)引用了立即調(diào)用函數(shù)變量對(duì)象內(nèi)的i。當(dāng)createFuncions執(zhí)行完畢,里面的i值已經(jīng)是10了。但是由于閉包的特性,每個(gè)函數(shù)都有各自的i值對(duì)應(yīng)著。對(duì)數(shù)組函數(shù)而言,相當(dāng)于產(chǎn)生了10個(gè)閉包。
所以能看出,閉包也十分的占用內(nèi)存,只要閉包不執(zhí)行,那么變量對(duì)象就無法被回收,所以不是特別需要,盡量不使用閉包。
關(guān)于this對(duì)象在閉包中使用this對(duì)象也會(huì)導(dǎo)致一些問題。我們知道,this對(duì)象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的;在全局對(duì)象中,this等于window,而當(dāng)函數(shù)被作為某個(gè)對(duì)象的方法調(diào)用時(shí),this等于那個(gè)對(duì)象。不過,匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其this對(duì)象通常指向window。但有時(shí)候由于編寫閉包的方式不同,這一點(diǎn)可能不會(huì)那么明顯。(當(dāng)然可以用call和apply)
var name = "The Window"; var obj = { name:"My Object", getName:function () { var bibao = function () { return this.name; }; return bibao; } }; alert(obj.getName()()); // The Window
先創(chuàng)建一個(gè)全局變量name,又創(chuàng)建一個(gè)包含name屬性的對(duì)象。這個(gè)對(duì)象包含一個(gè)方法——getName(),它返回一個(gè)匿名函數(shù),而匿名函數(shù)又返回this.name。由于getName()返回一個(gè)函數(shù),因此調(diào)用obj.getName()();就會(huì)立即調(diào)用它返回的函數(shù),結(jié)果就是返回一個(gè)字符串。然而,這個(gè)例子返回的字符串是"The Window",即全局name變量的值。為什么匿名函數(shù)沒有取得其波包含作用域(或外部作用域)的this對(duì)象呢?
每個(gè)函數(shù)調(diào)用時(shí)其活動(dòng)對(duì)象都會(huì)自動(dòng)取得兩個(gè)特殊變量:this和arguments。
內(nèi)部函數(shù)在搜索這兩個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對(duì)象為止,因此永遠(yuǎn)不可能直接訪問外部函數(shù)中的這兩個(gè)變量。不過,把外部作用域中的this對(duì)象保存在一個(gè)閉包能夠訪問到的變量里,就可以讓閉包訪問該對(duì)象了。
var name = "The Window"; var obj = { name:"My Object", getName:function () { var that = this; return function () { return that.name; }; } }; alert(obj.getName()());
this和arguments也存在同樣的問題,如果想訪問作用域中arguments對(duì)象,必須將該對(duì)象的引用保存到另一個(gè)閉包能夠訪問的變量中。
var name = "The Window"; var obj = { name:"My Object", getName:function (arg1,arg2) { var arg = []; arg[0] = arg1; arg[1] = arg2; function bibao() { return arg[0]+arg[1]; } return bibao; } }; alert(obj.getName(1,2)())obj.getName方法保存了其接收到的實(shí)參在它的變量對(duì)象上,并在執(zhí)行函數(shù)結(jié)束后沒有被回收,因?yàn)榉祷氐拈]包函數(shù)引用著obj.Name方法里的arg數(shù)組對(duì)象。使得外部變量成功訪問到了函數(shù)內(nèi)部作用域及其局部變量。
在幾種特殊情況下,this引用的值可能會(huì)意外的改變。
var name = "The Window"; var obj = { name:"My Object", getName:function () { return this.name; } };
這里的getName()只簡(jiǎn)單的返回this.name的值。
var name = "The Window"; var obj = { name:"My Object", getName:function () { console.log(this.name); } }; obj.getName(); // "My Object" (obj.getName)(); // "My Object" (obj.getName = obj.getName)(); // "The Window"
第一個(gè)obj.getName函數(shù)作為obj對(duì)象的方法調(diào)用,則自然其this引用指向obj對(duì)象。
第二個(gè),加括號(hào)將函數(shù)定義之后,作為函數(shù)表達(dá)式執(zhí)行調(diào)用,this引用指向不變。
第三個(gè),括號(hào)內(nèi)先執(zhí)行了一條賦值語句,然后在調(diào)用賦值后的結(jié)果。相當(dāng)于重新定義了函數(shù),this引用的值不能維持,于是返回"The Window"。
用setTimeout結(jié)合循環(huán)考察閉包是一個(gè)很老的面試題了
// 利用閉包,修改下面的代碼,讓循環(huán)輸出的結(jié)果依次為1, 2, 3, 4, 5 for (var i=1; i<=5; i++) { setTimeout( function timer() { console.log(i); }, i*1000 ); }setTimeout的執(zhí)行與我們平常的JS代碼執(zhí)行不一樣,這里需要提到一個(gè)隊(duì)列數(shù)據(jù)結(jié)構(gòu)執(zhí)行的概念。 關(guān)于setTimeout與循環(huán)閉包的思考題
個(gè)人理解:由于setTimeout函數(shù)的特殊性,須等其他非隊(duì)列結(jié)構(gòu)代碼執(zhí)行完畢后,這個(gè)setTimeout函數(shù)才會(huì)進(jìn)入隊(duì)列執(zhí)行棧。
用chrome開發(fā)者工具分析這段代碼,可以先自己分析一次,看看依次彈出什么?setTimeout(function() { console.log(a); }, 0); var a = 10; console.log(b); console.log(fn); var b = 20; function fn() { setTimeout(function() { console.log("setTImeout 10ms."); }, 10); } fn.toString = function() { return 30; } console.log(fn); setTimeout(function() { console.log("setTimeout 20ms."); }, 20); fn();
答案:
設(shè)置斷點(diǎn)如圖所示,今天剛學(xué)Chrome的開發(fā)者工具,有哪些使用上的錯(cuò)誤還請(qǐng)指出。
我分別給變量a、b、fn函數(shù)都設(shè)置了觀察,變量的值變化將會(huì)實(shí)時(shí)地在右上角中顯示,可以看到,在JS解釋器運(yùn)行第一行代碼前,變量a、b就已經(jīng)存在了,而fn函數(shù)已經(jīng)完成了聲明。接下來我們繼續(xù)執(zhí)行。要注意:藍(lán)色部分說明這些代碼將在下一次操作中執(zhí)行,而不是已經(jīng)執(zhí)行完畢。
把第一個(gè)setTimeout函數(shù)執(zhí)行完畢后也沒有反應(yīng)。我給三個(gè)setTimeout內(nèi)的匿名函數(shù)也加上觀察選項(xiàng),卻顯示不可使用。
所以,下一次執(zhí)行會(huì)發(fā)生什么?對(duì)console出b的值,但是b沒賦值,右上角也看到了,所以顯示undefined。
而console.log(fn)就是將fn函數(shù)函數(shù)體從控制臺(tái)彈出,要注意,console會(huì)隱式調(diào)用toString方法,這個(gè)會(huì)在后面講到。
現(xiàn)在第26行之前(不包括26行)的代碼都已略過,a,b變量也已得到賦值,繼續(xù)執(zhí)行。
重寫了toString方法前:
重寫后:
toString方法是Object所有,所有由它構(gòu)造的實(shí)例都能調(diào)用,現(xiàn)在這個(gè)方法被改寫并作為fn對(duì)象的屬性(方法)保留下來。
console會(huì)隱式調(diào)用toString方法,所以30行的console會(huì)彈出30;
繼續(xù)執(zhí)行,定義setTimeout函數(shù)也是什么沒有發(fā)生,知道調(diào)用fn前。
調(diào)用fn,是不是就會(huì)執(zhí)行setTimeout函數(shù)呢?其實(shí)沒有,我們可以看到call stack一欄已經(jīng)是fn的執(zhí)行棧了,但是依舊沒發(fā)生什么。
但是:
當(dāng)call stack里的環(huán)境都已退出,執(zhí)行棧里沒有任何上下文時(shí),三個(gè)setTimeout函數(shù)就執(zhí)行了,那這三個(gè)時(shí)間戳函數(shù)那個(gè)先執(zhí)行,那個(gè)后執(zhí)行呢?由設(shè)定的延遲時(shí)間決定,這個(gè)延遲時(shí)間是相對(duì)于其他代碼執(zhí)行完畢的那一刻。
不信我們可以通過改變延遲時(shí)間重新試一次就知道了。
我們?cè)诳椿卦瓉淼拈]包代碼:
// 利用閉包,修改下面的代碼,讓循環(huán)輸出的結(jié)果依次為1, 2, 3, 4, 5 for (var i=1; i<=5; i++) { setTimeout( function timer() { console.log(i); }, i*1000 ); }
先確認(rèn)一個(gè)問題,setTimeout函數(shù)里的匿名函數(shù)的i指向哪兒?對(duì),是全局變量里的i。
setTimeout里的匿名函數(shù)執(zhí)行前,外部循環(huán)已經(jīng)結(jié)束,i值已經(jīng)更新為6,這時(shí)setTimeout調(diào)用匿名函數(shù),里面的i當(dāng)然都是6了。
我們需要?jiǎng)?chuàng)建一個(gè)能夠保存當(dāng)前i值的"盒子"給匿名函數(shù),使得匿名函數(shù)能夠引用新創(chuàng)建的父函數(shù)。
// 利用閉包,修改下面的代碼,讓循環(huán)輸出的結(jié)果依次為1, 2, 3, 4, 5 for (var i=1; i<=5; i++) { !function (i) { setTimeout( function timer() { console.log(i); }, i*1000 ); }(i); }
自調(diào)用函數(shù)就是那個(gè)"盒子"
關(guān)于《JavaScript編程全解》中的說明考慮這個(gè)函數(shù):
function f(arg) { var n = 123 + Number(arg); function g() {console.log("n is "+n);console.log("g is called");} n++; function gg() {console.log("n is "+n);console.log("g is called");} return [g,gg]; }
調(diào)用數(shù)組內(nèi)函數(shù)的console結(jié)果是什么?
var arr = f(1); arr[0](); // 對(duì)閉包g的調(diào)用 // "n is 125" "g is called" arr[1](); // 對(duì)閉包gg的調(diào)用 // "n is 125" "gg is called"
函數(shù)g與函數(shù)gg保持了各自含有局部變量n的執(zhí)行環(huán)境。由于聲明函數(shù)g時(shí)與聲明函數(shù)gg時(shí)的n值是不同的,因此閉包g與閉包gg貌似將會(huì)表示各自不同的n值。實(shí)際上兩者都將表示相同的值。因?yàn)樗鼈円昧送粋€(gè)對(duì)象。
即都是引用了,f函數(shù)執(zhí)行環(huán)境內(nèi)變量對(duì)象內(nèi)的n值。當(dāng)執(zhí)行f(1)的時(shí)候,n值就已經(jīng)更新為最后計(jì)算的值。
防范命名空間的污染 模塊:在JavaScript中,最外層代碼(函數(shù)之外)所寫的名稱(變量名與函數(shù)名)具有全局作用域,即所謂的全局變量與全局函數(shù)。JavaScript的程序代碼即使在分割為多個(gè)源文件后,也能相互訪問其全局名稱。在JavaScript的規(guī)范中不存在所謂的模塊的語言功能。
因此,對(duì)于客戶端JavaScript,如果在一個(gè)HTML文件中對(duì)多個(gè)JavaScript文件進(jìn)行讀取,則他們相互的全局名稱會(huì)發(fā)生沖突。也就是說,在某個(gè)文件中使用的名稱無法同時(shí)在另一個(gè)文件中使用。即使在獨(dú)立開發(fā)中這也很不方便,在使用他們開發(fā)的庫之類時(shí)就更加麻煩了。
此外,全局變量還降低了代碼的可維護(hù)性。不過也不能就簡(jiǎn)單下定論說問題只是由全局變量造成的。這就如同在Java這種語言規(guī)范并不支持全局變量的語言中,同樣可以很容易創(chuàng)建出和全局變量功能類似的變量。
從形式上看,在JavaScript中減少全局變量的數(shù)量的方法時(shí)很簡(jiǎn)單的。首先我們按照下面的代碼這樣預(yù)設(shè)一下全局函數(shù)與全局變量。
// 全局函數(shù) function sum(a,b) { return Number(a)+Number(b); } // 全局變量 var position = {x:2,y:3}; // 借助通過對(duì)象字面量生成對(duì)象的屬性,將名稱封入對(duì)象的內(nèi)部。于是從形式上看,全局變量減少了 var MyModule = { sum:function (a,b) { return Number(a)+Number(b); }, position:{x:2,y:3} }; alert(MyModule.sum(3,3)); // 6 alert(MyModule.position.x); // 2
上面的例子使用對(duì)象字面量,不過也可以像下面這樣不使用對(duì)象字面量。
var MyModule = {}; // 也可以通過new表達(dá)式生成 MyModule.sum = function (a,b) {return Number(a)+Number(b);}; MyModule.position = {x:2,y:3};
這個(gè)例子中,我們將MyModule稱為模塊名。如果完全采用這種方式,對(duì)于1個(gè)文件來說,只需要一個(gè)模塊名就能消減全局變量的數(shù)量。當(dāng)然,模塊名之間仍然可能產(chǎn)生沖突,不過這一問題在其他程序設(shè)計(jì)語言中也是一個(gè)無法被避免的問題。
通過這種將名稱封入對(duì)象之中的方法,可以避免名稱沖突的問題。但是這并沒有解決全局名稱的另一個(gè)問題,也就是作用域過廣的問題。通過MyModule.position.x這樣一個(gè)較長(zhǎng)的名稱,就可以從代碼的任意一處訪問該變量。
// 在此調(diào)用匿名函數(shù) // 由于匿名函數(shù)的返回值是一個(gè)函數(shù),所以變量sum是一個(gè)函數(shù) var sum = (function () { // 無法從函數(shù)外部訪問該名稱 // 實(shí)際上,這變成了一個(gè)私有變量 // 一般來說,在函數(shù)被調(diào)用之后該名稱就無法再被訪問 // 不過由于是在被返回的匿名函數(shù)中,所以仍可以繼續(xù)被使用 var p = {x:2,y:3}; // 同樣是一個(gè)從函數(shù)外無法被訪問的私有變量 // 將其命名為sum也可以。不過為了避免混淆,這里采用其他名稱 function sum_internal(a,b) { return Number(a)+Number(b); } // 只不過是為了使用上面的兩個(gè)名稱而隨意設(shè)計(jì)的返回值 return function (a,b) { alert("x = "+p.x); return sum_internal(a,b); } })(); console.log(sum(3,4)); // "x = 2" // "y"
上面的代碼可以抽象為下面這種形式的代碼。在利用函數(shù)作用域封裝名稱,以及閉包可以使名稱在函數(shù)調(diào)用結(jié)束后依然存在這兩個(gè)特性。這樣信息隱藏得以實(shí)現(xiàn)。
(function(){函數(shù)體})();
像上面這樣,當(dāng)場(chǎng)調(diào)用函數(shù)的代碼看起來或許有些奇怪。一般的做法是先在某處聲明函數(shù),之后在需要時(shí)調(diào)用。不過這種做法是JavaScript的一種習(xí)慣用法,加以掌握。
匿名函數(shù)的返回值是一個(gè)函數(shù),不過即使返回值不是函數(shù),也同樣能采用這一方法。比如返回一個(gè)對(duì)象字面量以實(shí)現(xiàn)信息隱藏的功能。
var obj = (function() { // 從函數(shù)外部無法訪問該名稱 // 實(shí)際上,這是一個(gè)私有變量 var p = {x:2,y:3}; // 這同樣是一個(gè)無法從函數(shù)外部訪問的私有函數(shù) function sum_internal(a,b) { return Number(a+b); } // 只不過為了使用上面的兩個(gè)名稱而隨意設(shè)計(jì)的返回值 return { sum:function (a,b) { return sum_internal(a,b); }, x:p.x }; })(); alert(obj.sum(3,4)); // 7 alert(obj.x); // 2閉包與類
利用函數(shù)作用域與閉包,可以實(shí)現(xiàn)訪問在控制,上一節(jié)中,模塊的函數(shù)在被聲明之后立即就對(duì)其調(diào)用,而是用了閉包的類則能夠在生成實(shí)例時(shí)調(diào)用。即便如此,著厚重那個(gè)做法在形式上仍然只是單純的函數(shù)生命。下面是一個(gè)通過閉包來對(duì)類進(jìn)行定義的例子
// 用于生成實(shí)例的函數(shù) function myclass(x,y) { return {show:function () {alert(x+" | "+y)}}; } var obj = myclass(3,2); obj.show(); // 3 | 2
這里再舉一個(gè)具體的例子,一個(gè)實(shí)現(xiàn)了計(jì)數(shù)器功能的類。
這里重申一下:JavaScript的語言特性沒有"類"的概念。但這里的類指的是,實(shí)際上將會(huì)調(diào)用構(gòu)造函數(shù)的Function對(duì)象。此外在強(qiáng)調(diào)對(duì)象是通過調(diào)用構(gòu)造函數(shù)生成的時(shí)候,會(huì)將這些被生成的對(duì)象稱作對(duì)象實(shí)例以示區(qū)別。
表達(dá)式閉包JavaScript有一種自帶的增強(qiáng)功能,稱為支持函數(shù)型程序設(shè)計(jì)的表達(dá)式閉包(Expression closure)。
從語法結(jié)構(gòu)上看,表達(dá)式閉包是函數(shù)聲明表達(dá)式的一種省略形式??梢韵裣旅孢@樣省略只有return的函數(shù)聲明表達(dá)式中的return與{}。
var sum = function (a,b) {return Number(a+b)}; // 可以省略為 var sum = function (a,b) Number(a+b);
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/87034.html
摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語言,讓我們來看一下語言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對(duì)閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語言,發(fā)現(xiàn)不光是js,php、...
摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語言,讓我們來看一下語言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對(duì)閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語言,發(fā)現(xiàn)不光是js,php、...
摘要:注此讀書筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過閱讀你不知道的后的理解。作用域及閉包基礎(chǔ),代碼運(yùn)行的幕后工作者引擎及編譯器。 注:此讀書筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過閱讀《你不知道的JS》后的理解。 作用域及閉包基礎(chǔ),JS代碼運(yùn)行的幕后工作者:引擎及編譯器。引擎負(fù)責(zé)JS程序的編譯及執(zhí)行,編譯器負(fù)責(zé)詞法分析和代碼生成。那么作用域就像一個(gè)容器,引擎及編譯器都從這里提取東西。 ...
摘要:但閉包的情況不同嵌套函數(shù)的閉包執(zhí)行后,,然后還在被回收閉包會(huì)使變量始終保存在內(nèi)存中,如果不當(dāng)使用會(huì)增大內(nèi)存消耗。每個(gè)函數(shù),不論多深,都可以認(rèn)為是全局的子作用域,可以理解為閉包。 閉包(closure)是Javascript語言的一個(gè)難點(diǎn),也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。 閉包的特性 閉包有三個(gè)特性: 1.函數(shù)嵌套函數(shù) 2.函數(shù)內(nèi)部可以引用外部的參數(shù)和變量 3.參數(shù)和變量不會(huì)...
摘要:閉包是什么這是一個(gè)在面試的過程中出現(xiàn)的概率為以上的問題,也是我們張口就來的問題。文章推薦我們面試中在被問到閉包這個(gè)問題是要注意的幾點(diǎn)閉包的延伸,讓面試變得 閉包是什么?這是一個(gè)在面試的過程中出現(xiàn)的概率為60%以上的問題,也是我們張口就來的問題。但是我們往往發(fā)現(xiàn),在面試的過程中我們的回答并不那么讓面試官滿意,我們雖然能張口說出一些但是卻不能系統(tǒng)的對(duì)這個(gè)問題進(jìn)行回答。面試官希望加入自己團(tuán)隊(duì)...
閱讀 3246·2021-11-24 10:22
閱讀 3206·2021-11-23 10:10
閱讀 1559·2021-09-28 09:35
閱讀 1894·2019-08-29 13:16
閱讀 1532·2019-08-26 13:29
閱讀 2934·2019-08-26 10:27
閱讀 810·2019-08-26 10:09
閱讀 1600·2019-08-23 18:05