#看了一下影片中對於閉包作用的解釋我還是表示不明白,比如說截圖中這段程式碼完全可以在cmp函數中加一個passline參數來實現,沒必要使用閉包。
誰能舉個更好的例子來說明閉包的作用啊?
学习是最好的投资!
延長局部變數的生命週期,封裝私有變數
2. 延续局部变量的寿命 img 对象经常用于进行数据上报,如下所示: var report = function( src ){ var img = new Image(); img.src = src; }; report( 'http://xxx.com/getUserInfo' ); 但是通过查询后台的记录我们得知,因为一些低版本浏览器的实现存在 bug,在这些浏览器 下使用 report 函数进行数据上报会丢失 30%左右的数据,也就是说, report 函数并不是每一次 都成功发起了 HTTP 请求。丢失数据的原因是 img 是 report 函数中的局部变量,当 report 函数的 调用结束后, img 局部变量随即被销毁,而此时或许还没来得及发出 HTTP 请求,所以此次请求 就会丢失掉。 现在我们把 img 变量用闭包封闭起来,便能解决请求丢失的问题: var report = (function(){ var imgs = []; return function( src ){ var img = new Image(); imgs.push( img ); img.src = src; } })();
保存變數 大部分時候我是用它來取代全域變數 避免造成變數污染
閉包解決的問題:基於JS的詞法作用域規則,其存取是一直向上尋找作用域,直到全域作用域。而想直接訪問某個作用域可透過閉包解決。
JS
function foo(){ var a = 1; function bar(){ console.log(a); } return bar; } var baz = foo(); baz();
bar詞法作用域可以存取foo內部作用域,foo執行後回傳bar,最後賦值給baz,可以取得並存取foo內部作用域,只是標識符不同而已。 bar词法作用域可以访问foo内部作用域,foo执行后返回bar,最后赋值给baz,可以获取并访问foo内部作用域,只是标识符不同而已。该代码就使用了闭包,可以说写JS該程式碼就使用了閉包,可以說寫程式碼處處可見閉包,使用閉包還有一個好處就是引用的作用域不會被垃圾回收處理,當然不合理的使用會耗內存
bar
foo
baz
閉包用來增加變數(能訪問某作用域,自然能加變數)或延長其生命週期
for (var i = 0; i < 5; i++){ setTimeout(function(){ console.log(i)},i * 1000) } for (var i = 0; i < 5; i++){ (function (i) { setTimeout(function(){ console.log(i)},i * 1000) })(i) }
i
當然最能體現閉包思想的是模組,返回一個方法,該方法就相當引入了一個作用域。
閉包:就是一個取得並存取某個作用域,可在外存取或自身內部存取。
最大的兩個作用
讀取函數內部變數
讓變數值始終保持在記憶體
第一個不贅述,看第二個,舉例
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
result其實就是閉包f2函數。它總共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數f1中的局部變數n一直保存在記憶體中,並沒有在f1呼叫後被自動清除。 為什麼會這樣呢?原因就在於f1是f2的父函數,而f2被賦給了一個全域變量,這導致f2始終在記憶體中,而f2的存在依賴f1,因此f1也始終在記憶體中,不會在呼叫結束後,被垃圾回收機制(garbage collection)回收。 這段程式碼中另一個值得注意的地方,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關鍵字,因此nAdd是一個全域變量,而不是局部變數。其次,nAdd的值是匿名函數(anonymous function),而這個匿名函數本身也是閉包,所以nAdd相當於一個setter,可以在函數外部對函數內部的局部變數進行操作
管理私有變數和私有方法,將對變數(狀態)的變化封裝在安全的環境中
將程式碼封裝成一個閉包形式,等待時機成熟的時候再使用,例如實現柯里化和反柯里化
需要注意的:
由於閉包內的部分資源無法自動釋放,容易造成記憶體外洩 解決方法是,在退出函數之前,將不使用的局部變數全部刪除。
閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變數的值。
如果我說, set_passLine 其實就是兩個參數的函數,你能接受嗎?
set_passLine
def set_passLine(passline)(val): # 虽然这不符合语法 pass
這個和函數
def set_passLine(passline,val): pass
在功能上是等價的,但前者,不必一次給出所有參數來呼叫。
另外,第一種寫法可以實現和類別一樣的功能:
def set_passLine(passline): def cmp(val): pass def resetPassLine(newPassline): passline=newPassline pass return (cmp,resetPassLine)
雖然這些都是相同功能的不同實作。但是人們越來越發現函數式程式設計比其他的方式更好,更好的意思是指在程式碼量上更好,更清晰(但是對程式設計師的要求越來越高)。
給個連結吧,但是是我用 js 寫的:http://zonxin.github.io/post/...
P.S.物件導向的程式就是把,所有的「物體」看為對象,程式設計就是,使用物件模擬「物體」的行為,也就是模擬某個「世界」的運作。 而函數式編程,只關心「物體」的初始狀態和「物體」經過函數之後的最終狀態,而不必關心其中的過程,編程就是處理這些函數的複合。
我一直是這麼理解的:保護內部變量,透過暴漏API進行操作。
var name="meimei" function Private(){ var name = "leilei"; return { getName:function(){ console.log(name) }, setName:function(val){ name = val; } } } var private = Private(); private.getName()//"leilei" private.setName("xiaoming") private.getName()//"xiaoming" name//"meimei" //通过暴漏API来操作内部变量。 jquery: (function(){ ... window.$=window.jquery=window.jQuery=... }) //一个匿名自执行函数通过window暴漏jquery,内部变量不会受到其他全局变量的污染,只能通过$的API进行操作。
以上是個人理解
避免變數污染,但如果是在ES6中,用let和const就可以解決這個問題了
初級程度來看只知道1、可以存取到局部變數2、可以一直儲存在記憶體中
所以使用頻率不宜過高,會造成記憶體洩漏
回答我印象深刻的 偏函数
偏函数
function logger(logType){ return console.log.bind(console, logType); } var info = logger('[INFO]'); var error = logger('[ERROR]'); info('this is an info'); // => // [INFO] this is an info error('this is an error'); // => // [ERROR] this is an error
延長局部變數的生命週期,封裝私有變數
保存變數 大部分時候我是用它來取代全域變數 避免造成變數污染
閉包解決的問題:基於
JS
的詞法作用域規則,其存取是一直向上尋找作用域,直到全域作用域。而想直接訪問某個作用域可透過閉包解決。
。bar
詞法作用域可以存取foo
內部作用域,foo
執行後回傳bar
,最後賦值給baz,可以取得並存取foo
內部作用域,只是標識符不同而已。bar
词法作用域可以访问foo
内部作用域,foo
执行后返回bar
,最后赋值给baz
,可以获取并访问foo
内部作用域,只是标识符不同而已。该代码就使用了闭包,可以说写
JS
該程式碼就使用了閉包,可以說寫程式碼處處可見閉包,使用閉包還有一個好處就是引用的作用域不會被垃圾回收處理,當然不合理的使用會耗內存閉包用來增加變數(能訪問某作用域,自然能加變數)或延長其生命週期
(作用域被引用,自然會延長)i
变量(变量和函数声明都提升了)。第二个循环是定义了几个立即执行函数,又传递了
i
值,故每个i
第一個循環是聲明了幾個函數,共享全域值都有自己的作用域。 這個是一個比較好的例子,閉包+循環,只是這個比較特別,閉包訪問自身的作用域。
當然最能體現閉包思想的是模組,返回一個方法,該方法就相當引入了一個作用域。
閉包:就是一個取得並存取某個作用域,可在外存取或自身內部存取。
🎜最大的兩個作用
讀取函數內部變數
讓變數值始終保持在記憶體
第一個不贅述,看第二個,舉例
result其實就是閉包f2函數。它總共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數f1中的局部變數n一直保存在記憶體中,並沒有在f1呼叫後被自動清除。
為什麼會這樣呢?原因就在於f1是f2的父函數,而f2被賦給了一個全域變量,這導致f2始終在記憶體中,而f2的存在依賴f1,因此f1也始終在記憶體中,不會在呼叫結束後,被垃圾回收機制(garbage collection)回收。
這段程式碼中另一個值得注意的地方,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關鍵字,因此nAdd是一個全域變量,而不是局部變數。其次,nAdd的值是匿名函數(anonymous function),而這個匿名函數本身也是閉包,所以nAdd相當於一個setter,可以在函數外部對函數內部的局部變數進行操作
管理私有變數和私有方法,將對變數(狀態)的變化封裝在安全的環境中
將程式碼封裝成一個閉包形式,等待時機成熟的時候再使用,例如實現柯里化和反柯里化
需要注意的:
由於閉包內的部分資源無法自動釋放,容易造成記憶體外洩 解決方法是,在退出函數之前,將不使用的局部變數全部刪除。
閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變數的值。
如果我說,
set_passLine
其實就是兩個參數的函數,你能接受嗎?這個和函數
在功能上是等價的,但前者,不必一次給出所有參數來呼叫。
另外,第一種寫法可以實現和類別一樣的功能:
雖然這些都是相同功能的不同實作。但是人們越來越發現函數式程式設計比其他的方式更好,更好的意思是指在程式碼量上更好,更清晰(但是對程式設計師的要求越來越高)。
給個連結吧,但是是我用 js 寫的:http://zonxin.github.io/post/...
P.S.
物件導向的程式就是把,所有的「物體」看為對象,程式設計就是,使用物件模擬「物體」的行為,也就是模擬某個「世界」的運作。
而函數式編程,只關心「物體」的初始狀態和「物體」經過函數之後的最終狀態,而不必關心其中的過程,編程就是處理這些函數的複合。
我一直是這麼理解的:保護內部變量,透過暴漏API進行操作。
以上是個人理解
避免變數污染,但如果是在ES6中,用let和const就可以解決這個問題了
初級程度來看
只知道1、可以存取到局部變數
2、可以一直儲存在記憶體中
所以使用頻率不宜過高,會造成記憶體洩漏
回答我印象深刻的
偏函数