您好,登錄后才能下訂單哦!
今天小編給大家分享一下JavaScript中如何應用閉包的相關知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
什么是閉包(Closure)
簡單講,閉包就是指有權訪問另一個函數(shù)作用域中的變量的函數(shù)。
MDN 上面這么說:閉包是一種特殊的對象。它由兩部分構成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境。環(huán)境由閉包創(chuàng)建時在作用域中的任何局部變量組成。
但是,網(wǎng)上找了好多資料,它們對閉包的定義也各有各樣,搞得我也不知道怎么去定義閉包了,所以干脆不去定義了,意會吧。
道可道,非常道;名可名,非常名。
產(chǎn)生一個閉包
創(chuàng)建閉包最常見方式,就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。下面例子中的 closure 就是一個閉包:
function func(){ var a = 1,b = 2; function closure(){ return a+b; } return closure; }
閉包的作用域鏈包含著它自己的作用域,以及包含它的函數(shù)的作用域和全局作用域。
閉包的注意事項
通常,函數(shù)的作用域及其所有變量都會在函數(shù)執(zhí)行結束后被銷毀。但是,在創(chuàng)建了一個閉包以后,這個函數(shù)的作用域就會一直保存到閉包不存在為止。
function makeAdder(x) { return function(y) { return x + y; }; } var add5 = makeAdder(5); var add10 = makeAdder(10); console.log(add5(2)); // 7 console.log(add10(2)); // 12 // 釋放對閉包的引用 add5 = null; add10 = null;
add5 和 add10 都是閉包。它們共享相同的函數(shù)定義,但是保存了不同的環(huán)境。在 add5 的環(huán)境中,x 為 5。而在 add10 中,x 則為 10。***通過 null 釋放了 add5 和 add10 對閉包的引用。
在javascript中,如果一個對象不再被引用,那么這個對象就會被垃圾回收機制回收;
如果兩個對象互相引用,而不再被第3者所引用,那么這兩個互相引用的對象也會被回收。
閉包只能取得包含函數(shù)中任何變量的***一個值,這是因為閉包所保存的是整個變量對象,而不是某個特殊的變量。
function test(){ var arr = []; for(var i = 0;i < 10;i++){ arr[i] = function(){ return i; }; } for(var a = 0;a < 10;a++){ console.log(arr[a]()); } } test(); // 連續(xù)打印 10 個 10
對于上面的情況,如果我們改變代碼如下:
function test(){ var arr = []; for(let i = 0;i < 10;i++){ // 僅在這里作出了改動 arr[i] = function(){ return i; }; } for(var a = 0;a < 10;a++){ console.log(arr[a]()); } } test(); // 打印 0 到 9
對于上面兩種代碼的解釋,請看我在 segmentfault 上面的提問:鏈接
閉包中的 this 對象
var name = "The Window"; var obj = { name: "My Object", getName: function(){ return function(){ return this.name; }; } }; console.log(obj.getName()()); // The Window
obj.getName()()實際上是在全局作用域中調(diào)用了匿名函數(shù),this指向了window。這里要理解函數(shù)名與函數(shù)功能(或者稱函數(shù)值)是分割開的,不要認為函數(shù)在哪里,其內(nèi)部的this就指向哪里。匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其 this 對象通常指向 window。
var name = "The Window"; var obj = { name: "My Object", getName: function(){ var that = this; return function(){ return that.name; }; } }; console.log(obj.getName()()); // My Object
閉包的應用
應用閉包的主要場合是:設計私有的方法和變量。
任何在函數(shù)中定義的變量,都可以認為是私有變量,因為不能在函數(shù)外部訪問這些變量。私有變量包括函數(shù)的參數(shù)、局部變量和函數(shù)內(nèi)定義的其他函數(shù)。
把有權訪問私有變量的公有方法稱為特權方法(privileged method)。
function Animal(){ // 私有變量 var series = "哺乳動物"; function run(){ console.log("Run!!!"); } // 特權方法 this.getSeries = function(){ return series; }; }
模塊模式(The Module Pattern):為單例創(chuàng)建私有變量和方法。
單例(singleton):指的是只有一個實例的對象。JavaScript 一般以對象字面量的方式來創(chuàng)建一個單例對象。
var singleton = { name: "percy", speak:function(){ console.log("speaking!!!"); }, getName: function(){ return this.name; } };
上面是普通模式創(chuàng)建的單例,下面使用模塊模式創(chuàng)建單例:
var singleton = (function(){ // 私有變量 var age = 22; var speak = function(){ console.log("speaking!!!"); }; // 特權(或公有)屬性和方法 return { name: "percy", getAge: function(){ return age; } }; })();
匿名函數(shù)***的用途是創(chuàng)建閉包,并且還可以構建命名空間,以減少全局變量的使用。從而使用閉包模塊化代碼,減少全局變量的污染。
var objEvent = objEvent || {}; (function(){ var addEvent = function(){ // some code }; function removeEvent(){ // some code } objEvent.addEvent = addEvent; objEvent.removeEvent = removeEvent; })();
在這段代碼中函數(shù) addEvent 和 removeEvent 都是局部變量,但我們可以通過全局變量 objEvent 使用它,這就大大減少了全局變量的使用,增強了網(wǎng)頁的安全性。
一個閉包計數(shù)器
var countNumber = (function(){ var num = 0; return function(){ return ++num; }; })();
閉包的缺陷
閉包的缺點就是常駐內(nèi)存會增大內(nèi)存使用量,并且使用不當很容易造成內(nèi)存泄露。
如果不是因為某些特殊任務而需要閉包,在沒有必要的情況下,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因為閉包對腳本性能具有負面影響,包括處理速度和內(nèi)存消耗。
***再來一些有關閉包的面試題
下面代碼中,標記 ? 的地方輸出分別是什么?
function fun(n,o){ console.log(o); return { fun: function(m){ return fun(m,n); } }; } var a = fun(0); // ? a.fun(1); // ? a.fun(2); // ? a.fun(3); // ? var b = fun(0).fun(1).fun(2).fun(3); // ? var c = fun(0).fun(1); // ? c.fun(2); // ? c.fun(3); // ?
undefined 0 0 0 undefined, 0, 1, 2 undefined, 0 1 1
以上就是“JavaScript中如何應用閉包”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。