一篇常做错的经典JS闭包面试题
作者 | Jeskson
来源 | 达达前端小酒馆
1
究竟是怎么样的一道面试题,能让我拿出来说说呢?下面请看代码:
function fun(a,b) {
console.log(b)
return {
fun: function(c) {
return fun(c,a);
}
};
}
var d = fun(0); d.fun(1); d.fun(2);
d.fun(3);
var d1 = fun(0).fun(1).fun(2).fun(3);
var d2 = fun(0).fun(1);
d2.fun(2);
d2.fun(3);
function fun(a,b) {
console.log(b)
return {
fun: function(c) {
return fun(c,a);
}
};
}
var d = fun(0); d.fun(1); d.fun(2);
d.fun(3);
var d1 = fun(0).fun(1).fun(2).fun(3);
var d2 = fun(0).fun(1); d2.fun(2);
d2.fun(3);
undefined
VM1036:2 0
VM1036:2 0
VM1036:2 0
VM1036:2 undefined
VM1036:2 0
VM1036:2 1
VM1036:2 2
VM1036:2 undefined
VM1036:2 0
VM1036:2 1
VM1036:2 1
{fun: ƒ}
//答案:
//undefined,0,0,0
//undefined,0,1,2
//undefined,0,1,1
JS函数分两种:具名函数(命名函数)和匿名函数。
如何判断两种函数的方法呢?
可以用fn.name来判断,如果有name就是具名函数,如果没有name就是匿名函数。
需要注意的是在IE浏览器上无法获取具名函数的name,会返回undefined的结果,而在谷歌浏览器上就可以获取。
// 获取名称
function getFunctionName(fun){
if(fun.name !== undefined)
return fun.name;
var funName = fun.toString();
funName = funName.substr('function '.length);
funName = funName.substr(0, funName.indexOf('('));
return funName;
}
2
函数创建的方法有哪些?
第一种是:声明函数,声明函数方法,包括函数名和函数体。
function funDa() {}
第二种是:创建匿名函数的表达式。
创建一个变量,这个变量的内容是一个函数,为匿名函数
var funDa = function() {}
这样这个函数就没有了name
var funDa = function(){}
getFunctionName(funDa).length;
// 0
第三种是:创建具名函数表达式。
var funDa = function dada(){};
创建一个变量,变量赋值的内容为一个带有名称的函数。具名函数表达式的函数名只能在创建函数内部使用,函数的外层只能使用funData,dada函数名只能在创建函数内部使用。
在对象内定义函数,也是属于函数表达式。
第四种是:Function构造函数
Function("alert(1)");
ƒ anonymous() {
alert(1)
}
Function("dada");
ƒ anonymous() {
dada
}
new Function("alert(1)");
ƒ anonymous() {
alert(1)
}
new Function("dada");
ƒ anonymous() {
dada
}
Function构造函数传一个函数字符串,返回包含这个字符串命令的函数。
第五种是:自执行函数
( function(){
alert(1);
})();
undefined
( function(){
alert(1);
})
ƒ (){
alert(1);
}
(function da1(){
alert(1);
})();
自执行函数也是“函数表达式”。
第六种是:其他
运用eval,setTimeout,setInterval等方法。
3
第一个fun函数是属于标准的具名函数声明,是新创建的函数,返回的是一个对象字面量表达式,属性一个新的Object。
这返回,对象内部包含一个fun的属性,属于匿名函数表达式,这个fun属性存放的是一个新创建匿名函数表达式,所有声明的匿名函数都是一个新函数。则第一个fun函数和第二个fun函数不同,都是新创建的函数。
4
函数作用域链的问题
对象内部的函数表达式:
var d = {
fn: function(){
console.log(fn);
}
};
d.fn();
VM1879:3 Uncaught ReferenceError: fn is not defined
at Object.fn (<anonymous>:3:21)
at <anonymous>:6:3
fn @ VM1879:3
(anonymous) @ VM1879:6
var d1 = {
fn: function(){
console.log("dada");
}
};
d1.fn();
VM1973:3 dada
undefined
非对象内部的函数表达式:
var da = function () {
console.log(da);
};
da();
VM2270:2 ƒ () {
console.log(da);
}
undefined
使用var可以访问到存放当前函数的变量,var da,da()访问函数的变量,在对象内部不能访问到。
5
函数作用域链:
function fun(a,b) {
console.log(b)
return {
fun: function(c) {
return fun(c,a);
}
};
}
var d = fun(0); d.fun(1); d.fun(2);
d.fun(3);
var d1 = fun(0).fun(1).fun(2).fun(3);
var d2 = fun(0).fun(1); d2.fun(2);
d2.fun(3);
var d = fun(0);
d.fun(1);
d.fun(2);
d.fun(3);
undefined
VM2273:2 0
VM2273:2 0
VM2273:2 0
第一个fun(0)在调用第一层fun函数,第二个fun(1)是在调用前一个fun的返回值的fun函数。即就是fun(1),fun(2),fun(3)函数独使在调用第二层fun函数,第一次调用fun(0)时,b为undefined,第二次调用fun(1),c为1,a为0。
var d = fun(0);调用的是第一层
而d.fun->fun(0).fun调用第二层
fun:function(1),return fun(1,a),fun(1,0),此时fun闭包了外层函数的a,也就是第一次调用的a=0。这样子第一层fun函数为fun(1,0),所以为0。
第一次:
function fun(0,undefined) {
console.log(undefined)
return {
fun: function(c) {
return fun(c,0);
}
};
}
fun(0),b为undefined,fun(0).fun(1),c=1,此时fun闭包外层函数的a,也就是第一次调用的a=0,即c=1,a=0,并在内部调用第一层fun函数fun(1,0),所以b=0。
function fun(a,b) {
console.log(b)
return {
fun: function(1) {
return fun(1,0);
}
};
}
第三次调用fun(2)时,c为2,还是调用d.fun,还是闭包了第一次调用时的a,fun(2,0)所以输出b为0。
function fun(a,b) {
console.log(b)
return {
fun: function(c) {
return fun(c,a);
}
};
}
var d = fun(0); d.fun(1); d.fun(2); d.fun(3);
6
var d1 = fun(0).fun(1).fun(2).fun(3);
从fun(0)调用第一层fun函数,返回值为一个对象,第二个fun(1)调用的是第二层fun函数,后面的也是第二层fun函数。
第一层fun(0),b为undefined,第二层.fun(1)时c为1,c=1,a=0,内部调用第一层fun函数fun(1,0),所以b为0。
调用你.fun(2)时,c为2,此时当前的fun函数不是第一次执行的返回对象,而是第二次执行的返回对象,第二次执行第一层fun函数是:
fun(1,0),a=1,b=0。第三次执行fun函数,c=2,a=1
function fun(a,b) {
console.log(b)
return {
fun: function(1) {
return fun(1,0);
}
};
}
fun(1,0),a=1,b=0。第三次执行fun函数,c=2,a=1
function fun(a,b) {
console.log(b)
return {
fun: function(2) {
return fun(2,1);
}
};
}
// 1
function fun(2,1) a=2, b=1
第四次调用.fun(3)为c为3
// a=2
function fun(a,b) {
console.log(b)
return {
fun: function(3) {
return fun(3,2);
}
};
}
7
var d2 = fun(0).fun(1);
d2.fun(2);
d2.fun(3);
var d2=fun(0).fun(1);
// undefined, 0
此时的return(c=1,a=0),return fun(1,0),所以b为0
d2.fun(2);
第三次调用.fun(2),c为2
// c为2,a=1,b=0
function fun(a,b) {
console.log(b)
return {
fun: function(2) {
return fun(2,a);
}
};
}
所以return fun(2,1)
function fun(a=2,b=1),所以为 1
d2.fun(3),c为3,还是调用的第二次的返回值,最终调用第一层的
fun(a,b)
// c为3,a=1,b=0
function fun(a,b) {
console.log(b)
return {
fun: function(3) {
return fun(3,a);
}
};
}
所以return fun(3,1)
function fun(a=3,b=1),所以为 1
注意这里的:
// c为3,a=1,b=0
这是调用这个代码的结果
a=1,b=0
var d2 = fun(0).fun(1);
好了,这样就知道大概的答案和讲解了:
8
总的来说,你明白了!讲的好辛苦,给个赞哦!求奖励,我来了
function fun(a,b) {
console.log(b)
return {
fun: function(c) {
return fun(c,a);
}
};
}
var d = fun(0); d.fun(1); d.fun(2);
d.fun(3);
var d1 = fun(0).fun(1).fun(2).fun(3);
var d2 = fun(0).fun(1); d2.fun(2);
d2.fun(3);
undefined
VM1036:2 0
VM1036:2 0
VM1036:2 0
VM1036:2 undefined
VM1036:2 0
VM1036:2 1
VM1036:2 2
VM1036:2 undefined
VM1036:2 0
VM1036:2 1
VM1036:2 1
{fun: ƒ}
一名喜爱编程技术与专注于前端的程序员,将web前端领域、数据结构与算法、网络原理等通俗易懂的呈现给小伙伴。分享web前端相关的技术文章、工具资源,精选课程、热点资讯。
推荐阅读
1、你知道多少this,new,bind,call,apply?那我告诉你
2、为什么学习JavaScript设计模式,因为它是核心
3、一篇文章把你带入到JavaScript中的闭包与高级函数
4、大厂HR面试ES6中的深入浅出面试题知识点
❤️ 不要忘记留下你学习的脚印 [点赞 + 收藏 + 评论]
作者Info:
【作者】:Jeskson
【原创公众号】:达达前端小酒馆。
【福利】:公众号回复 “资料” 送自学资料大礼包(进群分享,想要啥就说哈,看我有没有)!
【转载说明】:转载请说明出处,谢谢合作!~
大前端开发,定位前端开发技术栈博客,PHP后台知识点,web全栈技术领域,数据结构与算法、网络原理等通俗易懂的呈现给小伙伴。谢谢支持,承蒙厚爱!!!
若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。
请点赞!因为你们的赞同/鼓励是我写作的最大动力!
欢迎关注达达的CSDN!
这是一个有质量,有态度的博客
一篇常做错的经典JS闭包面试题的更多相关文章
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- 经典JS闭包面试题(来理解闭包)(转)
转载地址:http://www.cnblogs.com/xxcanghai/p/4991870.html 先看代码: function fun(n,o) { console.log(o) return ...
- 面试题常考&必考之--js闭包特性和优缺点 (外加小例子)
当内部函数被返回到外部并保存时,一定会产生闭包.闭包会产生原来的作用域链,不释放. 闭包,可以理解为,写一个函数,然后产生闭包的这种现象. 概念: 基础: 主要是:add reduce 被返回 ...
- javascript深入理解js闭包(转)
javascript深入理解js闭包 转载 2010-07-03 作者: 我要评论 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...
- 一道经典JS面试题
超过80%的候选人对下面这道JS面试题的回答情况连及格都达不到.这究竟是怎样神奇的一道JS面试题?他考察了候选人的哪些能力?对正在读本文的你有什么启示? 不起眼的开始 招聘前端工程师,尤其是中高级前端 ...
- web报表工具FineReport使用中遇到的常见报错及解决办法(二)
web报表工具FineReport使用中遇到的常见报错及解决办法(二) 这里写点抛砖引玉,希望大家能把自己整理的问题及解决方法晾出来,Mark一下,利人利己. 出现问题先搜一下文档上有没有,再看看度娘 ...
- java常见报错及解决
Java常见报错信息: Java 常见异常种类 Java Exception: 1.Error 2.Runtime Exception 运行时异常 3.Exception 4.throw 用户自定 ...
- 03:git常见报错解决方法
1.1 git常见报错解决方法 1.warning: LF will be replaced by CRLF in .idea/workspace.xml. 参考博客:https://www.cnbl ...
- Django 连接 MySQL 数据库及常见报错解决
目录 Django 连接 MySQL数据库及常见报错解决 终端或者数据库管理工具连接 MySQL ,并新建项目所需数据库 安装访问 MySQL 的 Python 模块 Django 相关配置 可能会遇 ...
随机推荐
- C#简单构架之EF进行读写分离+多数据库Mysql/SqlServer
http://www.php361.com/index.php?c=index&a=view&id=3857 不建议用,太重的框架EF,仅仅参考一下别人的思路就好. [导读]最近因为项 ...
- #define宏作用
预处理器的任务 简单来讲,预处理器的任务就是执行源代码中的预处理指令,并对源代码进行相应的处理.因此,从预处理指令的类型来讲,预处理器的任务包括如下的几个部分: 将其他文件包含到当前文件中. 定义宏, ...
- MFC 解决绘图时闪烁问题的一点经验
2015-05 由于作图过于复杂和频繁,所以时常出现闪烁的情况,一些防止闪烁的方法,如下: (1)将Invalidate()替换为InvalidateRect(). Invalidate()会导致整个 ...
- HTML5深入学习之数据存储
概述 本来,数据存储都是由 cookie 完成的,但是 cookie 不适合大量数据的存储,cookie 速度慢且效率低. 现在,HMLT5提供了两种在客户端存储数据的办法: localStorage ...
- 16. Promise对象
目录 Promise对象 一.含义 1. Promise是什么 2. 实例讨论 二.Promise特性案例解析 1. Promise的立即执行性 2. promise的三种状态 3. Promise的 ...
- Flink Time深度解析(转)
Flink 的 API 大体上可以划分为三个层次:处于最底层的 ProcessFunction.中间一层的 DataStream API 和最上层的 SQL/Table API,这三层中的每一层都非常 ...
- 标准库中的装饰器 lru_cache和全新的 singledispatch
Python 内置了三个用于装饰方法的函数:property.classmethod 和 staticmethod. 另一个常见的装饰器是 functools.wraps,它的作用是协助构建行为 良好 ...
- Detectron2源码阅读笔记-(一)Config&Trainer
代码结构概览 核心部分 configs:储存各种网络的yaml配置文件 datasets:存放数据集的地方 detectron2:运行代码的核心组件 tools:提供了运行代码的入口以及一切可视化的代 ...
- P2220 [HAOI2012]容易题[小学数学]
题目描述 为了使得大家高兴,小Q特意出个自认为的简单题(easy)来满足大家,这道简单题是描述如下: 有一个数列A已知对于所有的A[i]都是1~n的自然数,并且知道对于一些A[i]不能取哪些值,我们定 ...
- Beta冲刺阶段博客集合
Beta冲刺阶段博客集合 课程名称:软件工程1916|W(福州大学) 团队名称: 云打印 作业要求: 项目Beta冲刺(团队) 作业目标:作业集合 团队队员 队员学号 队员姓名 个人博客地址 备注 2 ...