• 关于js闭包的误区


    一直以为js的闭包只是内部函数保存了一份外部函数的变量值副本,但是以下代码打破了我的认识:

    function createFunctions()
    {
    	var result = new Array();
    
    	for(var i=0;i<10;++i)
    	{
    		result[i] = function()
    		{
    			return i;
    		}
    	}
    
    	return result;
    }
    
    var funcs = createFunctions();
    for(var i=0;i<10;++i)
    {
    	console.log(funcs[i]());
    }
    

      执行结果是10个10 而不是0-9

    看了JS高级编程7.2.1之后才明白 变量i并不是存在于匿名函数的局部变量表,而是存储在createFunctions的活动对象表(存储参数和局部变量)中。并且在创建函数的定义过程中匿名函数只是被定义而没有被执行。直到后面输出的循环被定义的匿名函数们才得以执行,而这时候它们的活动对象表里并不存在i,然后它们就会从作用域链向上查找createFunctions的活动对象表中的i。这时i的值已经是10,因此它们的执行结果全是10。

    以下代码在闭包外部再加入了一个含参数的闭包,并且在定义之后调用,传递进去当前的i。这时这层新增的闭包活动对象表中含有参数num会存储i的当前值。这样结果就是0-9了:

     1 function createFunctions()
     2 {
     3     var result = new Array();
     4 
     5     for(var i=0;i<10;++i)
     6     {
     7         result[i] = function(num)
     8         {
     9             return function(){
    10                 return num;
    11             }
    12         }(i);
    13     }
    14     return result;
    15 }
    16 
    17 var funcs = createFunctions();
    18 for(var i=0;i<10;++i)
    19 {
    20     console.log(funcs[i]());
    21 }

    闭包的活动对象表中并不会包含this,this是当前执行上下文中的概念,会随着调用环境而变化。

     1 name = "global name"
     2 var obj = {
     3     name:"object name",
     4     func:function()
     5     {
     6         return function(){
     7              return this.name;
     8         }
     9     }
    10 }
    11 console.log(obj.func()());
    12 
    13 var obj2 = {
    14     name:"object name",
    15     func:function()
    16     {
    17         that = this;
    18         return function(){
    19              return that.name;
    20         }
    21     }
    22 }
    23 console.log(obj2.func()());
    24 
    25 var obj3 = {
    26     name:"object name",
    27     func:function()
    28     {
    29         return this.name;
    30     }
    31 }
    32 console.log(obj3.func());
    33 console.log((obj3.func)());
    34 console.log((obj3.func = obj3.func)());

    输出结果:

    global name
    object name
    object name
    object name
    global name

    第一个输出 因为this并不在活动对象表里,闭包在调用的地方才获得当前的this,也就是全局对象

    第二个输出 因为闭包定义之前取了this存到外层函数的that变量,用that就可以得到自定义对象

    第3,4个输出 没有闭包 直接输出this

    第五个输出 因为赋值表达式取结果的操作把当前的上下文变成了全局的,可以当做赋值操作不属于任何对象因此得到的是全局对象

  • 相关阅读:
    通信编程:WSAEventSelect 模型通信
    VMware 安装 Red Hat 6 虚拟机
    通信编程:Select 模型通信
    Android:隐式 Intent 调用标准 Action
    Android:显式 Intent
    Linux(CentOS)用户修改密码有效期
    linux 系统中断信息
    qt udp 聊天
    docker更改镜像存储位置
    通过dockerfile构建singularity镜像
  • 原文地址:https://www.cnblogs.com/fancybit/p/js_closeture_mistake.html
Copyright © 2020-2023  润新知