中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript 精粹 基礎 進階(7)函數和作用域(閉包、作用域)

發布時間:2020-06-15 10:58:55 來源:網絡 閱讀:217 作者:huanghanzhilian 欄目:web開發

轉載請注明出處

原文連接 http://blog.huanghanlian.com/article/5b698f05b8ea642ea9213f4f

閉包在JavaScript?中是一個非常重要的概念。

閉包例子
function outer() {
    var loc = 30;
    return loc;
};
console.log(outer()); //30

outer函數是一個函數聲明,有一個局部變量loc賦值為30,返回loc

當這個函數調用之后,局部變量就會被釋放了,

function outer() {
    var loc = 30;
    return function() {
        return loc;
    };
};
var func = outer();
console.log(func()); //30

這個outer函數有一個loc的局部變量,返回值是一個匿名函數表達式,在這個函數表達式又返回outer函數的loc局部變量,這種情況loc是不會被釋放掉的。

調用var func = outer();返回的是一個匿名函數,這個匿名函數里面仍然能夠訪問到outer()de 局部變量loc,當outer()函數被調用之后,func()這個函數再次調用的時候任然能訪問到它外層outer()函數的局部變量loc
這種情況就是我們通常所說的閉包

那么閉包的作用是什么呢?在前端編程里,閉包是非常常見的

閉包無處不在

<body>
<input type="button" value="按鈕" id="but">
<script type="text/javascript">
var but = document.getElementById("but");
! function() {
    var loc = 0;
    but.onclick = function() {
        console.log(loc++);
    };
}();
</script>
</body>

JavaScript 精粹 基礎 進階(7)函數和作用域(閉包、作用域)

<input type="button" value="按鈕" id="but">
<script type="text/javascript">
var but = document.getElementById("but");
! function() {
    var loc = "locc";
    but.addEventListener('click', function() {
        console.log(loc);
    }, false);
}();
</script>

比如說我們可能有一些自己的局部變量,或者說我們的函數有一些外函數的變量,我們在做點擊事件的時候,這個點擊事件可能會用到外層的一些局部變量,有了閉包我們可以在數據的傳遞上更為靈活。

! function() {
    var loc = "loc";
    var url = "http://www.huanghanlian.com/";
    $.ajax({
        url: url,
        success: function() {
            //do sth
            console.log(loc);
        }
    });
}();

有一個異步的請求,用jq的$.ajax方法也可以在success的回調函數中去用到外層具體的一些變量。

因為閉包的緣故,在最外層匿名函數調用結束后,success的回調函數仍然可以訪問外層的局部變量。locurl

閉包-常見錯誤之循環閉包

document.body.innerHTML = "<div id=a1>aa</div>" + "<div id=a2>bb</div>" + "<div id=a3>cc</div>" + "<div id=a4>dd</div>";
for (var i = 1; i < 4; i++) {
    document.getElementById("a" + i).addEventListener('click', function() {
        console.log(i);//始終都是4
    }, false);
};

這里面在網頁上面添加三個元素,通過循環來給這三個元素綁定事件,想當點擊第一個元素的時候,輸出1點擊第二個輸出2第三個輸出3。實現方式是先循環獲取元素,給元素增加點擊事件,點擊事件里面會輸出i的值。

