手机版

JavaScript必须知道和认识(9)函数谈论闭包

时间:2021-10-28 来源:互联网 编辑:宝哥软件园 浏览:

功能

函数格式

函数getPrototyNames(o,/*可选*/a){ a=a | |[];for(o中的var p){ a . push(p);}返回a;}来电者

Func.caller返回函数调用方。

函数call func(){ if(call func . caller){ alert(call func . caller . tostring());}else{alert('无函数调用');} }函数handleCaller(){ call func();} handleCaller();//返回handlercallfunc();//无函数调用,返回null,执行《没有函数调用》被调用程序。

匿名方法的递归调用。

alert((函数(x) {if (x=)返回;返回x * arguments . callee(x-);}()));//范围

范围对每个人来说都不陌生。今天,我们来谈谈闭包,彻底理解闭包。

scriptvar global='全局范围';//这是全局作用域function scope(){ varscope=' local scope ';//这是本地范围返回范围;//返回的范围是局部变量。}/script 1,定义的全局变量也可以在函数内部访问。当定义的局部变量和全局变量的名称相同时,局部变量将隐藏全局变量,而不会破坏全局变量的值。

var作用域='全局作用域';函数f(){ var scope=' local scope ';返回范围;} alert(f());//本地scopealert(范围);//全局范围;以上真的很好理解,不是吗?

2.全局变量可以不用var声明,但是局部变量必须用var声明。如果局部变量没有用var声明,编译器将默认它是一个全局变量。

span style='line-height:font-family: verdana,Arial,Helvetica,无衬线字体;font-size : px;背景-color: rgb(,);'/span作用域=“全局作用域”;函数f(){ scope=' local scope ';返回范围;} alert(f());//本地scopealert(范围);//局部作用域但是,全局变量不是用var声明的,它们仅限于非严格模式。如果使用严格模式,将会报告错误。

脚本“使用严格的”;作用域='全局作用域';函数f(){ scope=' local scope ';返回范围;} alert(f());//本地scopealert(范围);//本地范围/脚本

因此,建议在声明变量时千万不要省略var,以免带来不必要的麻烦。

3、提前声明,也可以降。提前做什么。

脚本“使用严格的”;范围;console.log(作用域);var作用域='全局作用域';console.log(作用域);/script,您可能会看到第一个打印没有定义。是的,他还没有被赋值。以下分配可以打印全局范围。

这种理解没有错,但为什么呢?变量在使用之前不应该定义吗?

让我告诉你范围链。JavaScript是一种基于词法范围的语言。

1.作用域链是一个对象或一个链表,在这组代码中定义了这段代码“作用域”中的变量。当JavaScript需要找到变量范围时,会从链中的第一个对象开始搜索。如果第一个对象是作用域,它将直接返回这个对象的值。如果它不存在,它将继续搜索第二个对象,直到找到为止。如果在作用域链上找不到该变量,将引发错误。

是的,这个动作链可以表达如下:寻找一个范围窗口(全局对象)显然有一个定义在它后面的范围。但是,没有执行赋值操作,赋值操作是稍后执行的,因此此时的值是未定义的。

4.这令人困惑。猜猜打印值是多少。

脚本“使用严格的”;var作用域='全局作用域';函数f() {console.log(作用域);var作用域=“本地作用域”;console.log(作用域);} f();/script看到这段代码:如果你不小心,你很可能会写错答案:

1、全球范围

2、局部范围

分析:声明全局变量。在函数体中,第一个代表全局变量,所以打印全局;第二个定义局部变量并覆盖全局范围,所以打印局部范围。

C# java中的分析完全正确。但是这里的分析真的错了。

在解释这个问题之前,我们先来看一个问题。

这句话很重要:全局变量总是在程序中定义的。局部变量总是在声明它的函数体和嵌套它的函数中定义。

如果你从事的是高级语言工作,不适合定义JavaScript的范围。我也是。让我们看一个例子:

scriptvar g='全局范围';函数f(){ for(var I=;我;I){ for(var j=;j;j){;} console . log(j);} console . log(I);} console . log(g);f();/脚本打印的结果是什么?

