摘要:注意由定義可以知道,閉包函數肯定是定義在函數中,才可能有上級的函數作用域可以訪問,否則上級作用域就是全局作用域。造成這種結果的原因就是綁定的多個函數是閉包函數,他們共同使用保留的上級函數作用域中的變量。
1 閉包的定義
維持了自由變量不被釋放的函數, 稱為閉包,(自由變量指不在自身上下文,也不在全局上下文中的變量)。
那么閉包函數的特點在哪里,我們知道函數在創建的時候,它的[[scope]]屬性就已經確定并不可以改變,所以閉包函數在創建的時候就保存了上級的作用域鏈,閉包函數通過作用域鏈去尋找使用到的變量,正常情況下,函數在執行完畢后,將銷毀函數的執行上下文,但是由于閉包函數的存在,包含閉包函數的上級函數執行完畢后,如果閉包函數還存在,那么這個上級函數的作用域中的變量仍然保留在內存中供閉包函數訪問。
注意:
由定義可以知道,閉包函數肯定是定義在函數中,才可能有上級的函數作用域可以訪問,否則上級作用域就是全局作用域。全局作用域中的變量本身就一直在內存中,所以訪問全局作用域中變量的函數不能稱為閉包。
var name = "global"; function func1() { var name1 = "func1"; console.log(name); console.log(name); function func2() { console.log(name); var name2 = "func2"; function func3() { console.log(name2); } func3(); } func2(); } func1();
上面代碼中,func3為閉包函數,因為它訪問了上級函數作用域中的變量name2,func2不能稱為閉包函數,因為它們訪問的是全局作用域中的變量name。
2 常見的閉包場景 2.1 維持變量的閉包var person = (function(){ var _name = "yangyiliang"; var _age = 18; return { getName: function () { return _name; }, getAge: function () { return _age; }, addAge: function (num) { return _age += num; }, reduceAge: function (num) { return _age -= num; } } })(); console.log(person.addAge(5)); // 23 console.log(person.reduceAge(3)); //20
上面的代碼中,首先外層包裹了一個匿名立即執行函數,創造了一個上級函數作用域,getName和getAge方法都是在其內部,并且訪問了上級函數作用域中的變量,所以是閉包,所當匿名函數執行完畢后,本該銷毀的執行上下文,卻因為閉包函數而保留了作用域中的_name和 _age變量, 通過addAge 和reduceAge的結果發現,兩個閉包共用保留的作用域。
2.2 維持參數的閉包function makeSizer(size) { return function() { document.body.style.fontSize = size + "px"; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16); document.getElementById("size-12").onclick = size12; document.getElementById("size-14").onclick = size14; document.getElementById("size-16").onclick = size16;
上面的代碼中,makerSizer函數的返回值即為閉包函數,閉包函數訪問上級函數作用域中的參數。
2.3 循環創建閉包常見錯誤
function bind() { var arr = document.getElementsByTagName("p"); for(var i = 0; i < arr.length;i++){ arr[i].onclick = function(){ alert(i); } } } bind();
上面的代碼中,假設arr的length為5,想要實現的功能是點擊5個P標簽分別alert 0,1,2,3,4。但是事實上得到的結果卻是都alert 5。
造成這種結果的原因就是綁定的多個onclick函數是閉包函數,他們共同使用保留的上級函數作用域中的變量 i 。 for循環執行結束后 i 的值即為5。
要想解決這種錯誤,就讓這些閉包保存不同的上級作用域即可。
function bind() { var arr = document.getElementsByTagName("p"); for(var i = 0; i < arr.length;i++){ (function (i) { arr[i].onclick = function(){ alert(i); } })(i); } } bind(); 或者 function bind() { var arr = document.getElementsByTagName("p"); for(var i = 0; i < arr.length;i++){ arr[i].onclick = (function(i){ return function () { alert(i); } })(i); } } bind();
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88064.html
摘要:但是我們知道中是沒有重載的為什么沒重載不是的特性也會有的嗎,因為后面定義的函數會覆蓋前面的同名函數,但是重載那么好用,我們想在實現函數重載該怎么辦呢今天就來給大家講講在里面實現函數重載的兩個思路。這就是閉包的核心作用。 大家都知道,所謂重載,就是一組相同的函數名,有不同個數的參數,在使用時調用一個函數名,傳入不同參數,根據你的參數個數,來決定使用不同的函數!重載這個在JAVA這些經典的...
摘要:插件開發前端掘金作者原文地址譯者插件是為應用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內優雅的實現文件分片斷點續傳。 Vue.js 插件開發 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應用添加全局功能的一種強大而且簡單的方式。插....
摘要:使用閉包遇到的陷阱一陷阱在類的原型對象中添加特權方法首先定義一個類,該類中有一個私有變量定義個特權方法來訪問修改私有變量然后我們對類進行測試到目前為止,類正常工作。 使用JavaScript閉包遇到的陷阱(一) 陷阱:在類的原型對象中添加特權方法 首先定義一個Page類,該類中有一個私有變量dom: function Page(){ var dom; } 定義2個特權方法來訪問...
摘要:什么時候需要用到單例模式呢其實單例模式在日常開發中的使用非常的廣泛,例如各種浮窗像登錄浮窗等,無論我們點擊多少次,都是同一個浮窗,浮窗從始至終只創建了一次。這種場景就十分適合運用單例模式。 單例模式 什么是單例模式? 單例模式的定義:一個類僅有一個實例,并且可以在全局訪問。什么時候需要用到單例模式呢?其實單例模式在日常開發中的使用非常的廣泛,例如各種浮窗、像登錄浮窗等,無論我們點擊多少...
閱讀 1035·2021-11-22 13:53
閱讀 1590·2021-11-17 09:33
閱讀 2390·2021-10-14 09:43
閱讀 2850·2021-09-01 11:41
閱讀 2271·2021-09-01 10:44
閱讀 2911·2021-08-31 09:39
閱讀 1448·2019-08-30 15:44
閱讀 1860·2019-08-30 13:02