閉包能夠理解爲定義在一個函數內部的函數,
函數A內部定義了函數B,
函數B有訪問函數A內部變量的權力;
閉包是函數和子函數之間的橋樑;
舉個例子:javascript
let func = function() { let firstName = 'allen' let innerFunc = function(lastName) { console.log(`hello ${firstName}-${lastName}`) } innerFunc('Liu'); } func();
輸出:hello allen-Liu
若是父函數已經退出(返回),那麼閉包效用也仍是在的
接着看這個例子:java
let func = function() { let firstName = 'allen' let innerFunc = function(lastName) { console.log(`hello ${firstName}-${lastName}`) } return innerFunc } let innerFunc = func(); innerFunc('Liu'); innerFunc('Zhang');
輸出:瀏覽器
hello allen-Liu hello allen-Zhang
可見,js的執行引擎不但記住了這個內部函數;還記住了這個內部函數所在的環境
就算讓這個內部函數引用它的父函數的入參,它也能引用的到!
並且,不但能夠引用環境變量,還能夠修改環境變量;
再看個例子:閉包
let func = function() { let name = 'allen' let setName = function() { name = 'kivi' } let getName = function() { console.log(name); } return { setName, getName } } let obj = func(); obj.getName(); obj.setName(); obj.getName();
輸出結果爲:
allen
kivi函數
假設咱們知道一個指向某方法的變量,
咱們能夠調用toString方法看這個方法的代碼:this
let func = function(x) {console.log(x)}; func.toString();
運行輸出:spa
"function(x) {console.log(x)}"
注意輸出的是一個字符串,
這是一個很是強悍的功能,你獲得這個字符串以後,能夠隨時eval它,執行方法的邏輯
遺憾的是,你不能信賴toString方法,
由於有時候你拿不到想要的方法體字符串;
舉個例子code
let func = (function(x) {console.log(this.x)}).bind({x:123}); func();
輸出:123
這是正常的,
由於:bind方法產生了一個新的函數,而且給產生的這個新函數綁定了this,在這裏this就是{x:123}
若是調用ip
func.toString();
輸出結果就是:開發
"function () { [native code] }"
由於ECMAScript對toString方法並無任何約束,瀏覽器開發廠商就無所顧忌了 js裏的bind方法頗有多是C++實現的,因此你看到了[native code]