Skip to content

Latest commit

 

History

History
156 lines (138 loc) · 5.29 KB

闭包的概念.md

File metadata and controls

156 lines (138 loc) · 5.29 KB

闭包,单从字面上来理解是一个包已经被封装好了的意思,外界是不可以访问的,那么,在js中又是什么意思呢?

以前对闭包的概念总是模模糊糊的,每每听人说闭包,就觉得什么好高大上的样子


  • 闭包,通常有个比较标准的格式,我们先来感受下
function my() {
var a=1;//局部变量
}
alert(a);//报错,a is not defined,函数体外不可以访问
function my() {
var a=1;//局部变量
return function () {
alert(a);}//闭包
}
my()();//1

其实我觉得闭包的格式就是一个函数1体内镶嵌另一个函数2,可以通过这个函数2访问函数1的变量

  • 这也引出了闭包的一个强大的作用,就是可以通过闭包外部访问函数内部的变量

  • 闭包还有一个作用,在一个环境下同时出现两个变量,为了避免冲突,可以使用闭包,这样就只能访问闭包里的东西,其他就不能访问

    • 举个例子
    var n=2;
    function my() {
    var n=1;
    return function () {
    var n=3;
    return n; }//this is a 闭包
    }
    alert(n);//2,这只能访问到全局变量n,函数内部无法访问
    alert(my);//打印出来my这个函数
    alert(my());//打印出来的是闭包,此时又为n赋值为3,
    alert(my()());//3,打印的是闭包里的变量

    这里面赋了3个n值,但是他们互不影响

    • js高级编程书上对于闭包是列出了这两段代码
    var name='ly';
    var obj={ name:'lyy', 
    say:function () {  //在这个时候没有使用闭包
    return function () {
    return this.name; };//注意看return这个函数,并没有返回任何对象的调用,返回的只是this.name。并没有指明他的对象

} }; alert(obj.say()());//'ly'obj.say()返回一个匿名函数,这个时候,编译器会默认对象是window


这里只是调用obj的这个say方法,方法定义的是返回this.name
在这个时候,没有使用闭包,并不能访问到obj.name的值,所以this会自动理解为全局变量

```javascript
var name='ly';
var obj={ name:'lyy', 
say:function () {  
var that=this;//这个时候this指向的是obj
return function () {
  return that.name; };//现在是一个闭包了,因为他调用了函数的变量了
 }
  };
 alert(obj.say()());//'lyy'因为使用了闭包,这个时候that指向的是obj
  • 最近在论坛上看到这样的一段代码,思考了很久,觉得挺有意义的
  function my() { 
  var n=1; 
  return function() { 
   n++;
   alert(n); 
} 
   } 
   my()();//2,使用了闭包,n 的值为1
   my()();//2,同样使用了闭包,闭包的作用就是让这些变量的值始终保持在内存中,所以n还是为1
var foo=my(); //创建了和my一样的函数
foo();//2,foo();使用了闭包
foo();//3,这个时候调用的n值已经是执行了一次方法的n值了,n=2;并没有使用闭包

只要把这两段代码弄懂了,闭包就差不多了,其实js不存在什么闭包的,每个都是对对象的调用,函数也不过是特殊对象一种而已

  • 在闭包中,其实就是需要弄清全局变量和局部变量
  • 在上一段小代码,方便理解全局变量和局部变量
fuction my() {
 n=2;
 var n=1;
 alert(n);
 }
 alert(n);//2,这是全局变量
 my();//1,这是局部变量,my这个函数要求打印局部变量n,因为alert是出现在n=1之后,所以临近原则是1
 //如果是出现在n=2之后,临近原则,出现的就是2
  • 最近发现了一段代码,叫循环中的闭包,先来感受下
  • 代码
function f() {
var a=[];
var i;
for(i=0;i<3;i++) {
a[i]=function () {  //这里的i是数组的arguments,数组的长度为3,0,1,2
return i; }  //这里的i不是上述的i,指的是for循环执行后的i,for循环是先比较,再执行,所以返回的是最终循环停止的结果3
}
return a;
 }
var m=f();
m[0]();//3
m[1]();//3
m[2]();//3
console.log(m);//返回的是一个数组

初次看这段代码,觉得一头雾水,琢磨了很久,还是有那么一点点领悟

首先弄清楚f()返回的就是一个数组,m是创造的一个函数实例,同样返回的是数组

再来看看a[i]这个函数,里面包含了一个闭包,返回的是i

接下来看循环,a[i]返回的就是a[0];a[1];a[2];return i返回的一直就是3,就是说这个函数返回的都是3

why?

难道不应该是0,1,2,最起码也是2啊,3是如何得来的?可以先看一个例子

function  f() { 
for (var i=0;i<3;i++) { 
var a=[i]; 
} 
console.log(i); //3,在这里据不得不说传值和传引用的区别了,这里返回的只是一个值
console.log(a); //2,这里返回的是数组
} f();

那么这个就说得通了,m()的返回就是一个数组,m[i]=function () { return i };在浏览器测试中就可以发现闭包下面的i一直都是3, 变的只是m[i],但这并不影响,其实说这段代码存在一个很大的bug一点也不为过,在写代码的时候没有考虑值的传入和数组的引用

  • 来一段修改后的正常代码
function f() {
var a=[];
var i;
for(i=0;i<3;i++) { 
a[i]=(function (x) { 
return function() {
return x;   //闭包
 } 
   })(i); //在函数中直接传入i的值,
   }  
 return a; 
 }