但是上面的代碼始終只會輸出4,這其實是閉包的原因,addEventListener('click', function() {這里是回調函數}是回調函數,也就是說當點擊時回調函數去做你想做的事情, 當我點擊的濕乎乎回調函數回去動態的拿到 i的值,這個i的值在整個初始化過程中完成之后實際上i的值就已經是4了,所以始終輸出4。

如果想想要實現效果就要用到閉包

document.body.innerHTML = "<div id=a1>aa</div>" + "<div id=a2>bb</div>" + "<div id=a3>cc</div>";
for (var i = 1; i < 4; i++) {
    ! function(i) {
        document.getElementById("a" + i).addEventListener('click', function() {
            console.log(i);//1,2,3
        }, false);
    }(i);
};

這個例子里面在每一層循環的時候,用一個匿名函數而且是立即執行的匿名函數給他包裝起來,然后將每一次遍歷的1.2.3分別的值去傳到這個匿名函數里,然后匿名函數接到這個參數i再放到點擊事件中去引用i當我們每次點擊事件輸出的值i就會取每一個閉包環境下的i。所以這樣就能達到效果。

閉包-封裝

閉包還有個好處就是可以封裝一些變量

(function() {
    var _userId = 23492;
    var _typeId = 'item';
    var expor = {};

    function converter(userId) {
        return +userId;
    };

    expor.getUserId = function() {
        return converter(_userId);
    };

    expor.getTypeId = function() {
        return _typeId;
    };
    window.expor = expor;
}());
console.log(expor.getUserId()); //23492
console.log(expor.getTypeId()); //item
console.log(expor._userId); //undefined
console.log(expor._typeId); //undefined

比如說以上代碼,有個立即調用函數,他有自己的函數作用域,在里面定義的局部變量外部是不可以訪問到的,最后可以通過window.expor = expor;這樣的方式來去把最終想輸出的對象輸出出去,那么外部就可以通過expor對象上提供的方法,就可以訪問到函數里面的對象或變量。

閉包的概念

在計算機科學中,閉包(也稱詞法閉包或函數閉包)是指一個函數或函數的引用,與一個引用環境綁在一起。這個引用環境是一個存儲該函數每個非局部變量(也叫自由變量)的表。

閉包,不同于一般函數,它允許一個函數在立即詞法作用域外調用時,仍可訪問非本地變量

作用域

全局,函數,eval [作用域]

JavaScript中的作用域,實際上是比較簡單的。

全局作用域

var a = 10;
console.log(window.a); //10

在最外層聲明變量a,這樣就聲明了全局作用域下的變量a。

for (var i = 0; i < 4; i++) {
    console.log(i); //0.1.2.3
}
console.log(i); //4

在全局范圍內用for循環里面有個vae i=0定義了一個變量i,可能會誤解為這個i只能在這個for循環里面可見,對外不可見,實際上這是錯誤的理解,JavaScript中是沒有塊級作用域的,也就是說不管是for循環while 循環里面去定義的變量,實際上和在外面定義的變量,也就是for循環所在的外面去定義變量實際上是沒有差別的,所以 i在外面也能訪問到。

函數作用域

(function() {
    var b = 20;
})();
console.log(b);//test_lt.html:13 Uncaught ReferenceError: b is not defined(…)

上面匿名立即執行函數表達式,在執行的時候聲明局部變量b,在函數外面是拿不到的。函數有自己獨立的作用域。

eval 作用域

eval("var a=1;");

作用域鏈

var le3 = 3;

function out() {
    var le = 1;

    function out2() {
        var le2 = 2;
        console.log(le, le2, le3); //1 2 3
    }
    out2()
}
out();

out()函數中有一個內部函數out2()它里面有一個局部變量le2,函數out2()能訪問到自己的內部變量le2,也可以在向上訪問le變量,也就是所謂的閉包,可以訪問外層函數的局部變量,對于函數out2()來講也叫作它的自由變量,還可以訪問最外層的le3變量,也就是全局對象,這個作用域手機從內向外都可以訪問的。

function out() {
    var le = 1;
    var func = new Function("var p=0;console.log(p);console.log(le)");
    func();
}
out();
//輸出
//0
//Uncaught ReferenceError: le is not defined(…)

如果使用new Function去構造的一個函數,構造器,去調用構造器定義位置所在的變量le的。

利用函數作用域封裝

(function() {
    //do sth here
    var a, b;
})();

! function() {
    //do sth here
    var a, b;
}();

利用函數作用域的特性,我們經常看到很多類庫,或者代碼最外層如果沒有模塊化的一些工具的話,會在最外層去寫一個function這樣一個匿名函數,這樣的好處就是可以把函數內部的變量變成函數的局部變量,而不是全局變量,這樣防止大量的全局變量和其他的一些類庫或者其他代碼引發沖突,! function() {}()這樣的作用其實就是把函數變成函數表達式,而不是函數聲明,如果省略掉這個!嘆號的話,那么他會理解為函數聲明,會被前置處理掉,那么最后留下一個括號或者你省略名字的話,都會報語法錯誤。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

仁化县| 临沧市| 开阳县| 咸阳市| 利辛县| 洛宁县| 宾阳县| 通许县| 诏安县| 罗山县| 阜阳市| 泗阳县| 化德县| 韩城市| 开封县| 宽城| 淮滨县| 买车| 上蔡县| 高安市| 静宁县| 漳浦县| 桑植县| 伊宁市| 顺昌县| 咸丰县| 巴东县| 田阳县| 宾川县| 乌鲁木齐县| 嘉兴市| 古丈县| 靖安县| 星子县| 慈溪市| 平和县| 平顺县| 昌江| 贵港市| 十堰市| 宁化县|