193 lines
4.5 KiB
Markdown
193 lines
4.5 KiB
Markdown
|
# 作用域
|
|||
|
### 练习
|
|||
|
```
|
|||
|
var color = "blue";
|
|||
|
|
|||
|
function changeColor() {
|
|||
|
let anotherColor = "red";
|
|||
|
|
|||
|
function swapColors() {
|
|||
|
let tempColor = anotherColor;
|
|||
|
anotherColor = color;
|
|||
|
color = tempColor;
|
|||
|
|
|||
|
// 这里可以访问color、anotherColor和tempColor
|
|||
|
}
|
|||
|
|
|||
|
// 这里可以访问color和anotherColor,但访问不到tempColor
|
|||
|
swapColors();
|
|||
|
}
|
|||
|
|
|||
|
// 这里只能访问color
|
|||
|
changeColor();
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
分析上面的作用域链:
|
|||
|
<details>
|
|||
|
<summary>展开查看</summary>
|
|||
|
|
|||
|
* window
|
|||
|
* color
|
|||
|
* changecolor()
|
|||
|
* anothercolor
|
|||
|
* swapcolors()
|
|||
|
* tempcolor
|
|||
|
</details>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### 垃圾回收机制
|
|||
|
优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。如果数据不再必要,那么把它设置为null ,从而释放其引用。这也可以叫作解除引用 。这个建议最适合全局变量和全局对象的属性。
|
|||
|
局部变量在超出作用域后会被自动解除引用
|
|||
|
即 全局变量(GO) 不会被销毁,但是局部变量(AO)函数执行完后会被销毁
|
|||
|
也可以手动销毁变量,即赋值为null
|
|||
|
|
|||
|
如下面的例子所示:
|
|||
|
```
|
|||
|
function createPerson(name){
|
|||
|
let localPerson = new Object();
|
|||
|
localPerson.name = name;
|
|||
|
return localPerson;
|
|||
|
}
|
|||
|
|
|||
|
let globalPerson = createPerson("Nicholas");
|
|||
|
|
|||
|
// 解除globalPerson对值的引用
|
|||
|
|
|||
|
//globalPerson = null;
|
|||
|
|
|||
|
```
|
|||
|
解析:
|
|||
|
<details>
|
|||
|
<summary>展开查看</summary>
|
|||
|
在上面的代码中,变量globalPerson 保存着createPerson() 函数调用返回的值。在createPerson() 内部,localPerson 创建了一个对象并给它添加了一个name 属性。然后,localPerson 作为函数值被返回,并被赋值给globalPerson 。localPerson 在createPerson() 执行完成超出上下文后会自动被解除引用,不需要显式处理。但globalPerson 是一个全局变量,应该在不再需要时手动解除其引用,最后一行就是这么做的。
|
|||
|
|
|||
|
不过要注意,解除对一个值的引用并不会自动导致相关内存被回收。解除引用的关键在于确保相关的值已经不在上下文里了,因此它在下次垃圾回收时会被回收。
|
|||
|
</details>
|
|||
|
|
|||
|
### 闭包
|
|||
|
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
function a() {
|
|||
|
var x = 0;
|
|||
|
return function(y) {
|
|||
|
x = x + y;
|
|||
|
// return x;
|
|||
|
console.log(x);
|
|||
|
}
|
|||
|
}
|
|||
|
var b = a();
|
|||
|
b(1); //1
|
|||
|
b(1); //2
|
|||
|
```
|
|||
|
练习1:
|
|||
|
```
|
|||
|
function fn() {
|
|||
|
var max = 10;
|
|||
|
return function bar(x) {
|
|||
|
if (x > max) {
|
|||
|
console.log(x);
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
var f1 = fn();
|
|||
|
f1(15);
|
|||
|
|
|||
|
```
|
|||
|
练习2
|
|||
|
```
|
|||
|
function init() {
|
|||
|
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
|
|||
|
function displayName() { // displayName() 是内部函数,一个闭包
|
|||
|
alert(name); // 使用了父函数中声明的变量
|
|||
|
}
|
|||
|
displayName();
|
|||
|
}
|
|||
|
init();
|
|||
|
|
|||
|
```
|
|||
|
<details>
|
|||
|
init() 创建了一个局部变量 name 和一个名为 displayName() 的函数。displayName() 是定义在 init() 里的内部函数,并且仅在 init() 函数体内可用。请注意,displayName() 没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 displayName() 可以使用父函数 init() 中声明的变量 name 。
|
|||
|
|
|||
|
</details>
|
|||
|
hrefs:
|
|||
|
https://blog.csdn.net/weixin_43586120/article/details/89456183
|
|||
|
|
|||
|
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
(function() {
|
|||
|
var m = 0;
|
|||
|
function getM() { return m; }
|
|||
|
function seta(val) { m = val; }
|
|||
|
window.g = getM;
|
|||
|
window.f = seta;
|
|||
|
})();
|
|||
|
f(100);
|
|||
|
console.info(g());
|
|||
|
|
|||
|
```
|
|||
|
<hr/>
|
|||
|
|
|||
|
```
|
|||
|
function fn(){
|
|||
|
var arr = [];
|
|||
|
for(var i = 0;i < 5;i ++){
|
|||
|
arr[i] = (function(i){
|
|||
|
return function (){
|
|||
|
return i;
|
|||
|
};
|
|||
|
})(i);
|
|||
|
}
|
|||
|
return arr;
|
|||
|
}
|
|||
|
// 立即执行函数 每调用一次完成后就自动销毁
|
|||
|
|
|||
|
var list = fn();
|
|||
|
for(var i = 0,len = list.length;i < len ; i ++){
|
|||
|
console.log(list[i]());
|
|||
|
} //0 1 2 3 4
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
function fn(){
|
|||
|
var arr = [];
|
|||
|
for(var i = 0;i < 5;i ++){
|
|||
|
arr[i] = function(){
|
|||
|
return i;
|
|||
|
}
|
|||
|
}
|
|||
|
return arr;
|
|||
|
}
|
|||
|
var list = fn();
|
|||
|
for(var i = 0,len = list.length;i < len ; i ++){
|
|||
|
console.log(list[i]());
|
|||
|
} //5 5 5 5 5
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
var lis = document.getElementsByTagName("li");
|
|||
|
for(var i=0;i<lis.length;i++){
|
|||
|
(function(i){
|
|||
|
lis[i].onclick = function(){
|
|||
|
console.log(i);
|
|||
|
};
|
|||
|
})(i); //事件处理函数中闭包的写法
|
|||
|
}
|
|||
|
|
|||
|
```
|
|||
|
```
|
|||
|
|
|||
|
var li = document.getElementsByTagName( "li" );
|
|||
|
for ( var i = 0; i < li.length; i++) {
|
|||
|
li[i].addEventListener( "click" , function () {
|
|||
|
console.log(i);
|
|||
|
})
|
|||
|
}
|
|||
|
```
|