日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

JavaScript闭包特性详解

發布時間:2023/12/2 综合教程 41 生活家
生活随笔 收集整理的這篇文章主要介紹了 JavaScript闭包特性详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天來總結一下js閉包的那些事,以及遇到的坑和解決方法,希望對你有所幫助。

是的,沒看錯標題,重要的事情要說三篇,JavaScript閉包。

在看下面的總結前,先來復習一下之前寫過的幾篇閉包(都是淚):

  1. 閉包相關的代碼
  2. js16:匿名函數和閉包
  3. 單擊li,輸出當前li在列表的序號

首先先簡要總結閉包特性:

  • 函數的局部變量在函數返回之后仍然可用
  • 棧上的內存空間在函數返回之后仍在存在,不被回收

給個例子。下面這段代碼會返回一個函數的引用:

function sayHello2(name) {
    var text = 'Hello ' + name; // Local variable
    var sayAlert = function() { alert(text); }
    return sayAlert;
}
say2 = sayHello2('Bob');
say2(); // alerts "Hello Bob"

對于這段代碼,C程序員可能會認為sayAlertsay2一樣,都是指向一個函數的指針。但實際上它倆有一個重要區別: 在JavaScript中,你可以認為一個函數的指針變量同時擁有兩個指針。一個指向這個函數,另一個隱藏的指針指向一個閉包。

重點在于你的函數內是否引用的外部變量。

在JavaScript中,如果你在一個函數內定義一個新的函數,那么這個新的函數就是一個閉包。 對于C或者其他高級語言,函數執行結束并返回之后,它所占用的棧空間將被釋放回收。函數內定義的局部變量將不再可用。但在JavaScript中,并不這樣。如上所示,函數執行結束后,它所占用的棧空間并不會被全部回收。

上面是基本理論。更進一步,再來一個例子:

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

這個例子說明:閉包中使用的函數局部變量并非是值拷貝,而是引用。say667()執行結束之后number所在的那塊內存的值為667,而sayNumber()是在say667()執行結束之后才執行,當它訪問number所在的內存時,結果自然也是667。

再進一步,看看用closure時易發生的錯誤的例子:

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]();
    }
}

時刻保持清醒:變量是在內存里的,閉包使用的是內存的引用而不是那塊內存的值拷貝。

當你在循環中定義函數(閉包)的時候得小心,它可能并不像你最開始想的那樣工作。關鍵有兩個:

  • 子函數使用的是外部函數的局部變量的引用。
  • 循環內只是定義了子函數,并沒有執行這個字函數。

最后,來一個最抽象的例子:

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);
      }
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;

這個例子說明,閉包的創建時機是在函數被調用的時候。每次函數調用都會生成一個新的閉包,也就是一塊新的內存區域。因為函數每次調用都會新分配一塊棧內存,這是一回事。

最后我自己來總結一下閉包:

  • 函數的局部變量在其他地方被引用
  • 閉包有兩種基本情況:閉包的返回值是一個函數,它其中使用了該閉包的局部變量;閉包內定義了內部函數,內部函數引用了閉包的局部變量
  • 每次函數調用,都會生成一個新的閉包,分配新的內存

實例:(滑過tab)

window.onload= function(){
var tits = $('#tabTit1 li');
var cons = $('#tabCon1 .con');
var len = cons.length;
var liChange = function(){
for(var n=0;n<len;n++){
tits[n].className = tits[n].className.replace(/s*cur/g,'');
cons[n].className = cons[n].className.replace(/s*cur/g,'');
}
}
for(var i = 0; i<tits.length; i++){
tits[i].i = i;
tits[i].onmouseover = function(){
liChange();
cons[this.i].addClass('cur');
tits[this.i].addClass('cur');
}
}
};

總結

以上是生活随笔為你收集整理的JavaScript闭包特性详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。