宝哥软件园

JavaScript基础的函数表达式闭包(6)

编辑:宝哥软件园 来源:互联网 时间:2021-09-20

实际上,js支持函数闭包的主要原因是js需要函数来保存数据。这里保存的数据是,函数运行后,只保存函数中的变量值。至于js为什么需要在函数中存储数据,它是一种函数式语言。在函数中保存数据是函数语言的一个主要特征。

回顾一下前面介绍的定义函数的三种方法。

functoisu(numnureturnunum//函数声明语法定义了vasuffunction(numnu num)returnunum }//函数表达式定义了vasunefunction(' num ' ' num ' ' returnunum ')//functoit构造函数。

在分析闭包之前,让我们看看定义和调用函数时容易犯的错误。

例1:

sayHi();//错误:函数尚不存在。var say hi=function(){ alert(' test ');};例2:

if(true){ function SayHi(){ alert(' 1 ');} } else { function SayHi(){ alert(' 2 ');} } SayHi();//打印出来的结果不是我们想要的。

var fun 1=fun 2(){ alert(' test ');} fun 2();//错误:示例1中还不存在该函数,所以在使用该函数的声明性语法定义之前,我们无法调用该函数。解决方案:

1.如果使用函数表达式来定义函数,则需要在定义表达式后调用它。

var SayHi=function(){ alert(' test ');};SayHi(2)。使用函数声明。(这里,浏览器引擎将升级函数声明,并在执行所有代码之前读取函数声明。)

sayHi();函数SayHi(){ alert(' test ');};在示例2中,预期结果应该是打印1,但实际结果是打印2。

if(true){ function SayHi(){ alert(' 1 ');} } else { function SayHi(){ alert(' 2 ');} } SayHi();//打印出来的结果不是我们想要的。为什么呢?由于函数声明的提升,浏览器在预解析时不会判断if条件,而是直接解析第二个函数定义,覆盖第一个。

解决方案:

var sayHiif(true){ SayHi=function(){ alert(' 1 ');} } else { SayHi=function(){ alert(' 2 ');} } SayHi();在示例3中,发现只能调用fun1(),而不能调用fun2()。

我自己的理解,真正的原因不得而知。未找到任何信息。

因为1:function fun 3(){ };相当于var fun 3=fun 3函数(){ };图片:

所以只能用fun1()调用,不能用fun2()调用。

实际上,我还有问题。哪位大神知道,请告诉我们。

既然fun2不能在外部调用,为什么可以在函数内部调用?即使在调试器中仍然无法获得fun1。

好了,通过以上三个问题热身。让我们继续今天的话题“结束”。

1.什么是结束?

定义:一个函数是一个变量,可以访问另一个函数的范围。

让我们从一个示例函数开始:

例1:

函数fun() {var a='张三';} fun();//在我们执行之后,变量a被标记为销毁。

函数fun() {var a='张三';return function(){ alert(' test ');} } var f=fun();//同样,在我们执行之后,变量A被标记为销毁。

函数fun() {var a='张三';返回函数(){ alert(a);} } var f=fun();//[现在情况变了。如果A被破坏,显然如果F被调用,变量A的值就不能被访问]F();//[那么变量A的值是正常访问的]//这就是闭包。当函数A的变量在函数A返回的函数B中使用时,那么函数B使用闭包。示例:函数fun() {var a='张三';返回函数(){ alert(a);} } var f=fun();//[现在情况变了。如果A被破坏,显然如果F被调用,变量A的值就不能被访问]F();//【那么变量A的值是正常访问的】显然,闭包的误用会增加内存的使用。所以尽量不要在非特殊情况下使用闭包。如果使用,记得手动设置null引用,这样内存可以回收f=null

插图:(如果不知道范围链,请先阅读前一篇文章范围和范围链)。

2.什么是匿名函数?(只是解释概念)

如:(即没有名字的函数)

当对象中函数的返回值是匿名函数时,会出现这种奇怪的现象。

在解释之前,先理清思路,不要看着看着就一头雾水。如果你感到困惑,就忽略以下内容。

Var name1='张三';Var obj={name1:' Li Si ',fun 2: fun(){ alert(this。name 1);},fun 3: function(){ return function(){ alert(this . name 1);} } } obj . fun 2();//打印结果‘李四’出乎意料。obj . fun 3()();//因为这是一个函数,我们需要添加一对()来调用它。打印结果是‘张三’,出乎意料。//确实超出了百事可乐的理解范围。这说明了什么大局?前面说过“这是被点击的对象”,那么我们的obj.fun3()()就打印“张三”,也就是说这个执行全局范围。

让我们看看下面的例子,我们可能知道为什么。

Var name1='张三';Var obj={name1:' Li Si ',fun 2: fun(){ alert(this。name 1);},fun 3: function(){ return function(){ alert(this . name 1);} } }//obj . fun 3()();var obj 2={ };obj 2 . name 1=' test ';obj 2 . fun=obj . fun 3();obj 2 . fun();//打印结果‘test’,再次证明“这是被点击的对象”。var name1='张三';Var obj={name1:' Li Si ',fun 2: fun(){ alert(this。name 1);},fun 3: function(){ return function(){ alert(this . name 1);} } }//obj . fun 3()();var obj 2={ };obj 2 . name 1=' test ';obj 2 . fun=obj . fun 3();obj 2 . fun();//打印结果‘测试’,再次证明“这是被点击的对象”。让我们分解obj.fun3()()。首先obj.fun3()向窗口范围返回一个匿名函数,然后调用该函数指向窗口。(感觉解释有点勉强,不知道对不对。我最初是这样理解的。)

闭合形成的原因:记忆释放问题。

一般在执行函数时,会破坏局部活动对象,只在内存中保存全局范围,但闭包情况不同。

闭包的活动对象仍然会存储在内存中,所以就像上面的例子,函数调用返回后,变量I属于活动对象,也就是说它的栈区还没有释放,但是当你调用c(),变量I保存的作用域链从b()-a()-全局查找作用域var i的声明,然后找到var I=1;然后我在封闭;因此,最终输出值为2;

以上是边肖分享的JavaScript基础文章(6)的函数表达式闭包。希望你喜欢。

更多资讯
游戏推荐
更多+