JS-词法作用域 作用域链

## 词法作用域

概念:所谓的词法作用域,就是代码在编写过程就体现出来的作用范围。代码一旦写好,不用执行, 作用范围就已经确定好了,这个就是所谓的词法作用域。

## 词法作用域的规则:

  1,函数允许访问函数外的数据              (也有就近原则)

  2,整个代码结构中只有函数可以限定作用域

  3,作用规则首先使用提升规则分析

  4,如果当前规则有名字了,则不考虑外面的名字

规则1对应例子:

*******************************************

   var num = 123;

  function foo() {

         console.log(num);

  }

  foo(); // 123

*******************************************

规则2,3,4对应例子:

***************************************************************************************************************************

  var num =123;                                       //1,首先提升num,foo 预解析                                         (规则3)

  function foo() {                                      //2,给 num 赋值123;

       var num = 456;                                  (函数内部代码执行过程)

        function func() {                             //3,函数调用,再预解析 函数内的num(覆盖了外面的num)func

                console.log(num);                  //4,赋值num=456

       }                                                      //5,执行调用func() ;

  func();                                                   //6,打印最近的num,打印456;(console.log(num);)  (规则4)

  }

foo(); //456

console.log(num);  //123                        //7,打印函数外部的num=123                                            (规则2)

******************************************************************************************************************************

### 作用域链

          概念:只有函数可以制造作用域结构。那么只要有代码,至少有一个作用域,即全局作用域,凡是代码中有函数,那种这个函数就构成了一个作用域链。如果函数中还有函                           数,那么作用域中又有一个作用域,将这样的所有作用域列出来,可以有一个结构:函数内指向函数外的链式结构。

例子:

执行结果1:789

执行结果2:123

#### 绘制作用域链

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>绘制作用域链 绘制</title>
</head>
<body>
    <script type="text/javascript">
        
        function f1() {
            var num = 123;
            function f2() {
                console.log(num);
            }
            f2();            
        }
        var num =456;
        f1();//123
        
    </script>

</body>
</html>

***************************************************************************************************************

### 闭包

目的:想办法间接地获得函数内部数据的使用权。

特点:

具有私有访问数据的 函数的。只有函数内部可以访问的,或者对象的方法。

例如 

function person () {
    this.age = 18;
}
//这样的可以被函数外的实例对象所改变。此数据是公开的。

***********************************************************************

一般闭包的使用模式:

1,写一个函数,函数内部定义一个新函数,返回新数据,用新函数获取函数内的数据。

2,写一个函数,函数内定义一个对象,对象中捆绑多个函数(方法),返回对象,利用对象的方法访问函数内的数据。

************************************************************************

1,闭包不允许外部访问。

function foo() {
     var num =123;
     return num;
}
var res = foo();
console.log(res);//123

console.log(foo());//123
console.log(foo());//123

这里每调用一次,创建一次。但是数据不再是相同的一个数据。每调用一次就有一个新的 num = 123 出来了。

2,在函数内的数据,不能直接在函数外被访问,那么在函数内再定义一个函数,那么在这个函数内部中可以被访问        function foo() {

        function foo() {  
var num =Math.random(); function fun() { return num; } return fun; } // 在函数内的数据,不能直接在函数外被访问,那么在函数内再定义一个函数,那么在这个函数内部中可以被访问的。 //整个过程只被调用一次 // 此时返回的是一个函数。访问的是同一个 num
//函数科粒化(高阶函数)调用:foo()();
var f = foo(); var res1 = f(); var res2 = f(); console.log(res1);// 0.15312875316801855 console.log(res2);// 0.15312875316801855
 说明:  // 0级链无法访问一级链里面的数据,所以通过0级链操作二级链,来访问1级链里面的数据

#闭包的性能问题?

函数执行需要内存,那么函数中定义的变量,会在函数执行结束后自动回收,凡是因为闭包结构,被引出的数据,如果还有变量引用这些数据的话,那么这些数据就不会被回收。

闭包比较占内存。

因此在使用闭包的时候如果不使用某些数据了,一定要赋值一个null;

var f = (function () {
     var num = 11;
     return function() {
           renturn num;
     };
})();
//f 引用着函数,函数引用着变量num
//因此在不使用该数据时,最好写上
f = null

 注:个人学习笔记

原文地址:https://www.cnblogs.com/xixiaijunjun/p/10085078.html