闭包在MDN相关文档中是这一样定义的闭包是函数和声明该函数的词法环境的组合。
在JavaScript高级程序设计(第3版)中的描述是这一样的闭包是指有权访问另一个函数作用域中的变量的函数。
看完定义大家可能不好理解,在这里给大家举几个例子帮助理解,其实他们的定义就是一个事物的多功能表述
1. 例1:词法作用域
js代码
function outer(){
var name="词法作用域演示";
function inner(){
document.getElementById("display").innerHTML=name;
}
inner()
}
outer();
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">词法作用域演示</div>
<p style="text-align: center" id="display"></p>
解释: outer()创建了一个变量name和一个函数inner(),inner()是outer()的内部函数,仅在outer()里面可以被用。同时inner()里面没有局部变量,它是使用外函数的变量。但是如果在inner()中命名同样类型的局部变量时,再调用的时候会就近调用。
例如
js代码
function outer(){
var name="词法作用域演示";
function inner(){
var name="就近调用";
document.getElementById("display").innerHTML=name;
}
inner()
}
outer();
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">词法作用域演示</div>
<p style="text-align: center" id="display"></p>
这个词法作用域的例子介绍了引擎是如何解析函数嵌套中的变量的。词法作用域中使用的域,是变量在代码中声明的位置所决定的。嵌套的函数可以访问在其外部声明的变量。
词法作用域解释:在说词法作用域之前先说一下作用域和标识符。
作用域: 作用域是一套规则,用于确定在何处以及如何查找变量(标识符)的规则。
标识符: 标识符(identifier)是用来识别具体对象的一个名称。最常见的标识符就是变量名,函数名。JavaScript语言的标识符对大小写敏感,所以a和A是两个不同的标识符。
其实通俗的讲也可以这么理解,在JS中所有的可以由我们自主命名的都可以称为是标识符,例如:变量名、函数名、属性名都属于标识符。 有了前面的两个定义的铺垫再看一下词法作用域的定义
词法作用域是作用域的一种工作模型作用域,有两种工作模型:一种主流的是,JavaScript的静态作用域——词法作用域,另一种则是动态作用域(比较少的语言在用)。另一种解释是:词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,即无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定。
词法作用域进一步解释:
可见这里有三个作用域的嵌套,再结合一下定义你会有所新的理解
2.例2:闭包
js代码
function outer(){
var name="闭包演示";
function inner(){
document.getElementById("display").innerHTML=name;
}
return inner;
}
var getfunction=outer();
getfunction();
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">闭包演示</div>
<p style="text-align: center" id="display"></p>
其实就返回的结果来看这里的结果和例1的词法作用域演示的结果是一样的(这里只是换了name值为“闭包演示”),但是就函数内部来说就有所不同。这里在执行inner()的之前,被外部函数返回了。
再看一个例子
js代码
function outer(){
var name="闭包演示";
function inner(){
document.getElementById("display").innerHTML=name;
}
return inner;
}
var getfunction=outer();//下面没有 getfunction();,直到这一步就结束
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">闭包演示</div>
<p style="text-align: center" id="display"></p>
可见这里是没有返回的结果,这个因为你没有调用getfunction(你可以这样简单的理解为,返回的函数赋值给了getfunction(这里其实是创建实例),需要调用getfunction才能输出结果)。
在例2中函数outer中就形成了闭包函数inner()也就是在JavaScript高级程序设计(第3版)中描述的那样。它可以用过自己的实例getfunction(),来访问变量name
3.例3:闭包中括号
在讲闭包括号之前先看一下这样 的代码
js代码
function outer(a,b){
return a*b;
}
document.getElementById("displayone").innerHTML=outer;
document.getElementById("displaytwo").innerHTML=outer();
document.getElementById("displaythree").innerHTML=outer(2,3);
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">演示</div>
<p style="text-align: center" id="displayone"></p>
<p style="text-align: center" id="displaytwo"></p>
<p style="text-align: center" id="displaythree"></p>
可以看出
1.没有加括号只是返回这个函数的内容
2.加上括号是函数执行后的值
再看下面的例子
js
function outer(){
var name="闭包括号演示";
function inner(){
document.getElementById("displaythree").innerHTML=name;
}
return inner;
}
document.getElementById("displayone").innerHTML=outer;
document.getElementById("displaytwo").innerHTML=outer();
outer()();
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">闭包括号演示</div>
<p style="text-align: center" id="displayone"></p>
<p style="text-align: center" id="displaytwo"></p>
<p style="text-align: center" id="displaythree"></p>
从上面的代码中可以看出加上一个括号例如outer()就是执行outer()函数,并返回子函数(上图第二个内容,如果没有就直接执行)。outer()()的意思就是执行inner()函数,并返回它的子函数(如果没有就直接执行),看下面的例子
4.例4:outer()()
js代码
function outer(){
var name="闭包括号演示";
function inner(){
document.getElementById("displaythree").innerHTML=name;
return "闭包函数返回";
}
return inner;
}
document.getElementById("displayone").innerHTML=outer;
document.getElementById("displaytwo").innerHTML=outer();
document.getElementById("displayfour").innerHTML=outer()();
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">闭包括号演示</div>
<p style="text-align: center" id="displayone"></p>
<p style="text-align: center" id="displaytwo"></p>
<p style="text-align: center" id="displaythree"></p>
<p style="text-align: center" id="displayfour"></p>
可以很清楚的看出outer()()的意思就是执行inner()函数,并返回它的子函数
接下来给大家举一个闭包很有意思的地方
5.例5
js代码
function Add(x) {
return function(y) {
return x + y;
};
}
var add5 = Add(5);
var add10 = Add(10);
document.getElementById("displayone").innerHTML=add5(2);
document.getElementById("displaytwo").innerHTML=add10(10);
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">闭包演示</div>
<p style="text-align: center" id="displayone"></p>
<p style="text-align: center" id="displaytwo"></p>
在前面讲过闭包函数的括号之后,这个例子就很好理解。接下来我对代码进行修改,大家可能会有新的发现
js代码
function Add(x) {
return function(y) {
return x + y;
};
}
document.getElementById("displayone").innerHTML=Add(5)(2);
document.getElementById("displaytwo").innerHTML=Add(10)(10);
html代码
<div style="height: 20px;line-height: 20px;text-align: center; background-color: cadetblue">闭包演示</div>
<p style="text-align: center" id="displayone"></p>
<p style="text-align: center" id="displaytwo"></p>
得到的结果如上,可以发现执行的结果和前面的例子是一样的,其实执行的步骤完全可以用闭包括号的相关知识来解释。
执行的大致步骤是这样的
- 先执行Add()函数,x=5,返回它的子函数
- 执行子函数,y=2,并返回结果(如果结果是个函数,那么就返回函数)
说到这里想必大家已经对闭包函数有了一定的理解了吧。
如果页面中有什么错的内容或者有什么不理解的地方,欢迎来交流