zoukankan      html  css  js  c++  java
  • JavaScript 作用域链与闭包

    作用域链

      在某个作用域访问某个变量或者函数时,会首先在自己的局部环境作用域中搜寻变量或者函数,如果本地局部环境作用域中有该变量或者函数,则就直接使用找到的这个变量值或者函数;如果本地局部环境作用域中没有搜寻到要使用的变量或者函数名,那么就会在上一层的环境作用域中继续寻找,如果在上一层环境作用域中寻找到要使用的变量或者函数名,那么就使用上一层环境作用域中的变量或者函数名;否则,如果在上一层仍旧没有找到要使用的变量名或者函数名,就会继续找上一层的上一层作用域,以此类推,直到进入到全局环境中,如果都没有找到的话,那么就认为是undefined(未声明、未定义)。

      换句话说,如果在局部环境中没有找到变量或者函数,就在上一层寻找,知道找到为止,最终都没找到的话,就是undefined。

    闭包 

      先看下面一个例子:

    function demo(){
    	var name="abc";
    }
    console.log(name);//undefined
    

      上面的代码很好理解,定义在demo函数内部的name变量,在外部是访问不到的。

      你可能会说,都没有调用demo(),怎么可能得到name变量的值,如你所愿:

    function demo(){
    	var name="abc";
    }
    demo();
    console.log(name);//undefined
    

      事实上,即使调用了demo()函数之后,name变量在函数外部也是访问不到的。

      但是有很多种方法可以让外部可以访问name变量。

    方法1:将name声明为全局变量

    function demo(){
    	name="abc";
    }
    demo();
    console.log(name);//abc
    console.log(window.name);//abc

      name声明为全局变量之后,也就是成为window对象的一个属性而已。

      这个方法最好不要使用,不然会造成环境中太多的全局变量,一旦有重复声明,那么就会造成重复声明之前的那些变量值改变,导致错误。

    方法2:将name变量在函数中返回

    function demo(){
    	var name="abc";
    	return name;
    }
    console.log(demo());
    

      这种方式很常用,因为很符合一般人的思维。

    方法3:使用闭包

    function demo(){
    	var name="abc";
    	return function(){
    		return name;
    	}
    }
    var test = demo();
    console.log(test());//abc
    

      

    闭包的概念

      网上有很多中关于闭包的说法,我觉得其中有一种特别好理解:

    闭包就是在一个函数中又定义了一个函数,内部函数可以访问到外部函数作用域内的变量,此时,定义的这个内部函数就叫做闭包。

    并且,无论内部函数在哪里调用,都能访问到外部函数作用域中的变量。

      看上面那个方法3中的demo函数,内部定义了一个函数,内部函数访问外部函数(demo)作用域中的name变量,内部函数称为闭包。

    为什么要使用闭包

    function demo(){
    	var name="abc";
    	return name;
    }
    console.log(demo());

      就以上面的例子而言,如果想要获取demo函数中的name值,那么就需要调用一下demo函数,虽然在调用函数之后,可以获取内部的name值,但是函数调用结束,其中的name变量就已经在内存中被销毁了。

      闭包就可以解决这个问题,使用闭包的话,在调用外部函数之后,外部函数的变量并不会立即销毁,而会一直保存。所以使用闭包有可能会引起内存占用大的情况。

    题外话

      请看下面的代码:

    var i = 10
    (function(x){ console.log(x) })(i)
    //输出10

      上面的代码看着的确很别扭,可以简化一下:

    i = 10;
    var demo = function(x){
    	console.log(x)
    }
    demo(i)
    

      没错,其实就是利用的匿名函数赋值给变量,然后利用变量加圆括号来调用函数。

    i = 10;
    (function(x){//x是定义的形参
    	console.log(x)
    })(i)  //i是传递给函数的实参
    

      

      可以看一下这种用法的示例:

    function demo(){
    	var funcArr = new Array();//funArr是保存函数的数组
    	for(var i=0;i<10;i++){
    		funcArr[i] = function(){
    			console.log(i)   //每次调用函数的时候,打印i值
    		}
    	}
    	return funcArr;		    //返回保存函数的数组
    }
    var func = demo();
    func[1]()  //10
    func[2]()  //10
    

      上面的代码并没有按照想象中运行,并没有func[1]()输出1,func[2]()输出2

      这是因为JavaScript没有块级作用域的原因,解决方法就可以利用上面的用法:

    function demo(){
    	var funcArr = new Array();//funArr是保存函数的数组
    	for(var i=0;i<10;i++){
    		funcArr[i] = (function(x){
    			return function(){
    				console.log(x)   //每次调用函数的时候,打印x值,x是形参,i才是实参
    			}
    		})(i)
    	}
    	return funcArr;		    //返回保存函数的数组
    }
    var func = demo();
    func[1]()  //1
    func[2]()  //2
    

      

      闭包使用最多的场景接收:保存环境变量,将返回的函数中要使用的某些现场变量,防止返回的函数的某些参数受到外界影响。

  • 相关阅读:
    C#中判断为空
    ArcGIS中的AddIn开发示例
    当前不会命中断点,还没有加载该文档加载任何符号
    设置ArcGIS的外观改回到出厂
    读取Style符号库样式的方法
    ArcEngine中的缩放地图
    修改字段结构之GP工具
    修改字段结构之ArcGIS Diagrammer
    merage语句
    Windows下Redis的安装使用
  • 原文地址:https://www.cnblogs.com/-beyond/p/7919002.html
Copyright © 2011-2022 走看看