你可以看到{}代表一个语句块,而语句块在一个作用域内,所以你可能猜测j和I的值已经在内存中释放了,所以结果肯定是未定义的。

真正的结果可能会让你失望,

为什么会这样?我从和你一样的表情开始。

看看此刻我让你记住的那句话。全局变量总是在程序中定义的。局部变量总是在声明它的函数体和嵌套它的函数中定义。

确切地说,函数的参数也属于局部变量的范畴。这句话也很重要!

那句话大致意思是,只要是函数内定义的变量,在整个函数内都有效。所以结果不难理解。回顾我们的问题,你明白了吗?

动作链也有以下定义:

1.动作链由一个全局对象组成。

2.在没有嵌套的函数体中,动作链中有两个对象,第一个定义函数参数和局部变量,第二个是全局对象。

3.在嵌套函数体中,动作链至少包含三个对象。

设置函数时,会保存一个范围链。

调用此函数时,它将创建一个新对象来存储其局部变量,并将此对象添加到保存的动作链中。同时,创建一个新的更长的动作链来表示函数调用。

对于嵌套函数,当调用外部函数时,内部函数将被重新定义。因为每次调用外部函数,动作链都不一样。每次定义内部函数时,它们都有细微的不同。每次调用外部函数,内部函数的代码都是一样的,关联代码的范围也不一样。

关闭

这样做了这么久,我们终于要谈了,不过我们会分析之前的范围。

script var nameg=' global ' var g=function f(){ console . log(name);函数demo(){ console . log(' demo=' name ');} var name=函数demo(){ var name=' ';console . log(' demo=' name);}函数demo(){ console . log(' demo=' nameg ');} demo();demo();demo();};g();/script我们根据动作链进行分析:

调用demo0,demo0()-查找名称,但找不到-f()查找,返回。

调用demo1,demo1()-查找名称,查找并返回。

调用demo2,demo2()-find nameg,但是-f () find nameg,而不是find-window find nameg find,返回。

看看这个例子:

script function f(){ var count=;return { count : function(){ return count;},reset : function(){ return count=;} } } var d=f();var c=f();console . log(' d first call:' d . counter());//console.log('c第一次调用: ' c . counter());//不影响console.log('d第一次调用: ' d . reset());//console.log('c第二次调用' c . counter());///脚本在这个例子中可以看到,我做了一个计数和清零操作。

创建了f的两个对象实例d c,每个实例都有自己的范围链,因此它们的值不会相互影响。第二次调用c时,由于c对象没有被破坏,因此保存了计数值。理解了这个例子之后,下面的例子就更容易理解了。

这个过程,大家应该都很清楚。现在我们来看看闭包问题。我设置了四个按钮,单击每个按钮返回响应的名称。

body script function BTninit(){ for(var I=;我;I){ var BTN=document . getelementbyid(' BTN ' I);btn.addEventListener('click ',function(){ alert(' BTN ' I);});} } window.onload=btnInit/script div button id=' BTN ' BTN/button button id=' BTN ' BTN/button button id=' BTN ' BTN/button button id=' BTN ' BTN/button/div/body点击运行,但结果都是btn5

我们用刚才的分析坐下来。首先,我们需要调用匿名函数-find I,但是-btnInit()没有找到,I是在for循环中找到的。找到了。我们知道它只有在函数调用结束后才会被释放,for中的I总是可见的,所以保留了I的最后一个值。那么如何解决呢?

为了解决I值在函数中不总是可见的问题,我们应该使用函数的嵌套,然后传入I值。

函数btnInit(){ for(var I=;我;I){(function(data _ I){ var BTN=document . getelementbyid(' BTN ' data _ I);btn.addEventListener('click ',function(){ alert(' BTN ' data _ I);});}(I));}}看看修改后的代码。首先,第一次执行并创建一个对象。首先,我们执行匿名函数-data_i,但不执行find -function(data_i),然后再次执行for来创建一个对象。关闭规则互不影响。这样我们才能得到正确的结果。

以上就是边肖给大家介绍的JavaScript知识。(9)函数谈闭包问题,希望对你有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

版权声明:JavaScript必须知道和认识(9)函数谈论闭包是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。