最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

理解和運(yùn)用JavaScript的閉包機(jī)制

 更新時(shí)間:2015年08月13日 12:14:24   作者:libuchao  
這篇文章主要介紹了理解和運(yùn)用JavaScript的閉包機(jī)制,是JavaScript入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下

偉大的愛因斯坦同志說過:“如果你無法向一個 6 歲小孩解釋清楚某問題,那說明你自己都沒整明白”。然而,當(dāng)我向一個 27 歲的朋友解釋什么是閉包時(shí),卻徹底失敗了。

這原本是國外某哥們兒在 Stack Overflow 上對 JavaScript 閉包所提出的問題。不過既然此問題是在 Stack Overflow 提出的,當(dāng)然也會有很多高手出來解答,其中有些回答確實(shí)是經(jīng)典,如下面這個:

如果在一個外部函數(shù)中再定義一個內(nèi)部函數(shù),即函數(shù)嵌套函數(shù),那么內(nèi)部函數(shù)也可以訪問外部函數(shù)中的變量:

function foo(x) {
 var tmp = 3;
 function bar(y) {
 alert(x + y + (++tmp));
 }
 bar(10);
}

foo(2); // alert 16
foo(2); // alert 16
foo(2); // alert 16

此段代碼可以正確執(zhí)行,并返回結(jié)果:16,因?yàn)?bar 能訪問外部函數(shù)的變量 tmp, 同時(shí)也能訪問外部函數(shù) foo 的參數(shù) x。但以上示例不是閉包!

要實(shí)現(xiàn)閉包的話,需要將內(nèi)部函數(shù)作為外部函數(shù)的返回值返回,內(nèi)部函數(shù)在返回前,會將所有已訪問過的外部函數(shù)中的變量在內(nèi)存中鎖定,也就是說,這些變量將常駐 bar 的內(nèi)存中,不會被垃圾回收器回收,如下:

function foo(x) {
 var tmp = 3;
 return function (y) {
 alert(x + y + (++tmp));
 }
}
var bar = foo(2); // bar 現(xiàn)在是個閉包了
bar(10); // alert 16
bar(10); // alert 17
bar(10); // alert 18

上述代碼中,第一次執(zhí)行 bar 時(shí),仍會返回結(jié)果:16,因?yàn)?bar 仍然可以訪問 x 及 tmp,盡管它已經(jīng)不直接存在于 foo 的作用域內(nèi)。那么既然 tmp 被鎖定在 bar 的閉包里,那么每次執(zhí)行 bar 的時(shí)候,tmp 都會自增一次,所以第二次和第三次執(zhí)行 bar 時(shí),分別返回 17 和 18。

此示例中,x 僅僅是個純粹的數(shù)值,當(dāng) foo 被調(diào)用時(shí),數(shù)值 x 就會作為參數(shù)被拷貝至 foo 內(nèi)。

但是 JavaScript 處理對象的時(shí)候,使用的總是引用,如果用一個對象作為參數(shù)來調(diào)用 foo,那么 foo 中傳入的實(shí)際上是原始對象的引用,所以這個原始對象也相當(dāng)于被閉包了,如下:

function foo(x) {
 var tmp = 3;
 return function (y) {
 alert(x + y + tmp++);
 x.memb = x.memb ? x.memb + 1 : 1;
 alert(x.memb);
 }
}
var age = new Number(2);
var bar = foo(age); // bar 現(xiàn)在是個閉包了
bar(10); // alert 15 1
bar(10); // alert 16 2
bar(10); // alert 17 3

和期望的一樣,每次執(zhí)行 bar(10) 時(shí),不但 tmp 自增了,x.memb 也自增了,因?yàn)楹瘮?shù)體內(nèi)的 x 和函數(shù)體外的 age 引用的是同一個對象。

via http://stackoverflow.com/questions/111102/how-do-javascript-closures-work

補(bǔ)充:通過以上示例,應(yīng)該能比較清楚的理解閉包了。如果覺得自己理解了,可以試著猜猜下面這段代碼的執(zhí)行結(jié)果:

function foo(x) {
 var tmp = 3;
 return function (y) {
 alert(x + y + tmp++);
 x.memb = x.memb ? x.memb + 1 : 1;
 alert(x.memb);
 }
}
var age = new Number(2);
var bar1 = foo(age); // bar1 現(xiàn)在是個閉包了
bar1(10); // alert 15 1
bar1(10); // alert 16 2
bar1(10); // alert 17 3

var bar2 = foo(age); // bar2 現(xiàn)在也是個閉包了
bar2(10); // alert ? ?
bar2(10); // alert ? ?
bar2(10); // alert ? ?

bar1(10); // alert ? ?
bar1(10); // alert ? ?
bar1(10); // alert ? ?

實(shí)際使用的時(shí)候,閉包可以創(chuàng)建出非常優(yōu)雅的設(shè)計(jì),允許對funarg上定義的多種計(jì)算方式進(jìn)行定制。如下就是數(shù)組排序的例子,它接受一個排序條件函數(shù)作為參數(shù):

[1, 2, 3].sort(function (a, b) {
 ... // 排序條件
});

同樣的例子還有,數(shù)組的map方法是根據(jù)函數(shù)中定義的條件將原數(shù)組映射到一個新的數(shù)組中:

[1, 2, 3].map(function (element) {
 return element * 2;
}); // [2, 4, 6]

