# 作用域
### 练习
```
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);
   })
}
```