zoukankan      html  css  js  c++  java
  • 闭包

    闭包##

    之前对闭包的理解就是函数嵌套,内层函数使用了外层函数的变量,然后外层函数执行时返回内层函数。很绕的样子。。。

    最近在啃js基础,才发现这只是表象;其实际是就如同“闭包”closure这个单词的意思一样,函数将变量close起来了; 你不知道的Javascript(上卷)里边的闭包讲的一针见血

    《你不知道的Javascript(上卷)》 推荐

    当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

    个人理解:

    1. 函数执行依赖于作用域链,而函数申明的时候就确定了作用域范围;
    2. 函数执行的时候资源的查找是自下而上的,从自身的局部作用域往上层局部作用域(嵌套函数的外层)直至全局作用域上查找,如果函数内部包含作用域链上的资源,就产生了闭包。
    3. 被闭包起来的资源不管其是值类型还是引用类型,都是共享成为引用,下面的经典问题代码就是由于闭包引起的结果
    4. 生是定义时作用域链的人,死(执行期)是定义时所处作用域链的鬼。
    经典代码#####
    var scope='global scope';
    function checkscope(){
    	var scope='local scope';
    	function f(){ return scope;}
    	return f;
    }
    checkscope()();    // => local scope
    
    经典问题代码#####
    function constfuncs(){
    	var funcs=[];
    	for(var i=0; i< 10; i++){
    		funcs[i] = function(){return i;}
    	}
    	return funcs;
    }
    var funcs = constfuncs();
    funcs[5]();  // =>  10   为毛?
    

    funcs是在同一个函数调用中定义的,因此它们共享变量i, constfuncs返回的时候变量i的值是10。

    解决上述问题

    function constfuncs(){
    	var funcs=[];
    	for(var i=0; i< 10; i++){
    		//利用自调用函数为每个循环创建一层独立的函数作用域
    		(function(j){
    			funcs[i] = function(){return j;}
    		})(i);
    	}
    	return funcs;
    }
    var funcs = constfuncs();
    funcs[5]();  // =>  5
    

    《Javascript权威指南》 犀牛书

    函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中成为“闭包”

    从技术的角度讲,所有的Javascript函数都是闭包: 它们都是对象,都关联到作用域链。

    当调用函数时闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链时,事情就变得非常微妙。当一个函数嵌套在另一个函数内,外部函数把嵌套的函数对象作为返回值返回时往往会发生这种事情。这种编程模式在javascript中非常常见。

    函数定义时的作用域到函数执行时依然有效。

    "闭包” 是指函数变量可以被隐藏于作用域链之内,因此看起来是函数将变量“包裹”起来了

    --

    其实C#中也有类似的闭包效果,比如函数内部返回一个委托

    function Func<int> TestClosure(){
        int count=0;
        return new Func<int>(() => count++);
    }
    var fun= TestClosure();
    fun();  // => 0
    fun();  // => 1 
    

    其实C#的闭包会吧这个int类型的count包装在一个匿名类中而变成引用类型给委托返回值共用;btw 在多线程编程的时候要特别注意闭包问题,因为多线程共享的资源即使是数值类型还最终也是会被clr以匿名类的形式弄成引用类型:

    for(int i=0; i<5; i++)
    {
    /* 这个接受操作非常重要,如果省略 每个task的i都会是4  注意:js没有c#这样的块级作用域, 不能简单的在这里接受!!!*/
    	int j=i; 
    	TaskFactory.StartNew(()=>{ 
    		// do something with "i" through "j"
    	});
    }
    
  • 相关阅读:
    Spring中的@Transactional以及事务的详细介绍
    Shiro缓存使用Redis、Ehcache、自带的MpCache实现的三种方式实例
    使用shiro缓存用户身份信息的时候报:java.io.NotSerializableException: org.apache.shiro.util.SimpleByteSource
    rocketmq 延时消息
    用区块链技术做一个 不可被修改的 恋爱记录 app 我叫<<誓言>>
    java 调用区块链 发布和调用智能合约
    centos 以太坊多节点私链搭建
    数据库的死锁原因 和 处理办法
    聚簇索引
    Java 容易疑惑的一些杂记录
  • 原文地址:https://www.cnblogs.com/mushishi/p/5862178.html
Copyright © 2011-2022 走看看