您好,登錄后才能下訂單哦!
本篇內容主要講解“JavaScript中“閉包”的含義和作用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“JavaScript中“閉包”的含義和作用”吧!
在JavaScript中,根據詞法作用域的規則,內部函數總是可以訪問其外部函數聲明的變量,當通過調用一個外部函數返回一個內部函數后,即使該外部函數已經執行結束了,但是內部函數引用外部函數的變量依然保存在內存中,就把這些變量的集合稱為閉包。
在一個函數中嵌套另一個函數或者將一個匿名函數作為值傳入另一個函數中。
// 函數fun1中嵌套了fun2,fun2作為參數返回,外部調用時仍能打印val1,構成閉包 function fun1() { const val1 = 10; function fun2() { console.log(val1); } return fun2; } function fun3() { const val2 = 20; // 定時器中的為一個匿名函數,其作為參數傳入了,函數fun3執行完畢之后,1s鐘后才會執行定時器函數,但此時還能打印val2,構成閉包 setTimeout(function() { console.log(val2); }, 1000); }
根據下面的函數來看看閉包的整個執行流程
function main() { const val1 = 20; var val2 = 2 function valResult() { return val1 * val2; } return valResult; } var result = main(); console.log(result()); // 40
上圖中展示了各個時期的調用棧,需要重點關注以下幾點:
鴻蒙官方戰略合作共建——HarmonyOS技術社區
當main函數執行完畢后,main函數的執行上下文從棧頂彈出;
返回的方法(valResult)中調用了main函數中的val1和val2變量,這兩個變量就會打包成closure閉包,加到[[scopes]];
調用返回的方法時,作用域鏈為:result函數作用域——Closure(main)——全局作用域
優點
(1)可以重復使用變量,并且不會造成變量污染;
(2)可以用來定義私有屬性和私有方法
缺點
(1)會產生不銷毀的上下文,導致棧/堆內存消耗過大
(2)會造成內存泄露。
擴展:閉包是怎么回收的?
鴻蒙官方戰略合作共建——HarmonyOS技術社區
如果閉包引入的函數是一個全局變量,那么閉包會一直存在直到頁面關閉;但如果這個閉包以后不再使用的話,就會造成內存泄露;
如果引用閉包的函數是一個局部變量,等函數銷毀后,在下次JavaScript引擎執行垃圾回收時,判斷閉包內容已經不再被使用,則js引擎的垃圾回收器就會進行回收。
閉包用途主要有以下兩個:
創建私有變量
function MyName(name) { return { getName() { return name; } } } const myName = MyName('lili'); // 只能通過getName訪問對應的名字,別的方式訪問不到 console.log(myName.getName()); // lili
作為回調函數。當把函數作為值傳遞到某處,并在某個時刻進行回調的時候就會創建一個閉包。例如定時器、DOM事件監聽器、Ajax請求。
function fun(name) { setTimeout(() => { console.log(name); }, 1000); } fun('linlin');
多個子函數的[[scope]]都是同時指向父級,是完全共享的。因此當父級的變量對象被修改時,所有子函數都受到影響。
for (var i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); }
上述代碼本意是輸出1、2、3、4,但結果卻是四個5,為了解決該問題,主要有三種辦法。
變量可以通過 函數參數的形式 傳入,避免使用默認的[[scope]]向上查找
for (var i = 1; i < 5; i++) { (function(i) { setTimeout(() => console.log(i), 1000); })(i); }
使用setTimeout包裹,通過第三個參數傳入。(注:setTimeout后面可以有多個參數,從第三個參數開始其就作為回掉函數的附加參數)
for (var i = 1; i < 5; i++) { setTimeout(value => console.log(value), 1000, i); }
使用 塊級作用域,讓變量成為自己上下文的屬性,避免共享
for (let i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); }
到此,相信大家對“JavaScript中“閉包”的含義和作用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。