共计 4089 个字符,预计需要花费 11 分钟才能阅读完成。
每个 JavaScript 程序员都必须晓得闭包是什么。在 JavaScript 面试中,你很可能会被问到闭包的概念。
以下是 7 个无关 JavaScript 闭包的面试题,比拟有挑战性。
不要查看答案或运行代码,看看本人的程度到底如何。做完这些题大概须要半小时左右。
1. 热身
有以下函数 clickHandler
,immediate
和delayedReload
:
let countClicks = 0;
button.addEventListener('click', function clickHandler() {countClicks++;});
const result = (function immediate(number) {const message = `number is: ${number}`;
return message;
})(100);
setTimeout(function delayedReload() {location.reload();
}, 1000);
这 3 个函数中哪个可能拜访内部范畴变量?
答案
clickHandler
可能从内部作用域拜访变量countClicks
。immediate
无法访问内部作用域中的任何变量。delayedReload
从全局作用域(也就是最外层作用域)中拜访全局变量location
。
2. 失落的参数
下列代码输入什么:
(function immediateA(a) {return (function immediateB(b) {console.log(a); // => ?
})(1);
})(0);
答案
输入为:0
用参数 0
调用 immediateA
,因而 a
参数为 0
。
immediateB
函数嵌套在 immediateA
函数中,是一个闭包,它从内部 immediateA
作用域中失去 a
变量,其中 a
为 0
。因而 console.log(a)
的输入为 0
。
3. 谁是谁
上面的代码将会输入什么内容?
let count = 0;
(function immediate() {if (count === 0) {
let count = 1;
console.log(count); // 输入什么?}
console.log(count); // 输入什么?})();
答案
输入 1
和 0
第一个语句 let count = 0
申明了一个变量 count
。
immediate()
是一个闭包,它从内部作用域失去 count
变量。在 immediate()
函数作用域内,count
是 0
。
然而,在条件内,另一个 let count = 1
申明了局部变量 count
,该变量笼罩了作用域之外的 count
。第一个 console.log(count)
输入 1
。
第二个 console.log(count)
输入为 0
,因为这里的 count
变量是从内部作用域拜访的。
4. 辣手的闭包
下列代码输入什么:
for (var i = 0; i < 3; i++) {setTimeout(function log() {console.log(i); // => ?
}, 1000);
}
答案
输入:3
, 3
, 3
。
代码分为两个阶段执行。
阶段 1
for()
反复 3 次。在每次循环都会创立一个新函数log()
,该函数将捕捉变量i
。setTimout()
安顿log()
在 1000 毫秒后执行。- 当
for()
循环实现时,变量i
的值为3
。
阶段 2
第二阶段产生在 1000ms 之后:
setTimeout()
执行预约的log()
函数。log()
读取变量i
以后的值3
,并输入3
所以输入 3
, 3
, 3
。
5. 谬误的信息
上面的代码将会输入什么:
function createIncrement() {
let count = 0;
function increment() {count++;}
let message = `Count is ${count}`;
function log() {console.log(message);
}
return [increment, log];
}
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // => ?
答案
输入:'Count is 0'
increment()
函数被调用 3 次,将 count
减少到 3
。
message
变量存在于 createIncrement()
函数的作用域内。其初始值为 'Count is 0'
。但即便 count
变量曾经减少了几次,message
变量的值也始终为 'Count is 0'
。
log()
函数是一个闭包,它从 createIncrement()
作用域中获取 message
变量。console.log(message)
输入录 'Count is 0'
到控制台。
6. 从新封装
上面的函数 createStack()
用于创立栈构造:
function createStack() {
return {items: [],
push(item) {this.items.push(item);
},
pop() {return this.items.pop();
}
};
}
const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5
stack.items; // => [10]
stack.items = [10, 100, 1000]; // 栈构造的封装被毁坏了
它能失常工作,但有一个小问题,因为裸露了 stack.items
属性,所以任何人都能够间接批改 items
数组。
这是一个大问题,因为它毁坏了栈的封装:应该只有 push()
和 pop()
办法是公开的,而 stack.items
或其余任何细节都不能被拜访。
应用闭包的概念重构下面的栈实现,这样就无奈在 createStack()
函数作用域之外拜访 items
数组:
function createStack() {// 把你的代码写在这里}
const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5
stack.items; // => undefined
答案
以下是对 createStack()
的重构:
function createStack() {const items = [];
return {push(item) {items.push(item);
},
pop() {return items.pop();
}
};
}
const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5
stack.items; // => undefined
items
已被移至 createStack()
作用域内。
这样批改后,从 createStack()
作用域的内部无法访问或批改 items
数组。当初 items
是一个公有变量,并且栈被封装:只有 push()
和 pop()
办法是公共的。
push()
和 pop()
办法是闭包,它们从 createStack()
函数作用域中失去 items
变量。
7. 智能乘法
编写一个函数 multiply()
,将两个数字相乘:
function multiply(num1, num2) {// 把你的代码写在这里...}
要求:
如果用 2 个参数调用 multiply(num1,numb2)
,则应返回这 2 个参数的乘积。
然而如果用 1 个参数调用,则该函数应返回另一个函数:const anotherFunc = multiply(num1)
。返回的函数在调用 anotherFunc(num2)
时执行乘法 num1 * num2
。
multiply(4, 5); // => 20
multiply(3, 3); // => 9
const double = multiply(2);
double(5); // => 10
double(11); // => 22
答案
以下是 multiply()
函数的一种实现形式:
function multiply(number1, number2) {if (number2 !== undefined) {return number1 * number2;}
return function doMultiply(number2) {return number1 * number2;};
}
multiply(4, 5); // => 20
multiply(3, 3); // => 9
const double = multiply(2);
double(5); // => 10
double(11); // => 22
如果 number2
参数不是 undefined
,则该函数仅返回 number1 * number2
。
然而,如果 number2
是 undefined
,则意味着曾经应用一个参数调用了 multiply()
函数。这时就要返回一个函数 doMultiply()
,该函数稍后被调用时将执行理论的乘法运算。
doMultiply()
是闭包,因为它从 multiply()
作用域中失去了number1
变量。
总结
如果你答对了 5 个以上,阐明对闭包把握的很好
如果你答对了不到 5 个,则须要好好的温习一下了。我倡议查看我的文章[JavaScript 闭包的简略阐明](https://dmitripavlutin.com/si…)。
本文首发微信公众号:前端先锋
欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章
欢送持续浏览本专栏其它高赞文章:
- 深刻了解 Shadow DOM v1
- 一步步教你用 WebVR 实现虚拟现实游戏
- 13 个帮你进步开发效率的古代 CSS 框架
- 疾速上手 BootstrapVue
- JavaScript 引擎是如何工作的?从调用栈到 Promise 你须要晓得的所有
- WebSocket 实战:在 Node 和 React 之间进行实时通信
- 对于 Git 的 20 个面试题
- 深刻解析 Node.js 的 console.log
- Node.js 到底是什么?
- 30 分钟用 Node.js 构建一个 API 服务器
- Javascript 的对象拷贝
- 程序员 30 岁前月薪达不到 30K,该何去何从
- 14 个最好的 JavaScript 数据可视化库
- 8 个给前端的顶级 VS Code 扩大插件
- Node.js 多线程齐全指南
- 把 HTML 转成 PDF 的 4 个计划及实现
- 更多文章 …