JavaScript基础的函数表达式闭包(6)
实际上,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)的函数表达式闭包。希望你喜欢。
版权声明:JavaScript基础的函数表达式闭包(6)是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。