亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > JavaScript > 正文

Javascript閉包實例詳解

2024-05-06 16:25:27
字體:
來源:轉載
供稿:網友
閉包就是函數的局部變量集合,只是這些局部變量在函數返回后會繼續存在,本文通過代碼實例給大家介紹javascript閉包,對javascipt閉包相關知識感興趣的朋友一起學習吧
 

什么是閉包

閉包是什么?閉包是Closure,這是靜態語言所不具有的一個新特性。但是閉包也不是什么復雜到不可理解的東西,簡而言之,閉包就是:

閉包就是函數的局部變量集合,只是這些局部變量在函數返回后會繼續存在。

閉包就是就是函數的“堆棧”在函數返回后并不釋放,我們也可以理解為這些函數堆棧并不在棧上分配而是在堆上分配當在一個函數內定義另外一個函數就會產生閉包上面的第二定義是第一個補充說明,抽取第一個定義的主謂賓——閉包是函數的‘局部變量'集合。只是這個局部變量是可以在函數返回后被訪問。(這個不是官方定義,但是這個定義應該更有利于你理解閉包)

理解Javascript的閉包非常關鍵,本篇試圖用最簡單的例子理解此概念。

function greet(sth){  return function(name){    console.log(sth + ' ' + name);  }}//hi darrengreet('hi')('darren');

或者可以寫成這樣:

var sayHi = greet('hi');sayHi('darren');


我們要提的問題是:為什么greet的內部函數能使用sth這個變量?

其內部大致運作如下:

→ 創建全局上下文
→ 執行var sayHi = greet('hi');語句,創建greet上下文,變量sth存儲在greet上下文中。
→ 繼續執行greet函數內的語句,返回一個匿名函數,雖然greet上下文從堆棧上消失,但sth變量依舊存在于內存的某個空間。
→ 繼續執行sayHi('darren');創建了sayHi上下文,并試圖搜尋sth變量,但在sayHi這個上下文中沒有sth變量。sayHi上下文會沿著一個作用域鏈找到sth變量對應的那個內存。 外層函數就像一個閉包,其內部函數可以使用外部函數的變量。

一個閉包的簡單例子

function buildFunctions(){  var funcArr = [];  for(var i = 0; i < 3; i++){    funcArr.push(function(){console.log(i)});  }  return funcArr;}var fs = buildFunctions();fs[0](); //3fs[1](); //3fs[2](); //3

以上,為什么結果不是0, 1, 2呢?

--因為i作為一個閉包變量,當前值為3,被內部函數使用。要實現想要的效果,可以在遍歷的時候每一次遍歷創建一個獨立的上下文使其不受閉包影響。而自觸發函數可以實現獨立上下文。

function buildFunctions(){  var funcArr = [];  for(var i = 0; i < 3; i++){    funcArr.push((function(j){      return function(){       console.log(j);      };    }(i)));  }  return funcArr;}var fs = buildFunctions();fs[0](); //0fs[1](); //1fs[2](); //2

本篇的兩個例子正好體現了閉包的2個方面:一個是內部函數使用閉包變量,另一個是把內部函數寫在自觸發函數中從而避免受閉包影響。

做為局部變量都可以被函數內的代碼訪問,這個和靜態語言是沒有差別。閉包的差別在于局部變變量可以在函數執行結束后仍然被函數外的代碼訪問。這意味 著函數必須返回一個指向閉包的“引用”,或將這個”引用”賦值給某個外部變量,才能保證閉包中局部變量被外部代碼訪問。當然包含這個引用的實體應該是一個 對象,因為在Javascript中除了基本類型剩下的就都是對象了??上У氖?,ECMAScript并沒有提供相關的成員和方法來訪問閉包中的局部變 量。但是在ECMAScript中,函數對象中定義的內部函數() inner function是可以直接訪問外部函數的局部變量,通過這種機制,我們就可以以如下的方式完成對閉包的訪問了。

