前端面试题:闭包_前端设计模式面试题

前端面试题:闭包_前端设计模式面试题前段时间一直在投一些中小型公司吧,感觉好久都收不到反馈,也不知道是被淘汰了还是没出结果呢,最近开始投一些大一点的公司准备尝试一下,就在昨天接到面试电话的时候,接受到了滴滴的毒打。跟一些面试不一样的是不只是一些基础的基本概念吧,比如说什么是原型和原型链,说一下继承,讲一下this指向之类的。更多的是为什么要这样用,手写算法,预测输出结果之类的面试题。印象最深刻的应该就是那道关于闭包的题目了吧,是预测一个程序的输出结果,当时看的我是晕头转向,大厂的面试也是招架不住,真的是把我给面到自闭,感觉自己啥也不是,估

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前段时间一直在投一些中小型公司吧,感觉好久都收不到反馈,也不知道是被淘汰了还是没出结果呢,最近开始投一些大一点的公司准备尝试一下,就在昨天接到面试电话的时候,接受到了滴滴的毒打。跟一些面试不一样的是不只是一些基础的基本概念吧,比如说什么是原型和原型链,说一下继承,讲一下this指向之类的。更多的是为什么要这样用,手写算法,预测输出结果之类的面试题

印象最深刻的应该就是那道关于闭包的题目了吧,是预测一个程序的输出结果,当时看的我是晕头转向,大厂的面试也是招架不住,真的是把我给面到自闭,感觉自己啥也不是,估计不用等结果直接就知道自己已经凉了。今天一天也没有接到面试,同样也没有约到面试机会。

所以就索性去学了一下关于闭包的知识,也算是给自己补补洞吧,同样还是老规矩把学习的东西记录分享出来,分享之前还是看一下昨天那道题目。

面试题

—————————————————正经分界线———————————————————

 什么是闭包

要理解闭包就要去理解变量的作用域,在JS中存在两种变量的作用域,一种是全局变量,一种是局部变量。两种变量的区别就是函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。

那什么是闭包呢?闭包是指有权访问另外一个函数作用域中的局部变量的函数。声明在一个函数中的函数,叫做闭包函数。而且内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

闭包的特点

1、让外部访问函数内部变量成为可能

2、局部变量会常驻在内存中

3、可以避免使用全局变量,防止全局变量污染

4、会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,并且互不干扰。闭包会发生内存泄漏,每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。但凡是当前活动对象中有被内部子集引用的数据,那么这个时候,这个数据不删除,保留一根指针给内部活动对象。大概意思就是说当外部函数运行结束甚至销毁时,局部的变量key=value,尽管key被垃圾回收机制给回收了,但是value仍不会被回收,会变成一个自由变量留下引用的指针。

这一天也是看了不少的例子,还是有一些没理解清楚的,回来理解一下再过来更新,还是先把我理解了的分享出来,记录讲解一下我的理解。

例子1

var age = 10;
function foo(){
    console.log(age);//-----------------1
	var name = "hunt_bo";
	return function(){
		console.log(name);
	}
}
console.log(name);//---------------2
var bar = foo();
bar();

这个应该说是最简单的一个闭包的例子了,那就用他来介绍一下闭包的基本概念,首先呢是函数内部肯定是可以访问到全局变量的值的,所以在foo()函数中去打印age肯定是可以打印出来的,就像代码中的标记1,但是呢在标记2处打印的函数内部的变量name是打印不出来的。

但是当我们用到闭包的时候,在foo函数内部返回一个函数,在返回的函数中去用到局部变量name,最后呢在外部调用,这时候的bar仍然在函数外部,但是完全可以拿到局部变量的name值。这就是闭包的定义吧,同样呢也是闭包的第一个特点。

例子2

function addCount(){
	var count = 0;
	return function(){
		count += 1;
		console.log(count);
	}
}
var fun1 = addCount();
var fun2 = addCount();
fun1();//1
fun1();//2
fun1();//3
fun2();//1
fun2();//2

这个例子呢,跟第一个也算是差不多的,就是在返回函数中做了一个递增并打印的操作,把addCount的返回函数给到fun1和fun2,当我向上面代码一样调用的时候呢,就会发现替他打印的不是12345,而是12312,那这是什么原因呢,这就回到了上边介绍的那句话:每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。所以说虽然fun1和fun2都是addCount(),但是呢都创建了新地址,都是自己的,互不干扰。

例子3

var i = 0;
function outerFn(){
	function innerFn(){
		i++;
		console.log(i);
		}
	return innerFn
}
var inner1 = outerFn();
var inner2 = outerFn();
inner1();//1
inner2();//1
inner1();//2
inner1();//3
inner2();//2
inner2();//3

