作用域链和闭包

作用域链

作用域就是变量和函数的可访问范围,他包含全局变量和局部变量~我们知道的是JavaScript在执行语句的时候是有预解析的。

var a=3; //全局变量
    function fn(b){ //局部变量
        c=2; //全局变量
        var d=5; //局部变量
        function subFn(){
            var e=d; //父函数的局部变量对子函数可见
            for(var i=0;i<3;i++){
                console.write(i);
            }
            alert(i);//3, 在for循环内声明,循环外function内仍然可见,没有块作用域
        }
    }
    alert(c); //在function内声明但不带var修饰,仍然是全局变量

javascript 是没有块级作用域的,但是他有预解析

    console.log(a); //undefined
    var a = 3;
    console.log(a); //3
    console.log(b); //Uncaught ReferenceError: b is not defined

引言——执行环境

执行环境(execution context)定义了变量或函数有权访问的其它数据,决定了它们的各自行为。每个执行环境都有一个与之关联的变量对象(variable object, VO)
执行环境中定义的所有变量和函数都会保存在这个对象中,解析器在处理数据的时候就会访问这个内部对象。
在这里插入图片描述
全局执行环境是最外层的一个执行环境,在web浏览器中全局执行环境是window对象,因此所有全局变量和函数都是作为window对象的属性和放大创建的。
每个函数都有自己的执行环境,当执行流进入一个函数的时候,函数的环境会被推入一个函数栈中,而在函数执行完毕后执行环境出栈并被销毁,保存在其中的所有变量和函数定义随之销毁,控制权返回到之前的执行环境中,全局的执行环境在应用程序退出(浏览器关闭)才会被销毁。

例如上面的图片~当我执行一次Fn的时候,就会产生一个需要执行Fn一次的任务,这个任务产生一个Fn的执行环境,里面有变量b = 2,c = 3; 当这个任务被执行完,这些变量就会一起被销毁

现在来说说作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain,不简称sc)来保证对执行环境有权访问的变量和函数的有序访问。作用域第一个对象始终是当前执行代码所在环境的变量对象(VO)

function a(x,y){
    var b = x + y;
    return b;
}
// 在这里函数 a 的执行环境就是一个包含在 window 作用域下的一个分支

再来看看这段代码:

	function a(x,y){
	    var b = x + y;
	    function c() {
			var d = 4;
		}
	    return b;
	 }
	var total = a(5,10);

在这里插入图片描述

再来看看闭包

只要存在调用内部函数的可能,JavaScript就需要保留被引用的函数。而且JavaScript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,JavaScript的垃圾收集器才能释放相应的内存空间。

	for(var i = 0;i < data.length; i++){
	    data[i].onclick = function (){
	          alert(i);
	      }
	  }

每次循环产生一个 onclick 的函数,这些函数随时都有可能被执行,并且这些函数里面需要被打印的变量 i 是父级作用域的值
在这里插入图片描述
所以最后打印出来的 i 都是 3,就是因为子函数在执行的时候应用了父执行环境的变量~所以导致父级函数在执行完之后没有被销毁,而是继续保留。

总结

例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

作用域 是针对变量的,比如我们创建了一个函数,函数里面又包含了一个函数,那么现在就有三个作用域

  • 全局作用域==>函数1作用域==>函数2作用域
    作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。

原型链 是针对构造函数的,比如我先创建了一个函数,然后通过一个变量new了这个函数,那么这个被new出来的函数就会继承创建出来的那个函数的属性,然后如果我访问new出来的这个函数的某个属性,但是我并没有在这个new出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章