简单了解闭包(面试)

75 篇文章 2 订阅

闭包其实很简单 ,先了解一下变量的作用域

变量的作用域包括两种:全局变量和局部变量。

全局变量:

var n = 999;//全局变量
function f1(){
  console.log(n);
}
f1();//999

局部变量:

function f1(){
  var n = 999;//局部变量
}
console.log(n);//n is not defined

一、简单理解闭包

闭包:闭包让你可以在一个内层函数中访问到其外层函数的作用域。

代码示例:

function f1(){
  var n = 999;
  
  function f2(){
    console.log(n);
  }
  
  return f2//返回内部函数f2,这样在f1中就能读取f2的数据和函数等价于window.f2 = f2;
  
}

var result = f1();
result();//999  // 相当于我winddows.result能访问f1里面的变量n(局部变量)
  • 首先定义个普通函数f1;
  • 在f1中再定义一个普通函数f2、和在f1函数中的内部变量n;
  • 在f1中返回函数f2(确切说,在f1中返回了f2的引用);
  • 将f1的返回值赋值给变量result;
  • 执行result

在上面:f1函数里面嵌套了一个函数f2,并且f2调用了f1的变量,那么变量n和函数f2组合就成了一个闭包。

1、产生闭包的条件:

  • 一个外部函数里面嵌套着一个内部函数;比如外部函数f1里面嵌套了一个内部函数f2
  • 一个嵌套的内部函数调用了外部函数的内部变量或函数;比如f2内部函数调用了外部函数f1的变量n 只要满足以上两个条件,就产生了闭包。

2、那你可能会问为什么要return f2呢?

因为在JS中,只要内部函数才能够读取外部函数的内部变量或数据,反之则不行,如果你不return f2,那你将无法使用f2这个闭包,return f2是为了在f1中能使用f2的变量和数据,与闭包没有关系的。

3、那到底什么是闭包呢?

可以通俗理解成:闭包就是有权访问另一个函数作用域中内部变量或数据的函数,因为在JS中,只要内部函数能能够读取外部函数的变量或数据,反之就不行,所有可以将闭包简单理解成,定义在一个函数内部的函数。

总结:

闭包就是有权访问另一个函数内部变量的函数。

闭包产生的原因:内部函数存在对外部函数局部变量的引用就会导致闭包。

二、闭包的经典使用场景

1、return一个内部函数,读取内部函数的变量;

最大的一个用途就是前面提到的可以:读取内部函数的变量;

function f1(){
  var n = 999;
  function f2(){
    console.log(n);
  }
  return f2;
}

var result = f1();
result();//999

2、函数作为参数

var n = 999;

function f1(){
  var n = 1000;
  function f2(){
    console.log(n);
  }
  return f2
}

function f3(p){
  var n = 1001;
  p();
}

f3(f1());//1000

3、IIFE(自执行函数)

var n = 999;
(function f1(){
  console.log(n);
})()
//999

上边的代码中f1( )是一个闭包,调用了全局变量n(即调用了window下的变量n);

4、循环赋值

for(var i = 0; i<10; i++){
  (function(j){
    setTimeout(function(){
      console.log(j);
    },1000)
  })(i)
}
//0,1,2,3,4,5,6,7,8,9依次打印

5、使用回调函数就是在使用闭包

window.n = 999;
setTimeout(function f1(){
  console.log(window.n);
},1000)

6、将外部函数创建的变量值始终保持在内存中;

可以看下下面这段代码:

function f1(){
  var n = 999;
  function f2(){
    console.log(n++);
  }
  result f2
}
var result = f1();
result();//1000

上边代码中f1的内部变量n一直存在内存中,不会在f1调用结束后被自动清除。 再看另一段代码:

function f1(){
  var n = 999;
  nAdd = function(){
    n+=1;
  }
  function f2(){
    console.log(n);
  }
  result f2
}

var result = f1();
result();//999
nAdd();
result();//1000

上边代码中函数f1的返回值赋值给了全局变量result,函数f1的返回值实际上就是f2函数,可以理解为f2被赋值给了全局变量result,这就导致了f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束之后,被垃圾回收机制(GC机制)回收,所有很容易造成内存泄漏

内存泄漏,就是一些你访问不到或用不到的变量,还占据着内存空间,不能被再次利用起来。

7、封装对象的私有对象和私有方法;

var Counter = (function(){
   var privateCounter = 0;
   return function changeBy(val){
     privateCounter += val;
   }
   return {
     increment:function(){
       changeBy(1);
     },
     decrement:function(){
       changeBy(-1);
     },
     value:function(){
       return privateCounter;
      }
   }
 })();

console.log(Counter.value());//0
Counter.increment();
Counter.increment();
console.log(Counter.value());//2
Counter.decrement();
console.log(Counter.value());//1

三、 使用闭包需要注意什么?

因为使用闭包会包含其他函数的作用域,会比其他函数占据更多的内存空间,不会在调用结束之后被垃圾回收机制(简称GC机制)回收,多度使用闭包会过度占用内存,造成内存泄漏。

四、闭包相关的面试题

1、简述什么是闭包,闭包的作用是什么?写出一个简单的闭包例子。

2、闭包会造成内存泄漏吗?

会,因为使用闭包会包含其他函数的作用域,会比其他函数占据更多的内存空间,不会在调用结束之后被垃圾回收机制回收,过度使用闭包会过度占用内存,造成内存泄漏。

3、for循环和闭包(必刷题)

var data = [];

for(var i = 0; i < 3; i++){
  data[i] = function (){
  console.log(i);
  };
}

data[0]();//3
data[1]();//3
data[2]();//3

上边代码的变量i属于一个全局变量,公用一个作用域,所有输出是3个3; 使用闭包改善上边的写法达到预期的效果:

var data = [];
for(var i = 0; i < 3; i++){
  (function(j){
    setTimeout(data[j] = function(){
    console.log(j);
    },0)
  })(i)
}
data[0]();
data[1]();
data[2]();

4、请写出以下代码的输出结果:

第一题4-1:

var n = 10;
function f1(){
  var n = 20;
  function f2(){
    n++
    console.log(n);
  }
  f2();
  return f2
}

var result = f1();//21
result();//22
result();//23
console.log(n);//10

第二题4-2:

function makeAdder(x){
  return function(y){
    return x+y;
  }
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2));//7
console.log(add10(2));//12

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值