每个 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);
答案
clickHandler
能够从外部作用域访问变量countClicks
。immediate
无法访问外部作用域中的任何变量。delayedReload
从全局作用域(也就是最外层作用域)中访问全局变量location
。
2. 丢失的参数
答案
输出为: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. 棘手的闭包
下列代码输出什么:
答案
输出:3
, 3
, 3
。
阶段1
for()
重复 3 次。在每次循环都会创建一个新函数log()
,该函数将捕获变量i
。setTimout()
安排log()
在 1000 毫秒后执行。- 当
for()
循环完成时,变量i
的值为3
。
阶段2
所以输出 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. 重新封装
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. 智能乘法
要求:
如果用 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
答案
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
变量。
总结
原文链接:
这 7 道关于闭包的面试题,你能答对几个?
作者:疯狂的技术宅
原文地址:https://blog.csdn.net/Cangjie627/article/details/125331056
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_14051.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!