作用域链、闭包以及this的使用

执行环境与作用域:

每个执行环境都有与之相关联的变量对象,如果这个环境是函数,则将其活动对象(activation object)作为变量对象环境中定义的所有变量和函数都保存在这个变量中,活动对象在最开始只包含一个arguments对象。

js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。

作用域污染:

只要函数内定义了一个局部变量,函数在解析时都会将这个变量“提前声明”

 var scope = "global";
     
 function fn(){
         console.log(scope);//result:undefined
         var scope = "local";
         console.log(scope);//result:local;
 }
 fn();

在js中可以随时定义全局变量,但是全局变量会削弱程序的灵活性,增大了模块之间的耦合性。

在多人协作时,如果定义过多的全局变量,有可能造成全局变量的冲突,也就是全局变量的污染,有两种解决方法:

(1)定义全局变量命名空间

只创建一个全局变量,并定义该变量为当前容器,把其他全局变量写到该命名空间下。

var myInfo={
    name:'chengxi',
    like:'football',
    likeDo:function(){
        alert(this.like);
    }
}

(2)利用匿名函数将脚本包裹起来

(function(){
    var exp={};
    var name='aa';
    exp.method=function(){
        return name;
    };
    window.ex=exp;
})();
console.log(ex.method());//aa

作用域:

在js中作用域分为全局作用域和函数作用域。 

作用域链:

当代码在一个环境中执行时,会创建一个作用域链,其用途是保证对执行环境有权访问的所有变量和函数的有序访问。

比如查找一个变量,首先在当前作用域中查找,如果没有,就会向上级作用域去查,直到查到全局作用域,这么一个查找的过程形成的链条就叫做作用域链。

  作用域链的前端,始终都是当前执行的代码所在环境的变量对象,如果这个环境是函数,则将其活动对象作为变量对象,活动对象在最开始时只包含一个变量,即arguments对象。作用域链的下一变量对象来自于包含(外部)环境,全局执行环境的变量对象始终都是作用域链中的最后一个对象。


<script>
      function outer(){
         var scope = "outer";
         function inner(){
            return scope;
         }
         return inner;
      }
      var fn = outer();
      fn();
   </script>
 

一般来说,当某个环境中的所有代码执行完毕后,该环境被销毁(弹出环境栈),保存在其中的所有变量和函数也随之销毁(全局执行环境变量直到应用程序退出,如网页关闭才会被销毁)


但是像上面那种有内部函数的又有所不同,当outer()函数执行结束,执行环境被销毁,但是其关联的活动对象并没有随之销毁,而是一直存在于内存中,因为该活动对象被其内部函数的作用域链所引用。

像上面这种内部函数的作用域链仍然保持着对父函数活动对象的引用,就是闭包(closure)

闭包有两个作用:
第一个就是可以读取自身函数外部的变量(沿着作用域链寻找)
第二个就是让这些外部变量始终保存在内存中 

//闭包
function outer(){
    var result = new Array();
    for(var i = 0; i < 2; i++){
          result[i] = function(num){
                return function(){
                      return num;
                }           
        }(i)
   }
return result;
}
var fn = outer();
console.log(fn[0]());//result:0
console.log(fn[1]());//result:1

   如果没使用以上方式,i是贯穿整个作用于的,并不是给每个result分配一个i,所以用立即执行函数创建一个独立的作用域即可。

  我们没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将将立即执行该匿名函数的结果赋值给数组。这里的匿名函数有一个参数num,也就是最终函数要返回的值。在调用每个匿名函数时,传入变量i的值,由于函数参数是按值传递的,所以会将变量i的值赋值给参数num,而这个匿名函数内部,又创建并返回一个访问num的闭包,这样数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的值了。

原文地址:https://www.cnblogs.com/xiaoan0705/p/9390732.html