这个跟例子2是一样的道理,只是变量的位置不一样,但是呢,对于内部的innerFn来说,变量是外部函数的局部变量和全局变量来说都是一样的,就不过多的解释了。

例子4

function fn(){
	var a = 3;
	return function(){
		return ++a;
	}
}
console.log(fn()());//4
console.log(fn()());//4
console.log(fn()());//4
var newFn = fn();
console.log(newFn());//4
console.log(newFn());//5
console.log(newFn());//6

还是一样的,相当于fn()()的直接调用都是在开辟一个新的地址,但是把它赋给一个变量的时候,地址就不会再改变了,这个时候就会发现输出只是在递增的。

例子5

(function() { 
  	var m = 0; 
  	function getM(){ 
  		return m; 
  	}
  	function seta(val){
  		m = val;
  	}
  	window.g = getM;
  	window.f = seta;
})();
f(100);
console.log(g());//100

(function(){ /* code */ })()是立即执行函数,当js执行到(function {// code})();时, 由于(function {// code})是表达式, js会去对它求解得到返回值, 由于返回值是一个函数, 故而遇到()时, 便会被执行。然后把getM和seta给到了window,这时候呢,我想到了大佬总结的一句话:闭包找到的是同一地址中父级函数中对应变量最终的值。

例子6

var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
  	(function(i){
      	 lis[i].onclick = function(){
           	  console.log(i);
      	 };
  	})(i);
}

这个呢是在事件处理中闭包的应用,也就是说我们按照传统的思想去写的话,相信我,不管点击第几个都会给你打印5的,但是闭包处理过的就可以实现我们想要的功能。

说句题外话就是在现实应用中我是不会这样用,let它不香么,这么复杂。

再来最后一个例子吧,就是我在面试中面试官给我的那道题:

function fnnn(){
   	var arr = [];
   	for(var i = 0;i < 5;i ++){
		arr[i] = function(){
			return i;
	 	}
   	}
   	return arr;
}
var list = fnnn();
for(var i = 0,len = list.length;i < len ; i ++){
   console.log(list[i]());
}

这个题我刚开始看的时候吧,感觉就是一个简单的函数的数组,当时想都没想,直接就说了12345,但是当时没有看清楚var定义的i,在函数中直接返回,在调用的时候i早就变成5了呀,然而现在已经晚了,继续准备后面的面试吧。

忙了一天,就为了这一篇博客,生气

前端面试题:闭包_前端设计模式面试题前端面试题:闭包_前端设计模式面试题

当我去搜闭包为什么会造成内存泄漏的时候,突然在知乎上发现了一篇帖子,关于js闭包是否真的会造成内存泄漏?大家可以去看一下,感觉挺有趣的,不过真的把我搞蒙了,到底会不会造成内存泄漏。

咱也不知道咱也不敢问啊

在学习的过程中也是参考了不少大佬的博客文章,感觉我写的太菜的话,建议大家去这几篇博客学习一下,因为我是从这些文章里看懂的,理解的闭包。

什么是闭包?闭包的优缺点?

什么是闭包?闭包的作用,用法及优缺点

闭包与自执行函数 区别

闭包,看这一篇就够了——带你看透闭包的本质,百发百中

JavaScript内存泄露,闭包内存泄露如何解决

闭包

春招在即,面试不慌:带你复习什么是闭包

闭包-廖雪峰的官方网站

关于js闭包是否真的会造成内存泄漏?

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/174499.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 请问IOS中做一个手机网站的app壳复杂吗?

    请问IOS中做一个手机网站的app壳复杂吗?

    2021年11月17日
  • Spring常用注解

    Spring常用注解

  • vue调用js文件_vue调用其他js文件中的方法

    vue调用js文件_vue调用其他js文件中的方法本文主要介绍了vue引用js文件的多种方式,本文大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 1、vue-cliwebpack全局引入jquery(1)首先npminstalljquery–save(–save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖。)(2)在webpack.base.conf.js里加入varwebpack=require(“webpack”)(3)在module

  • 线程、多线程与线程池面试题

    线程、多线程与线程池面试题●概念线程:进程中负责程序执行的执行单元。一个进程中至少有一个线程。多线程:解决多任务同时执行的需求,合理使用CPU资源。多线程的运行是根据CPU切换完成,如何切换由CPU决定,因此多线程运行具有不确定性。线程池:基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对…

  • java反射的原理,作用

    什么是反射,反射原理Java反射的原理:java类的执行需要经历以下过程,编译:.java文件编译后生成.class字节码文件加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例连接:细分三步验证:格式(class文件规范)语义(final类是否有子类)…

  • Python 学习笔记 – Paramiko 模块

    Python 学习笔记 – Paramiko 模块

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号