function greeting(name) {   var text = 'Hello ' + name; // local variable   // 每次調用時,產生閉包,并返回內部函數對象給調用者   return function () { alert(text); }}var sayHello=greeting( "Closure" );sayHello() // 通過閉包訪問到了局部變量text

上述代碼的執行結果是:Hello Closure,因為sayHello()函數在greeting函數執行完畢后,仍然可以訪問到了定義在其之內的局部變量text。

好了,這個就是傳說中閉包的效果,閉包在Javascript中有多種應用場景和模式,比如Singleton,Power Constructor等這些Javascript模式都離不開對閉包的使用。

ECMAScript閉包模型

ECMAScript到底是如何實現閉包的呢?想深入了解的親們可以獲取ECMAScript 規范進行研究,我這里也只做一個簡單的講解,內容也是來自于網絡。

在ECMAscript的腳本的函數運行時,每個函數關聯都有一個執行上下文場景(Execution Context) ,這個執行上下文場景中包含三個部分

文法環境(The LexicalEnvironment)
變量環境(The VariableEnvironment)
this綁定

其中第三點this綁定與閉包無關,不在本文中討論。文法環境中用于解析函數執行過程使用到的變量標識符。我們可以將文法環境想象成一個對象,該對 象包含了兩個重要組件,環境記錄(Enviroment Recode),和外部引用(指針)。環境記錄包含包含了函數內部聲明的局部變量和參數變量,外部引用指向了外部函數對象的上下文執行場景。全局的上下文 場景中此引用值為NULL。這樣的數據結構就構成了一個單向的鏈表,每個引用都指向外層的上下文場景。

例如上面我們例子的閉包模型應該是這樣,sayHello函數在最下層,上層是函數greeting,最外層是全局場景。如下圖:

 

因此當sayHello被調用的時候,sayHello會通過上下文場景找到局部變量text的值,因此在屏幕的對話框中顯示出”Hello Closure”
變量環境(The VariableEnvironment)和文法環境的作用基本相似,具體的區別請參看ECMAScript的規范文檔。

閉包的樣列

前面的我大致了解了Javascript閉包是什么,閉包在Javascript是怎么實現的。下面我們通過針對一些例子來幫助大家更加深入的理解閉包,下面共有5個樣例,例子來自于JavaScript Closures For Dummies(鏡像)。

例子1:閉包中局部變量是引用而非拷貝

function say667() {  // Local variable that ends up within closure  var num = 666;  var sayAlert = function() { alert(num); }  num++;  return sayAlert;}var sayAlert = say667();sayAlert()

因此執行結果應該彈出的667而非666。

例子2:多個函數綁定同一個閉包,因為他們定義在同一個函數內。

function setupSomeGlobals() {  // Local variable that ends up within closure  var num = 666;  // Store some references to functions as global variables  gAlertNumber = function() { alert(num); }  gIncreaseNumber = function() { num++; }  gSetNumber = function(x) { num = x; }}setupSomeGolbals(); // 為三個全局變量賦值gAlertNumber(); //666gIncreaseNumber();gAlertNumber(); // 667gSetNumber(12);//gAlertNumber();//12

例子3:當在一個循環中賦值函數時,這些函數將綁定同樣的閉包

function buildList(list) {  var result = [];  for (var i = 0; i < list.length; i++) {    var item = 'item' + list[i];    result.push( function() {alert(item + ' ' + list[i])} );  }  return result;}function testList() {  var fnlist = buildList([1,2,3]);  // using j only to help prevent confusion - could use i  for (var j = 0; j < fnlist.length; j++) {    fnlist[j]();  }}

testList的執行結果是彈出item3 undefined窗口三次,因為這三個函數綁定了同一個閉包,而且item的值為最后計算的結果,但是當i跳出循環時i值為4,所以list[4]的結果為undefined.

例子4:外部函數所有局部變量都在閉包內,即使這個變量聲明在內部函數定義之后。

function sayAlice() {  var sayAlert = function() { alert(alice); }  // Local variable that ends up within closure  var alice = 'Hello Alice';  return sayAlert;}var helloAlice=sayAlice();helloAlice();

執行結果是彈出”Hello Alice”的窗口。即使局部變量聲明在函數sayAlert之后,局部變量仍然可以被訪問到。

例子5:每次函數調用的時候創建一個新的閉包

function newClosure(someNum, someRef) {  // Local variables that end up within closure  var num = someNum;  var anArray = [1,2,3];  var ref = someRef;  return function(x) {    num += x;    anArray.push(num);    alert('num: ' + num +    '/nanArray ' + anArray.toString() +    '/nref.someVar ' + ref.someVar);  }}closure1=newClosure(40,{someVar:'closure 1'});closure2=newClosure(1000,{someVar:'closure 2'});closure1(5); // num:45 anArray[1,2,3,45] ref:'someVar closure1'closure2(-10);// num:990 anArray[1,2,3,990] ref:'someVar closure2'

閉包的應用

Singleton 單件:

var singleton = function () {  var privateVariable;  function privateFunction(x) {    ...privateVariable...  }  return {    firstMethod: function (a, b) {      ...privateVariable...    },    secondMethod: function (c) {      ...privateFunction()...    }  };}();

這個單件通過閉包來實現。通過閉包完成了私有的成員和方法的封裝。匿名主函數返回一個對象。對象包含了兩個方法,方法1可以方法私有變量,方法2訪 問內部私有函數。需要注意的地方是匿名主函數結束的地方的'()',如果沒有這個'()'就不能產生單件。因為匿名函數只能返回了唯一的對象,而且不能被 其他地方調用。這個就是利用閉包產生單件的方法。



注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
美女国内精品自产拍在线播放| 在线观看视频99| 日本精品视频在线观看| 日韩免费中文字幕| 91精品啪aⅴ在线观看国产| 亚洲一区二区少妇| 久久久久久久久久久久久久久久久久av| 夜夜嗨av一区二区三区免费区| 68精品国产免费久久久久久婷婷| 国产色视频一区| 欧美日韩国内自拍| 97香蕉久久超级碰碰高清版| 国产一区二区三区高清在线观看| 国产欧美一区二区三区久久| 欧美精品videossex88| 欧美日本国产在线| 综合136福利视频在线| 日韩av在线播放资源| 亚洲精品福利在线观看| 91久久精品国产| 国产欧美一区二区三区在线| 欧美一级大片在线免费观看| 亚洲一区二区三区视频播放| 精品日韩中文字幕| 欧美乱大交xxxxx| 欧美体内谢she精2性欧美| 欧美黄色www| 精品久久中文字幕| 日韩极品精品视频免费观看| 91精品视频在线免费观看| 成人深夜直播免费观看| 国产精品视频精品| 亚洲一区二区三区乱码aⅴ蜜桃女| 精品国产91乱高清在线观看| 久久这里只有精品视频首页| 亚洲视频在线观看| 国产一级揄自揄精品视频| 国产精品高清免费在线观看| 欧美精品少妇videofree| 国产精品高清网站| 国产一区二中文字幕在线看| 日韩免费观看视频| 久久久久五月天| 91午夜在线播放| 亚洲日韩中文字幕在线播放| 亚洲精品99999| 中文字幕久久久av一区| 中文日韩在线观看| 欧美色播在线播放| 国产日韩换脸av一区在线观看| 国产亚洲精品高潮| 麻豆一区二区在线观看| 欧美特级www| 欧洲亚洲妇女av| 日韩一区视频在线| 亚洲片在线观看| 亚洲免费人成在线视频观看| 亚洲视频在线播放| 992tv成人免费视频| 欧美国产精品va在线观看| 亚洲三级av在线| 在线播放精品一区二区三区| 日韩美女在线观看| 久久综合电影一区| 欧美一区二区影院| 欧美成人午夜激情视频| 午夜精品在线观看| 秋霞成人午夜鲁丝一区二区三区| 欧美成人黄色小视频| 91精品视频免费观看| 性欧美激情精品| 国产精品久久久久久久7电影| 欧美日本黄视频| 日本精品视频在线播放| 日韩av黄色在线观看| 久久久精品欧美| 亚洲国产精彩中文乱码av在线播放| 精品中文字幕乱| 中文字幕欧美日韩va免费视频| 国产一区二区三区久久精品| 亚洲欧洲国产一区| 久久婷婷国产麻豆91天堂| 亚洲天堂免费视频| 午夜欧美不卡精品aaaaa| 亚洲免费人成在线视频观看| 福利一区视频在线观看| 欧美精品久久久久| 亚洲黄色片网站| 91免费综合在线| 91av免费观看91av精品在线| 欧美午夜精品久久久久久人妖| 亚洲福利影片在线| 国产三级精品网站| 国产精品久久久久久久久久小说| 青草热久免费精品视频| 日韩专区在线观看| 精品亚洲一区二区三区在线观看| 国产精品丝袜一区二区三区| 久久免费视频在线观看| 日本精品中文字幕| 欧美成人精品xxx| 亚洲综合日韩在线| 亚洲国产成人久久| 日韩免费看的电影电视剧大全| 久久视频免费在线播放| 久久久亚洲国产天美传媒修理工| 国产97在线|日韩| 成人xxxxx| 国内偷自视频区视频综合| 精品视频在线播放免| 夜夜狂射影院欧美极品| 国产女同一区二区| 欧美成人精品三级在线观看| 91久久在线视频| 欧美视频二区36p| 欧美极品在线播放| 欧美日韩在线视频一区| 日韩电影中文字幕在线| 午夜精品一区二区三区视频免费看| 在线日韩av观看| 成人a视频在线观看| 欧美视频免费在线| 国产精品欧美一区二区| 中文在线不卡视频| 中文字幕精品久久久久| 国产日本欧美一区| 97香蕉久久超级碰碰高清版| 欧美国产高跟鞋裸体秀xxxhd| 国产偷亚洲偷欧美偷精品| 91a在线视频| 538国产精品视频一区二区| 国产不卡av在线免费观看| 国产精品夜间视频香蕉| 久久天天躁狠狠躁夜夜av| 欧美黑人狂野猛交老妇| 国产精品美女午夜av| 成人av番号网| 亚洲国产精品嫩草影院久久| 久久久久久久久久国产精品| 日韩在线免费观看视频| 亚洲精品国产精品自产a区红杏吧| 性色av香蕉一区二区| 国产美女久久久| 日韩精品在线观看视频| 欧美日韩成人在线播放| 精品视频中文字幕| 538国产精品视频一区二区| 国产精品青草久久久久福利99| 亚洲国产成人精品久久| 日韩电视剧在线观看免费网站| 亚洲精品乱码久久久久久按摩观| 5252色成人免费视频| 亚洲视频一区二区三区| 成人乱人伦精品视频在线观看| 最近2019中文字幕mv免费看| 91视频国产一区| 国产欧美韩国高清| 日本高清视频一区| 国产精品免费视频xxxx| 久久亚洲私人国产精品va| 国产精品免费小视频| 欧美做爰性生交视频| 91色视频在线观看| 久久久999国产|