精华内容
下载资源
问答
  • 有些同学会理解什么是闭包,和匿名函数有什么区别,为什么闭包会占用内存? 什么是闭包? 一个函数与其相关的环境组合而成的实体 由于闭包是其所在环境相关的,所以直到闭包对象被释放,闭包内部的内存是...

    有些同学会不理解什么是闭包,和匿名函数有什么区别,为什么闭包会占用内存?

    什么是闭包?

    • 一个函数和与其相关的环境组合而成的实体
    • 由于闭包是和其所在环境相关的,所以直到闭包对象被释放,闭包内部的内存是不会释放的

    举个go语言的例子

    func main() {
    	f := adder()
    	fmt.Println(f(1), f(2), f(3))	// 2, 4 7
    }
    
    func adder() func(int) int {
    	x := 1
    	return func(d int) int {
    		x += d
    		return x
    	}
    }
    

    解释下代码流程

    • 首先变量 f 是一个函数类型的变量,其值就是 adder 返回的一个匿名函数
    • 而这个返回的匿名函数并不是一个单纯的匿名函数,其中使用了 adder 的内部变量x
    • 也就是在 f 是一直会持有 x 这个变量直到 f 退出其所在的变量作用域,x 才会被回收,并不是在调用完 adder 就被回收了
    • 由于 f 始终持有 x ,所以每次调用 f 时,对 x 的赋值操作都会被保留,直到 f 被回收结束

    下面的例子可自行理解一下

    func adder(x int) func(int) int {
    	return func(d int) int {
    		x += d
    		return x
    	}
    }
    
    func proc() {
    	f1 := adder(1)
    	fmt.Println(f1(1), f1(2), f1(3))    // 2, 4 7
    	f2 := adder(10)
    	fmt.Println(f2(1), f2(2), f2(3))    // 11, 13, 16
    }
    
    展开全文
  • 也去网上搜索了不少的资料,查到资料解释都各说辞,甚至有些解释本身就是正确的,这更加让人头疼。今天就来聊一聊匿名函数闭包,浅谈一下他们之间的关系(实际上他们之间并没有什么直接关系!important)。 ...

    前言

    相信很多前端小伙伴在工作和学习中,都会或多或少的接触和了解到匿名函数闭包。也去网上搜索了不少的资料,查到资料和解释都各有说辞,甚至有些解释本身就是不正确的,这更加让人头疼。今天就来聊一聊匿名函数闭包,浅谈一下他们之间的关系(实际上他们之间并没有什么直接关系!important)。

    什么是匿名函数

    匿名函数相对应的是具名函数,具名函数非常简单:function myFn(){},这就是个具名函数这个函数的name是myFn。可以测试一下:

    function myFn(){
    }
    cosnole.log(myFn.name);//myFn
    

    特别说明一下,函数表达式也是一种具名函数的定义方式。比如var myFn1 = function(){},打印myFn1.name,也会得到myFn1。

    再说匿名函数,一般用到匿名函数的时候都是立即执行的。通常叫做自执行匿名函数或者自调用匿名函数。常用来构建沙箱模式,作用是开辟封闭的变量作用域环境,在多人联合工作中,合并js代码后,不会出现相同变量互相冲突的问题。立即执行的匿名函数有很多种写法,常见的有以下两种:

    (function(){ 
      console.log("我是匿名方式1");
    })();//我是匿名方式1
    
    (function(){ 
      console.log("我是匿名方式2");
    }());//我是匿名方式2
    
    console.log((function(){}).name);//'' name为空
    

    两者的区别就是:一个是发起执行的括号在匿名函数括号的外面,另外一个发起执行的括号在匿名函数的里面。实际中的书写方式个人推荐第一种,这种写法更符合调用机制,调用时的参数也比较明显,如下:

    (function(i,j,k){ 
      console.log(i+j+k);
    })(1,3,5);
    //9
    

    还有其他一些自执行匿名函数的写法,如下:

    -function(){ 
      console.log("我是匿名方式x");
    }();
    console.log(-function(){}.name);//-0
    +function(){ 
      console.log("我是匿名方式x");
    }();
    console.log(+function(){}.name);//0
    ~function(){ 
      console.log("我是匿名方式x");
    }();
    console.log(~function(){}.name);//-1
    !function(){ 
      console.log("我是匿名方式x");
    }();
    console.log(!function(){}.name);//true
    void function(){ 
      console.log("我是匿名方式x");
    }();
    console.log(void function(){}.name);//undefined
    

    这几种操作符,有时会影响结果的类型,不推荐使用,大家可以查下资料看看各种方式之间的差别。具名函数其实也可以立即执行,在此不做太多的伸展(本文主要目的是为了说明匿名函数和闭包之间的关系)。

    实际上,立即执行的匿名函数并不是函数,因为已经执行过了,所以它是一个结果,这个结果是对当前这个匿名函数执行结果的一个引用(函数执行默认return undefined)。这个结果可以是一个字符串、数字或者null/false/true,也可以是对象、数组或者一个函数(对象和数组都可以包含函数),当返回的结果包含函数时,这个立即执行的匿名函数所返回的结果就是典型的闭包了。

    闭包是怎么定义的,该如何理解

    闭包本身定义比较抽象,MDN官方上解释是:A closure is the combination of a function and the lexical environment within which that function was declared.
    中文解释是:闭包是一个函数和该函数被定义时的词法环境的组合。
    很多地方可以看到一个说法:js中每个函数都是一个闭包,这样理解也是没有问题的,不过会增加对闭包的理解难度,这里先不这么理解,可以按照闭包起的作用来理解它:就是能在一个函数外部执行这个函数内部的定义方法,并访问内部的变量

    在此,先看个经典的使用闭包的案例,实现在函数外部访问函数内部的局部变量:

    function box(){
      var a = 10;
      function inner(){
        return a;
      }
      return inner;
    }
    var outer = box();
    console.log(outer());//10
    

    正常情况,box执行过后,会被回收机制回收所占用的内存,包括其内部定义的局部变量。但是此时box执行过后返回一个内部的函数inner,这个inner引用了内部的变量a,inner又被外部outer给接收,回收机制检查到内部的变量被引用,就不会执行回收。

    但是看到这里,还是一脸蒙比,哪里使用了闭包?貌似有三个函数呀,一个box,一个inner还有一个outer = box()。

    • 这个案例中用到的闭包其实是inner和inner被定义时的词法环境,这个闭包被return出来后被外部的outer引用,因此可以在box外部执行这个inner,inner能够读取到box内部的变量a。

    • 使用这个闭包的目的是为了在box外部访问a,就是通过执行outer()。

    用匿名函数实现闭包

    上面的例子是在具名函数box内部用一个具名函数inner实现了闭包,那怎么使用匿名函数实现闭包呢,也很简单:

    //第一步直把内部inner这个具名函数改为匿名函数并直接return, 结果同样是10
    function box(){
      var a = 10;
      return function(){
        console.log(a) ; 
      }
    }
    var outer = box();
    outer();//10
    //第二步把外部var outer = box()改成立即执行的匿名函数
    var outer = (function(){
      var a=10;
      return function(){
        console.log(a);
      }
    })();
    //outer 作为立即执行匿名函数执行结果的一个接收,这个执行结果是闭包,outer等于这个闭包。
    //执行outer就相当于执行了匿名函数内部return的闭包函数
    //这个闭包函数可以访问到匿名函数内部的私有变量a,所以打印出10
    outer();//10
    

    这样我们就改写成了由匿名函数实现的闭包,真正使用到的闭包是内部的被return的函数和这个函数所定义时的环境。由此可以说明:闭包跟函数是否匿名没有直接关系,匿名函数和具名函数都可以创建闭包。

    for循环的问题及解决方案

    还有一个令人感到困惑,工作和学习中也经常遇见的问题是在for循环中:

    for(var i = 0;i<5;i++){
      setTimeout(function(){
        console.log(i);
      },100*i);
    }
    

    我们希望打印出来0,1,2,3,4,然而打印出来的是5个5,很尴尬。什么原因引起的这问题呢?这是因为setTimeout的回调函数并不是立即执行的而是要等到循环结束才开始计时和执行(在此对运行机制不伸展),要说明的一点是js中函数在执行前都只对变量保持引用,并不会真正获取和保存变量的值。所以等循环结束后i的值是已经是5了,因此执行定时器的回调函数会打印出5个5。

    1)怎么解决这个问题?
    最常见的解决方法就是给定时器外面加一个立即执行的匿名函数,并把当前循环的i作为实参传入这个立即执行的匿名函数。如下:

    for(var i = 0;i<5;i++){
      (function(i){
        setTimeout(function(){
          console.log(i);
        },100*i);
      })(i);
    }
    

    可以得到预想的结果:0,1,2,3,4,此时很多人认为这个立即执行的匿名函数就是闭包,其实这么理解是错误的,然后在错误的理解之上又扩展了好多案例,导致其他人看后不知所谓,一头雾水。附上一张Stack Overflow上一位同学的回答截图,我觉得他说的特别有道理:

    image


    原文地址:https://stackoverflow.com/questions/8967214/what-is-the-difference-between-a-closure-and-an-anonymous-function-in-js

     

    2)那到底这个for循环中的闭包是什么呢,其中的自执行匿名函数又起到什么作用呢?
    我们可以试着把这个自执行的匿名函数改写为具名的函数,来测试下结果:

    for(var i = 0;i<5;i++){
      function hasNameFn(i){
        setTimeout(function(){
          console.log(i);
        },100*i);
      };
      hasNameFn(i);
    }
    

    可以发现结果和使用匿名函数的结果是一样的,所以这里也可以说明闭包跟匿名函数没什么直接关系。

    这个for循环中的闭包怎么理解以及自执行匿名函数的作用:

    • 这个for循环产生的闭包其实是定时器的回调函数,这些回调函数的执行环境是window,类似刚才例子中的引用inner的全局outer的执行环境,匿名函数则相当于刚才例子中的box函数。

    • 而自执行的匿名函数的作用也很简单:就是每一次循环创建一个私有词法环境,执行时把当前的循环的i传入,保存在这个词法环境中,这个i就类似上面box函数中var声明的a。

    • 刚才有说到函数在被执行前都只是保存对变量的引用,自执行的匿名函数正是因为执行了,所以能够获取当前的变量i的值。因此定时器的回调函数在执行时引用的i就已经确定了具体的值。

    • 或许我们改写一下,这么看就能更清晰明了一些:

    for(var i = 0;i<5;i++){
      (function(j){
        setTimeout(function(){
          console.log(j);
        },100*j);
      })(i);
    }
    

    改写后的匿名函数形参用j来表示,匿名函数执行时传入实参i,此时定时器里面打印的其实是j,匿名函数立即执行,j的值也会确定。所以最后每次定时器的回调函数打印的结果也都是这个已经被匿名函数所确定的值。

    3)其他的解决方案
    解决刚才for循环的问题,其实根本要解决的问题是如何让每次循环的定时器的回调函数引用当前的i,而不是循环结束后的i。

    最简单的方法是使用es6 let,能够为变量创建块级作用域:

    for(let i = 0;i<5;i++){
      setTimeout(function(){
        console.log(i);
      },100*i);
    }
    //改写成下面这么写更好理解一些
    for(var i = 0;i<5;i++){
      let j = i;
      setTimeout(function(){
        console.log(j);
      },100*j);
    }
    

    还可以用bind绑定当前的i给定时器的回调函数(实际上bind方法内部还是实现了一个对调用者的柯里化闭包,并保存了执行时传入的参数给调用者):

    for(var i = 0;i<5;i++){
      setTimeout(function(i){
        console.log(i);
      }.bind(this,i),100*i);
    }
    

    可以得到跟使用立即执行函数同样的效果,所以说匿名函数闭包之间并没有什么关系,只不过很多时候在用到匿名函数解决问题的时候恰好形成了一个闭包,就导致很多人分不清楚匿名函数和闭包的关系。

    原文链接:https://www.jianshu.com/p/0a3150afb7ed

     

    展开全文
  • 全面一致的64位支持。...移除了一些老的在支持的SAPI(服务器端应用编程端口)扩展。 新增了空接合操作符。 新增加了结合比较运算符。 新增加了函数的返回类型声明。 新增加了标量类型声明。

    性能提升:PHP7比PHP5.6性能提升了两倍。

    全面一致的64位支持。
    以前的许多致命错误,现在改成抛出异常
    移除了一些老的不在支持的SAPI(服务器端应用编程端口)和扩展。
    新增了空接合操作符。
    新增加了结合比较运算符。
    新增加了函数的返回类型声明。
    新增加了标量类型声明。

    展开全文
  • 匿名用户1级2017-08-15 回答存储函数存储过程统称为存储例程(stored routine)。两者的定义语法很相似,但却是不同的内容。存储函数限制比较多,比如能用临时表,只能用表变量。还有一些函数都可用等等。而存储...

    匿名用户

    1级

    2017-08-15 回答

    存储函数和存储过程统称为存储例程(stored routine)。两者的定义语法很相似,但却是不同的内容。

    存储函数限制比较多,比如不能用临时表,只能用表变量。还有一些函数都不可用等等。而存储过程的限制相对就比较少。

    一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。

    2、返回值上的不同

    存储函数将向调用者返回一个且仅返回一个结果值。

    存储过程将返回一个或多个结果集(函数做不到这一点),或者只是来实现某种效果或动作而无需返回值。

    3、调用方式上的不同

    存储函数嵌入在sql中使用的,可以在select中调用,就像内建函数一样,比如cos()、hex()

    存储过程只能通过call语句进行调用

    4、参数的不同

    存储函数的参数类型类似于IN参数

    存储过程的参数类型有三种、IN参数、OUT参数、INOUT参数

    ------------------------------------------

    存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。

    存储过程和函数存在以下几个区别:

    1)一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。存储过程,功能强大,可以执行包括修改表等一系列数据库操作;用户定义函数不能用于执行一组修改全局数据库状态的操作。

    2)对于存储过程来说可以返回参数,如记录集,而函数只能返回值或者表对象。函数只能返回一个变量;而存储过程可以返回多个。存储过程的参数可以有IN,OUT,INOUT三种类型,而函数只能有IN类~~存储过程声明时不需要返回类型,而函数声明时需要描述返回类型,且函数体中必须包含一个有效的RETURN语句。

    3)存储过程,可以使用非确定函数,不允许在用户定义函数主体中内置非确定函数。

    4)存储过程一般是作为一个独立的部分来执行(

    EXECUTE

    语句执行),而函数可以作为查询语句的一个部分来调用(SELECT调用),由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。

    SQL语句中不可用存储过程,而可以使用函数。

    展开全文
  • 我们在给标签添加事件的时候会遇到添加return和不添加return的写法,例如: 1:不添加 return (正常写法) <!--调用方法时,因为f()被赋值给一个变量 c, 所以直接用c()调用这个方法,方法可以省去f()命名,直接写匿名...
  • 匿名用户1级2009-08-18 回答下面通过一个简单的例子加以说明,两者的区别。由于构图不好,照了一张很多白边的照片,就会把正确构图以外的部分统统去掉,即只保留照片部分,白边统统删除,这叫"裁切" 。裁切多用在...
  • 匿名内部类看了半天真心看懂,不知如何理解,如何更好的应用,还要它是否属于内部类的一种,成员内部类以及局部内部类有什么区别
  • 1.箭头函数相当于匿名函数,是能作为构造函数的,能使用new 2.箭头函数绑定arguments,取而代之用rest参数…解决 3.箭头函数会捕获其所在上下文的this值,作为自己的this值。即箭头函数的作用域会继承自外围...
  • 匿名是指每个人的身份是无法被人知道的,而化名是指每个人在区块链上一个真实身份无关的虚拟身份,但是这个虚拟身份做的所有事情都是透明的。 那么匿名其实是想表露自己身份同时还可以是保护隐私...
  • 中国移动互联网设置中国移动WAP设置有什么区别匿名 | 浏览 22852 次 |举报 我有更好的答案 推荐于2017-05-16 17:48:47 最佳答案 在移动端,把接入点分成wapnet两种,这是中国特色,世界其他...
  • 匿名用户1级2014-10-24 回答变量分类1. 类变量l 在类定义中使用关键字static修饰的字段l 在接口声明中使用或者使用static修饰的字段说明:当准备好类或接口时就会创建一个类变量并将其初始化为一个默认值。当卸载...
  • 匿名用户1级2018-11-24 回答2012比08功能增强很多,赠家了一些函数,修改了一些处理机制1. AlwaysOn-这个功能将数据库的镜像提到了一个新的高度。用户可以针对一组数据库做灾难恢复而不是一个单独的数据库。2....
  • 塞巴斯蒂安,你问的是一个相当困难的问题。虽然你可能认为这只是一个问题,你实际上是一次问几个问题...基本上两种类型:静态非静态。这两者之间的真正区别是:>静态内部类:>被认为是“顶级”。>不要...
  • 右值引用左值右值引用的作用左值右值的概念右值引用左值引用的区别 ...右值:能对表达式取地址,或匿名对象。一般指表达式结束就不再存在的临时对象。 右值引用左值引用的区别 左值可以寻址,而右
  • 匿名用户1级2017-05-09 回答非相关子查询先看一个非相关子查询到sql语句。需求:查询学生表student学生成绩表grade中成绩为70分的学生的基本信息。[sql] view plain copy print?select t.sno,t.sname,t.sage,t....
  • 1、比特币的区块链是去中心化的,而传统电子货币都一个中心的服务商。这使得比特币存在一个单独的漏洞可供击溃,系统较为稳定。 2、比特币的区块链的账户是匿名的。但是因为交易历史是完全公开的,投入足够的...
  • 这种方式, 编译后变量声明FUNCTION_NAME 会“被提前”了,但是他的赋值(也就是FUNCTION_BODY)并会被提前。也就是,匿名函数只有在被调用时才被初始化。如果我们使用 function FUNCTION_N...
  • 匿名用户1级2009-06-08 回答常看到别人使用或讨论yield语法,能搜到的中文解释却多,今天决心搞定yield,把暂时的理解贴到这里.搞定yield之前: 叠代器(iterator)发现yield: 生成器(constructor)使用yield: 递归调用1....
  • 你问的是一个非常棘手的问题。 虽然您可能认为这只是一个问题,但实际上您实际上是... 基本上两种类型:静态嵌套类内部类。 这些之间的真正区别是:静态嵌套类:被认为是“顶级”。要求构造包含类的实例。如果...
  • 1. 两种写法最大的区别是: (1) var init = function()...ES5 规定,函数只能在顶级作用域函数作用域中声明,否则是合法的。例如: ES6 引入了块级作用域的概念,这种定义方法就被允许了。在块级作用域里面声明
  • 1.接口的方法默认是Public,所有的方法在接口中都能实现(在方法的括号后面写分号不要再有大括号),抽象类可以非抽象的方法 2.接口中的实例变量默认是final类型的,而抽象类一定 3.一个类可以继承多个接口,但...
  • 这种方式, 编译后变量声明a 会“被提前”了,但是他的赋值(也就是a)并会被提前。 也就是,匿名函数只有在被调用时才被初始化。 如果使用 function a () {}; 这种方式, 编译后函数声明他的赋值都会被提前。 ...
  • 现在市面上IP代公司出售的代理IP,从隐藏级别上区分,可分为三种,即透明代理、普通代理匿名代理。三者区别如下:1、透明代理:服务器知道你使用了代理IP,而且知道你的真实IP;2、普通代理:服务器知道你使用了...
  • 在 ES 规范中,一个内部函数 IsAnonymousFunctionDefinition()用来判断一个函数是否为匿名函数,但是这个函数只在规范中使用,通过 JS 代码并能调用,很多 JS 引擎会在内部实现这个函数(非强制要求)。...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 304
精华内容 121
关键字:

匿名和不匿名有什么区别