使用函數(shù)式參數(shù),可以很方便的實(shí)現(xiàn)一個搜索方法,并且可以支持無限制的搜索條件:

someCollection.find(function (element) {
 return element.someProperty == 'searchCondition';
});

還有應(yīng)用函數(shù),比如常見的forEach方法,將函數(shù)應(yīng)用到每個數(shù)組元素:

[1, 2, 3].forEach(function (element) {
 if (element % 2 != 0) {
  alert(element);
 }
}); // 1, 3

順便提下,函數(shù)對象的 apply 和 call方法,在函數(shù)式編程中也可以用作應(yīng)用函數(shù)。 這里,我們將它們看作是應(yīng)用函數(shù) —— 應(yīng)用到參數(shù)中的函數(shù)(在apply中是參數(shù)列表,在call中是獨(dú)立的參數(shù)):

(function () {
 alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);

閉包還有另外一個非常重要的應(yīng)用 —— 延遲調(diào)用:

var a = 10;
setTimeout(function () {
 alert(a); // 10, after one second
}, 1000);
還有回調(diào)函數(shù):

//...
var x = 10;
// only for example
xmlHttpRequestObject.onreadystatechange = function () {
 // 當(dāng)數(shù)據(jù)就緒的時(shí)候,才會調(diào)用;
 // 這里,不論是在哪個上下文中創(chuàng)建
 // 此時(shí)變量“x”的值已經(jīng)存在了
 alert(x); // 10
};
//...

還可以創(chuàng)建封裝的作用域來隱藏輔助對象:

var foo = {};

// 初始化
(function (object) {

 var x = 10;

 object.getX = function _getX() {
  return x;
 };

})(foo);

alert(foo.getX()); // 獲得閉包 "x" – 10

相關(guān)文章

  • ASP.NET實(shí)現(xiàn)Repeater控件的數(shù)據(jù)綁定

    ASP.NET實(shí)現(xiàn)Repeater控件的數(shù)據(jù)綁定

    這篇文章介紹了ASP.NET實(shí)現(xiàn)Repeater控件數(shù)據(jù)綁定的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • JS入門代碼集合

    JS入門代碼集合

    在閃吧看見了一篇js教程,感覺不錯 適合閱讀范圍:對JavaScript一無所知~離精通只差一步之遙的人
    2008-05-05
  • JavaScript 基礎(chǔ)篇之運(yùn)算符、語句(二)

    JavaScript 基礎(chǔ)篇之運(yùn)算符、語句(二)

    其實(shí)運(yùn)算符大家要是有計(jì)算機(jī)語言基礎(chǔ)應(yīng)該都知道,可能甚至比我還精通,這樣我就不多解釋了,就來說說其它幾個生疏的吧
    2012-04-04
  • 簡介JavaScript中charAt()方法的使用

    簡介JavaScript中charAt()方法的使用

    這篇文章主要介紹了JavaScript中charAt()方法的使用詳解,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-06-06
  • javascript冒泡排序小結(jié)

    javascript冒泡排序小結(jié)

    冒泡排序由于比較簡單和容易理解,往往會成為人們首先想到的排序算法。最基本的想法就是在一次里面比較兩個數(shù)字,并且確保他們在移動到其他項(xiàng)目之前有一個正確的順序。在每一關(guān)結(jié)束,有價(jià)值的“排序”到正確的位置,最終只留下其他項(xiàng)目排序。
    2016-04-04
  • javascript回調(diào)函數(shù)詳解

    javascript回調(diào)函數(shù)詳解

    這篇文章主要介紹了javascript回調(diào)函數(shù)的相關(guān)知識點(diǎn)以及用法代碼實(shí)例分析,對此有需要的朋友可以學(xué)習(xí)參考下。
    2018-02-02
  • 詳解JavaScript實(shí)現(xiàn)異步Ajax

    詳解JavaScript實(shí)現(xiàn)異步Ajax

    本文詳細(xì)講解了JavaScript實(shí)現(xiàn)異步Ajax的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • js檢測瀏覽器版本、核心、是否移動端示例

    js檢測瀏覽器版本、核心、是否移動端示例

    這篇文章主要介紹了js檢測瀏覽器版本、核心、是否移動端示例,需要的朋友可以參考下
    2014-04-04
  • 提取字符串中年月日的函數(shù)代碼

    提取字符串中年月日的函數(shù)代碼

    提取字符串中年月日的函數(shù)代碼,需要的朋友可以過來參考下。希望對大家有所幫助
    2013-11-11
  • 在JavaScript中typeof的用途介紹

    在JavaScript中typeof的用途介紹

    本篇文章,小編為大家介紹,在JavaScript中typeof的用途介紹。不過在閱讀本文的前提是,你現(xiàn)在應(yīng)該已經(jīng)知道原始值和對象值的區(qū)別了
    2013-04-04

最新評論

九龙城区| 新巴尔虎左旗| 河西区| 红河县| 安西县| 镇原县| 弋阳县| 班玛县| 日照市| 陈巴尔虎旗| 图片| 汤原县| 平江县| 元朗区| 泊头市| 舟山市| 葵青区| 铜山县| 新巴尔虎左旗| 焦作市| 甘孜| 苏尼特左旗| 长沙市| 四会市| 彝良县| 禄丰县| 娱乐| 华蓥市| 庆元县| 嘉荫县| 中卫市| 读书| 托克托县| 二手房| 南丰县| 上饶市| 本溪| 田林县| 淮滨县| 泰兴市| 保德县|