摘要:函數(shù)對(duì)象可以通過(guò)這個(gè)作用域鏈相互關(guān)聯(lián)起來(lái),如此,函數(shù)體內(nèi)部的變量都可以保存在函數(shù)的作用域內(nèi),這在計(jì)算機(jī)的文獻(xiàn)中被稱之為閉包。所以按照第二段所說(shuō)的,嚴(yán)格意義上所有的函數(shù)都是閉包。
Like most modern programming languages, JavaScript uses lexical scoping. This means that functions are executed using the variable scope that was in effect when they were defined, not the variable scope that is in effect when they are invoked. In order to implement lexical scoping, the internal state of a JavaScript function object must in- clude not only the code of the function but also a reference to the current scope chain. (Before reading the rest of this section, you may want to review the material on variable scope and the scope chain in §3.10 and §3.10.3.) This combination of a function object and a scope (a set of variable bindings) in which the function’s variables are resolved is called a closure in the computer science literature. (This is an old term that refers to the fact that the function’s variables have bindings in the scope chain and that therefore the function is “closed over” its variables.)
Technically, all JavaScript functions are closures: they are objects, and they have a scope chain associated with them. Most functions are invoked using the same scope chain that was in effect when the function was defined, and it doesn’t really matter that there is a closure involved. Closures become interesting when they are invoked under a different scope chain than the one that was in effect when they were defined. This happens most commonly when a nested function object is returned from the function within which it was defined. There are a number of powerful programming techniques that involve this kind of nested function closures, and their use has become relatively common in JavaScript programming. Closures may seem confusing when you first en- counter them, but it is important that you understand them well enough to use them comfortably.
JavaScript, The Definite Guide
翻譯成中文的話也許是這樣:
和大多數(shù)的現(xiàn)代化編程語(yǔ)言一樣,JavaScript是采用詞法作用域的,這就意味著函數(shù)的執(zhí)行依賴于函數(shù)定義的時(shí)候所產(chǎn)生(而不是函數(shù)調(diào)用的時(shí)候產(chǎn)生的)的變量作用域。為了去實(shí)現(xiàn)這種詞法作用域,JavaScript函數(shù)對(duì)象的內(nèi)部狀態(tài)不僅包含函數(shù)邏輯的代碼,除此之外還包含當(dāng)前作用域鏈的引用。函數(shù)對(duì)象可以通過(guò)這個(gè)作用域鏈相互關(guān)聯(lián)起來(lái),如此,函數(shù)體內(nèi)部的變量都可以保存在函數(shù)的作用域內(nèi),這在計(jì)算機(jī)的文獻(xiàn)中被稱之為閉包。
從技術(shù)的角度去將,所有的JavaScript函數(shù)都是閉包:他們都是對(duì)象,他們都有一個(gè)關(guān)聯(lián)到他們的作用域鏈。絕大多數(shù)函數(shù)在調(diào)用的時(shí)候使用的作用域鏈和他們?cè)诙x的時(shí)候的作用域鏈?zhǔn)窍嗤模沁@并不影響閉包。當(dāng)調(diào)用函數(shù)的時(shí)候閉包所指向的作用域鏈和定義函數(shù)時(shí)的作用域鏈不是同一個(gè)作用域鏈的時(shí)候,閉包become interesting。這種interesting的事情往往發(fā)生在這樣的情況下: 當(dāng)一個(gè)函數(shù)嵌套了另外的一個(gè)函數(shù),外部的函數(shù)將內(nèi)部嵌套的這個(gè)函數(shù)作為對(duì)象返回。一大批強(qiáng)大的編程技術(shù)都利用了這類嵌套的函數(shù)閉包,當(dāng)然,javascript也是這樣。可能你第一次碰見(jiàn)閉包覺(jué)得比較難以理解,但是去明白閉包然后去非常自如的使用它是非常重要的。
通俗點(diǎn)說(shuō),在程序語(yǔ)言范疇內(nèi)的閉包是指函數(shù)把其的變量作用域也包含在這個(gè)函數(shù)的作用域內(nèi),形成一個(gè)所謂的“閉包”,這樣的話外部的函數(shù)就無(wú)法去訪問(wèn)內(nèi)部變量。所以按照第二段所說(shuō)的,嚴(yán)格意義上所有的函數(shù)都是閉包。
需要注意的是:我們常常所說(shuō)的閉包指的是讓外部函數(shù)訪問(wèn)到內(nèi)部的變量,也就是說(shuō),按照一般的做法,是使內(nèi)部函數(shù)返回一個(gè)函數(shù),然后操作其中的變量。這樣做的話一是可以讀取函數(shù)內(nèi)部的變量,二是可以讓這些變量的值始終保存在內(nèi)存中。
JavaScript利用閉包的這個(gè)特性,就意味著當(dāng)前的作用域總是能夠訪問(wèn)外部作用域中的變量。
function counter (start) { var count = start; return { add: function () { count ++; }, get: function () { return count; }, }; } var foo = counter (4); foo.add(); foo.get() //5
上面的代碼中,counter函數(shù)返回的是兩個(gè)閉包(兩個(gè)內(nèi)部嵌套的函數(shù)),這兩個(gè)函數(shù)維持著對(duì)他們外部的作用域counter的引用,因此這兩個(gè)函數(shù)沒(méi)有理由不可以訪問(wèn)count ;
在JavaScript中沒(méi)有辦法在外部訪問(wèn)count(JavaScript不可以強(qiáng)行對(duì)作用域進(jìn)行引用或者賦值),唯一可以使用的途徑就是以這種閉包的形式去訪問(wèn)。
對(duì)于閉包的使用,最常見(jiàn)的可能是下面的這個(gè)例子:
for (var i = 0; i < 10; i++) { setTimeout (function (i) { console.log (i); //10 10 10 .... }, 1000); }
在上面的例子中,當(dāng)console.log被調(diào)用的時(shí)候,匿名函數(shù)保持對(duì)外部變量的引用,這個(gè)時(shí)候for 循環(huán)早就已經(jīng)運(yùn)行結(jié)束,輸出的i值也就一直是10。但這在一般的意義上并不是我們想要的結(jié)果。
為了獲得我們想要的結(jié)果,我們一般是這樣做:
for (var i = 0; i < 10; i++) { (function (e) { setTimeout (function () { console.log (e); }, 1000); })(i); }
外部套著的這個(gè)函數(shù)不會(huì)像setTimeout一樣延遲,而是直接立即執(zhí)行,并且把i作為他的參數(shù),這個(gè)時(shí)候e就是對(duì)i的一個(gè)拷貝。當(dāng)時(shí)間達(dá)到后,傳給setTimeout的時(shí)候,傳遞的是e的引用。這個(gè)值是不會(huì)被循環(huán)所改變的。
除了上面的寫法之外,這樣的寫法顯然也是沒(méi)有任何問(wèn)題的:
for (var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log (e); } })(i), 1000); }
或許,還可以借助這個(gè)故事理解一下:
I"m a big fan of analogy and metaphor when explaining difficult concepts, so let me try my hand with a story.
Once upon a time:
There was a princess...
function princess() {She lived in a wonderful world full of adventures. She met her Prince Charming, rode around her world on a unicorn, battled dragons, encountered talking animals, and many other fantastical things.
var adventures = []; function princeCharming() { /* ... */ } var unicorn = { /* ... */ }, dragons = [ /* ... */ ], squirrel = "Hello!";But she would always have to return back to her dull world of chores and grown-ups.
return {And she would often tell them of her latest amazing adventure as a princess.
story: function() { return adventures[adventures.length - 1]; } }; }But all they would see is a little girl...
var littleGirl = princess();...telling stories about magic and fantasy.
littleGirl.story();And even though the grown-ups knew of real princesses, they would never believe in the unicorns or dragons because they could never see them. The grown-ups said that they only existed inside the little girl"s imagination.
But we know the real truth; that the little girl with the princess inside...
...is really a princess with a little girl inside.
http://stackoverflow.com/a/6472397/4681656
原文鏈接:http://life.rccoder.net/javascript/1214.html
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/78367.html
摘要:深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對(duì)閉包的定義為閉包是指那些能夠訪問(wèn)自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對(duì)閉包的定義為: 閉包是指那些能夠訪問(wèn)自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...
摘要:今天同學(xué)去面試,做了兩道面試題全部做錯(cuò)了,發(fā)過(guò)來(lái)給道典型的面試題前端掘金在界中,開(kāi)發(fā)人員的需求量一直居高不下。 排序算法 -- JavaScript 標(biāo)準(zhǔn)參考教程(alpha) - 前端 - 掘金來(lái)自《JavaScript 標(biāo)準(zhǔn)參考教程(alpha)》,by 阮一峰 目錄 冒泡排序 簡(jiǎn)介 算法實(shí)現(xiàn) 選擇排序 簡(jiǎn)介 算法實(shí)現(xiàn) ... 圖例詳解那道 setTimeout 與循環(huán)閉包的經(jīng)典面...
摘要:目錄執(zhí)行環(huán)境與作用域鏈立即執(zhí)行函數(shù)閉包知識(shí)點(diǎn)什么是閉包使用閉包的意義與注意點(diǎn)閉包的具體應(yīng)用小結(jié)這是基本語(yǔ)法的函數(shù)部分的第篇文章,主要講述了中比較重要的知識(shí)點(diǎn)閉包在講閉包之前,在上一篇函數(shù)二的基礎(chǔ)上,進(jìn)一步深化執(zhí)行環(huán)境和作用域鏈的知識(shí)點(diǎn),并補(bǔ) 目錄 1.執(zhí)行環(huán)境與作用域鏈 2. 立即執(zhí)行函數(shù) 3. 閉包知識(shí)點(diǎn) 3.1 什么是閉包 3.2 使用閉包的意義與注意點(diǎn) 3.3 閉包的具體應(yīng)用 4...
摘要:的變量作用域是基于其特有的作用域鏈的。需要注意的是,用創(chuàng)建的函數(shù),其作用域指向全局作用域。所以,有另一種說(shuō)法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。 作用域 定義 在編程語(yǔ)言中,作用域控制著變量與參數(shù)的可見(jiàn)性及生命周期,它能減少名稱沖突,而且提供了自動(dòng)內(nèi)存管理 --javascript 語(yǔ)言精粹 我理解的是,一個(gè)變量、函數(shù)或者成員可以在代碼中訪問(wèn)到的范圍。 js的變量作...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開(kāi)發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...
閱讀 497·2021-09-03 00:22
閱讀 1372·2021-08-03 14:03
閱讀 2088·2021-07-25 21:37
閱讀 653·2019-08-30 13:18
閱讀 1880·2019-08-29 16:19
閱讀 2689·2019-08-29 13:22
閱讀 1300·2019-08-29 12:16
閱讀 2590·2019-08-26 12:16