闭包几个思想
javascript中有两种作用域,全局和局部,由于局部作用域的存在导致外部无法访问函数内部变量,从而出现了闭包思想。闭包的关键是作为沟通函数内外部的数据桥梁。
//一个实现
function closure() {
var innerVar = 0;
function inner() {
return ++innerVar;//可以直接修改innervar的值
}
return inner;
}
var quote = closure();
echo(pclosure1, quote());//1
echo(pclosure1, quote());//2
js是函数作用域的,即一个function就是一个局部作用域,innerVar在函数作用域里面。但是希望能操作该内部变量。 那么其内部的函数就可以访问并修改这个局部变量。所以在第二次调用时,第一次调用的结果仍然保存着。
2:闭包中涉及的静态与动态作用于思想
var name = "xiaofu";
var person = function(lastname){
var name = 'yang';
function personName(){
return name + lastname;
}
return personName;
}
var pName = person();
pName("xiaoming");
js 中一个function就是一个作用域,所以personName在person这个函数的作用域里面。但是调用的是在这个作用域的外面,那么当personName执行的时候,它里面的name取的是person这个作用域还是最外层的作用域呢?
如果是静态作用域则调用的是person里面的 name, 如果是动态作用域则调用的是外层的name(“xiaofu”);而不是”yang”。
而闭包就是用来实现静态作用域的一种方式,即通过闭包将函数和它声明时的作用域保存下来,这样在调用的时候取到的就是声明时所在作用域 而不是调用时的作用域。
this
this则与变量有点不同,即this采用的是类似于动态作用域的情况。js里面一切都是对象,所以函数也都是某个对象的方法,如果没有显示指定则是全局对象window。
var person = {
fullname: function{
console.log(this);
},
printAge: function(){
console.log(this);
}
}
person.fullname(); //this指向person
var age = person.printAge;
age(); //this指向window(浏览器中)
将person.printAge赋值给age之后,再执行age(),此时age没有显示指定调用对象则默认是window(浏览器环境)。所以this并不是声明所在的环境。
3箭头函数(es6)
es6中新增了箭头函数,箭头函数与通过function声明的函数不同,它的this是使用的声明时上下文中的this.并且不可通过apply, call等改变所以在使用箭头函数时一定要注意this指向问题。
4 闭包的应用—立即执行函数
1:关键立即执行函数本身即是一个闭包
2:闭包可以操作所在函数中的变量(利用这点锁住每次循环的变量值到内存中)
有个网友问了个问题,如下的html,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5。
<html >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>闭包演示</title>
<script type="text/javascript">
function init() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = function() {
alert(i);
}
}
}
</script>
</head>
<body onload="init();">
<p>产品一</p>
<p>产品二</p>
<p>产品三</p>
<p>产品四</p>
<p>产品五</p>
</body>
</html>
使用闭包可以解决异步加载问题:,
方法1、将变量 i 保存给在每个段落对象(p)上
“`
function init() {
var pAry = document.getElementsByTagName(“p”);
for( var i=0; i
**方法2、将变量 i 保存在匿名函数自身**
```
function init2() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
(pAry[i].onclick = function() {
alert(arguments.callee.i);
}).i = i;
}
}
方法3、加一层闭包,i以函数参数形式传递给内层函数
function init3() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
(function(arg){
pAry[i].onclick = function() {
alert(arg);
};
})(i);//调用时参数
}
}
方法4、加一层闭包,i以局部变量形式传递给内存函数
function init4() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
(function () {
var temp = i;//调用时局部变量
pAry[i].onclick = function() {
alert(temp);
}
})();
}
}
方法5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
function init5() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = function(arg) {
return function() {//返回一个函数
alert(arg);
}
}(i);
}
}
方法6、用Function实现,实际上每产生一个函数实例就会产生一个闭包
function init6() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = new Function("alert(" + i + ");");//new一次就产生一个函数实例
}
}
方法7、用Function实现,注意与6的区别
function init7() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = Function('alert('+i+')')
}
}