JS面试题---闭包相关的题

(1)说说你对闭包的理解

使用闭包主要是为了设计私有的方法和变量。

闭包的优点是可以避免全局变量的污染,实现属性私有化

闭包的缺点:闭包会常驻内存,增加内存使用量,使用不当容易造成内存泄漏 (因此在不用的时候需要删除)

闭包的特性:①函数嵌套函数②函数内部可以引用外部的参数和变量③参数和变量不会以垃圾回收机制回收

 

(2)看以下这段代码并回答以下问题

for(var i=0;i<5;i++){
  var btn = document.createElement("button");
  btn.appendChild(document.createTextNode("Button "+i));
  btn.addEventListener('click',function(){
     console.log(i);
})

   document.body.appendChild(btn);
}

 ①当用户单击“Button 4”的时候,控制台会输出什么???

    答:无论用户点击哪个button,控制台会输出数字5。因为当调用onclick方法的时候,for循环已经结束,变量i的值已经为5。

②提供一个或者多个可获取当前i的值的实现方案

方案一:使用闭包实现

for(var i=0;i<5;i++){
  var btn = document.createElement("button");
  btn.appendChild(document.createTextNode("Button "+i));
  btn.addEventListener('click',(function(i){  //这里使用了闭包,将循环变量存储了
	  return function(){
		  console.log(i);
	  }
  })(i));

方案二:使用ES6语法

for(let i=0;i<5;i++){   //这里使用了let  let具备块级作用域
  var btn = document.createElement("button");
  btn.appendChild(document.createTextNode("Button "+i));
  btn.addEventListener('click',function(){
 console.log(i);
});

 document.body.appendChild(btn);

}

方案三:封装全部调用到新的匿名函数中

	for(var i=0;i<5;i++){
  var btn = document.createElement("button");
  btn.appendChild(document.createTextNode("Button "+i));
  (function(){
	  btn.addEventListener('click',function(){
		  console.log(i);
	  });
  })(i);
   document.body.appendChild(btn);
}

(3)什么是闭包?

为说明闭包,创建一个闭包

function hello(){
  //函数执行完毕,变量仍然存在
  var num = 100;
  var showResult = function(){
  alter(num);
}
  num++;
  return showResult;

}

var showResult=hello();
showResult();//执行结果,弹出101

执行hello()后,hello闭包内部的变量会存在,而闭包内部函数变量不会存在。使得JS的垃圾回收机制不会回收hello()占用的资源,因为hello内部函数执行的时候需要依赖hello()中的变量。

 

(4)以下代码将输出什么?闭包在这里能起什么作用?

for(var i=0;i<5;i++){
	(function(){
		setTimeout(function(){console.log(i)},i*100);
	})();
}

将输出5,5,5,5,5 而不是0,1,2,3,4

原因是每个函数先将循环执行完之后,再执行循环体中的函数(跟函数的调用,事件的执行有关),因此就会引用存储在i中的最后一个值 5

闭包可以为每次迭代创建一个唯一的作用域。存储作用域内的循环变量。

for(var i=0;i<5;i++){
	(function(i){
		setTimeout(function(){console.log(i)},i*100);
	})(i);
}

这样就可以输出0,1,2,3,4

(5)下列的递归代码在数组列表偏大的情况下会导致堆栈溢出,在保留原递归模式的基础上,怎么解决这个问题?

var list = readHugeList();
var nextListItem = function(){
	var item = list.loop();
	it(item){
		nextListItem();
	}
}

改为以下代码:

var list = readHugeList();
var nextListItem = function(){
	var item = list.loop();
	it(item){
		setTimeout(nextListItem(),0); //事件循环操纵递归
	}
}

之所以堆栈溢出会被消除,是因为事件循环操纵了递归,而不是调用堆栈。该方法从头到尾都没有直接递归调用,所以无论迭代多少次,调用堆栈一直保持清空的状态。

(6)看下一段代码,控制台会输出什么?为什么?

(function(x){
	return (function(y){console.log(x)})(2);
})(1);

控制台会输出1。因为这里创建了闭包,闭包可以访问外部函数的变量和参数。

(7)输出什么?

const add = () => {
  const cache = {};
  return num => {
    if (num in cache) {
      return `From cache! ${cache[num]}`;
    } else {
      const result = num + 10;
      cache[num] = result;
      return `Calculated! ${result}`;
    }
  };
};

const addFunction = add();
console.log(addFunction(10));
console.log(addFunction(10));
console.log(addFunction(5 * 2));

Calculated! 20 From cache! 20 From cache! 20

分析:add函数是一个记忆函数。 通过记忆化,我们可以缓存函数的结果,以加快其执行速度

如果我们使用相同的参数多次调用addFunction函数,它首先检查缓存中是否已有该值,如果有,则返回缓存值,这将节省执行时间。如果没有,那么它将计算该值,并存储在缓存中。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值