##### 9 閉包 我們都知道,函數里是可以訪問函數外的全局變數,而函數外不能訪問函數內的局部變數,如下: ```js // 函數外定義a,在函數內可以訪問 var a = "測試"; function fn() { console.log(a); } fn(); ``` 執行結果: ![imag ...
9 閉包
我們都知道,函數里是可以訪問函數外的全局變數,而函數外不能訪問函數內的局部變數,如下:
// 函數外定義a,在函數內可以訪問
var a = "測試";
function fn() {
console.log(a);
}
fn();
執行結果:
// 函數內定義a,在函數外訪問不到
function fn() {
var a = "測試";
}
console.log(a);
執行結果:
之所以出現這樣的情況,就是因為函數內定義的變數為局部變數,函數外定義的變數為全局變數(不同於windows)。在函數內部可以訪問到全局變數,而在函數外部是無法訪問到函數內部的局部變數的。
接下來,我們先看一段代碼:
let name = "水木年華";
function fn() {
name = "張傑";
}
fn();
console.log(name); // 張傑
由此可知,在函數內部想要修改外部的變數是十分容易的一件事. 尤其是全局變數. 這是非常危險的. 試想, 我寫了一個函數. 要用到name, 結果被別人寫的某個函數給修改掉了. 多難受.
接下來,我們來看一個例子:
比如目前有一個項目,需要兩個人一起開發,分別是小明.js和小芳.js
小明.js:
var key = '小明的key';
function jiami() {
console.log("小明使用", key, "來加密");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="小明.js"></script>
<script>
fn(); // 小明使用 小明的key 來加密
</script>
</head>
<body>
</body>
</html>
小芳.js:
var key = '小芳的key';
function jiami() {
console.log("小芳使用", key, "來加密");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="小芳.js"></script>
<script>
fn(); // 小芳使用 小芳的key 來加密
</script>
</head>
<body>
</body>
</html>
兩個人的代碼在各自執行的時候都沒有問題,但是當把兩個js文件同時在一個html文件中引用時,就會出現變數值被修改的問題:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="小明.js"></script>
<script src="小芳.js"></script>
<script>
/*兩個人都叫jiami,怎樣區分調用的是誰的方法?*/
jiami();
jiami();
</script>
</head>
<body>
</body>
</html>
執行結果:
很明顯,兩個腳本在同一個html文件中被引用時,變數名和函數名重覆,是不是覺得讓各自的變數名和函數名不一致就可以了?如下:
小明.js:
var xiaoming_key = '小明的key';
function xiaoming_jiami() {
console.log("小明使用", xiaoming_key, "來加密");
}
小芳.js:
var xiaofang_key = '小芳的key';
function xiaofang_jiami() {
console.log("小芳使用", xiaofang_key, "來加密");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="小明.js"></script>
<script src="小芳.js"></script>
<script>
xiaoming_jiami();
xiaofang_jiami();
</script>
</head>
<body>
</body>
</html>
執行結果:
這樣搞確實可以實現了哈。但是問題來了,這個項目用到的變數和函數少,js腳本也少。而在真正的羡慕中,一個html文件可能引用幾十個js文件,每個js文件又有成百上千的變數或者函數,這樣的話我在一個一個的去修改變數名和函數名?不太現實,況且在html文件中引用的時候也不方便。那麼現在這種情況,我們就可以嘗試一下閉包了,比如小明和小芳之前的js代碼是在一個函數中的:
小明.js:
function ming() {
/*
在外面在套一層函數結構,使key變數和jiami函數的作用範圍由之前的全局變為ming函數的局部作用域
*/
var key = '小明的key';
function jiami() {
console.log("小明使用", key, "來加密");
}
return jiami; // 最後在返回函數名供外部使用
}
ming_jiami = ming(); // 這裡的ming_jiami要與小芳的進行區分
小芳.js:
function fang() {
var key = '小芳的key';
function jiami() {
console.log("小芳使用", key, "來加密");
}
return jiami;
}
fang_jiami = fang(); // 小芳這裡的fang_jiami也要與小明區分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="小明.js"></script>
<script src="小芳.js"></script>
<script>
ming_jiami(); // 小明
fang_jiami(); // 小芳
</script>
</head>
<body>
</body>
</html>
執行結果:
現在執行結果確實沒有問題了,兩個人的腳本都可以正常使用了。但是兩個人外層的函數還是有可能是一樣的,我們再用之前學過的匿名函數再優化一下:
小明.js:
ming_jiami = (function(){
var key = '小明的key';
function jiami() {
console.log("小芳使用", key, "來加密");
}
return jiami;
})();
小芳.js:
fang_jiami = (function () {
var key = '小芳的key';
function jiami() {
console.log("小芳使用", key, "來加密");
}
return jiami;
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="小明.js"></script>
<script src="小芳.js"></script>
<script>
ming_jiami(); // 小明
fang_jiami(); // 小芳
</script>
</head>
<body>
</body>
</html>
執行結果:
OK,至此,就完美的優化了這個代碼。在最外面接收內部返回的參數的變數兩個人重覆的的幾率就已經非常低了。何為閉包? 上面這個就是閉包。相信你百度一下就會知道,什麼內層函數使用外層函數變數。什麼讓一個變數常駐記憶體,等等。其實你細看,它之所以稱之為閉包~,它是一個封閉的環境,在內部,自己和自己玩兒,避免了對該模塊內部的衝擊和改動,避免的變數之間的衝突問題。
閉包的特點:
- 內層函數對外層函數變數的使用
- 會讓變數常駐與記憶體
這倆玩意就不解釋了,和python的閉包是一個意思。不懂沒關係,能看懂他的執行過程就好。
本文來自博客園,作者:生而自由愛而無畏,轉載請註明原文鏈接:https://www.cnblogs.com/zczhaod/p/17645458.html