作为js开发,必须知道闭包是什么。在前端面试中,很可能会被问到闭包的概念。
我整理了7个有趣且比较有难度的问题。
准备好一只笔和一张纸,尽量不看答案或者敲代码运行。我估算你大概需要30分钟。
尽情开始吧!
如果你需要学习闭包,我推荐看闭包简单的例子
目录
1、哪个是闭包
2、参数问题
3、谁的谁
4、棘手的闭包
5、消息对还是错
6、恢复封装
7、智能相乘
小结
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);
问题:以上哪个是闭包以及为什么?
答案:
判断是否是闭包的简单规则就是,一个函数是否能访问外部函数的变量
1、clickHandler函数是闭包,因为它能访问外部的countCLicks。
2、immediate函数不是闭包,因为它没有访问到外部的任何一个变量。
3、delayedReload函数是闭包,因为它访问到全局变量location,也就是最顶层的函数域。
2、 参数问题
以下代码打印出什么?
(function immediateA(a) {
return (function immediateB(b) {
console.log(a); // 打印出什么
})(1);
})(0);
答案:
打印出 0
因为immediateA函数的参数是0,因此传输给a为0.
然后immediateB又是在immediateA的函数里,而且它是一个闭包的,所以immediateB里的a能访问到外面immediateA的a,所以打印出 0
3: 谁的谁
以下的代码块打印出什么
let count = 0;
(function immediate() {
if (count === 0) {
let count = 1;
console.log(count); // What is logged?
}
console.log(count); // What is logged?
})();
答案:
打印出 1 和 0
因为一开头声明了count = 0,然后在immediaye函数是一个闭包,因为它的count能访问到一开头声明的那个count,所以此时count是0,然后在条件块上,因为满足count===0的条件,所以进入条件块里,然后因为let具有块级作用域,所以用let声明count时,此时的count为1,所以第一个console.log(count)打印出1
第二个console.log(count)因为是在immediate函数里,而count是会访问到外部的count,也就是一开头声明的那个count,所以为0
4: 棘手的闭包
以下的代码块打印出什么
for (var i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // What is logged?
}, 1000);
}
答案:
打印出 3,3,3 该代码块执行有两个阶段: 阶段一: 1、for循环有3次,每次循环时都会创建一个新的log函数,而log函数里的setTimeout()是在1000ms后开始执行的。 2、循环完成后,i就变成3,而setTimeout还没开始执行的。 阶段二: 第二个就是发生在1000ms后: 1、setTimeou()就开始执行的,因为是闭包的,所以里面的i能访问到外部的i,而外部的i此时就是3,所以打印出3,之后的setTimeou也是如此的。 这就是为什么打印出3,3,3的原因。
挑战另一个问题:如何让这个代码块打印出0,1,2?请在下面的评论写下你的答案。
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(); // What is logged?
答案:
打印出 Count is 0 increment被调用3次,每次count都+1,3次后就成为3. message变量是在createIncrement函数内,它的初始化是“count is 0"。然而,即使count增加1,message始终保持“count is 0" log函数是一个闭包,它能访问到外部的message,所以打印出“count is 0"
挑战另一个问题:如何让message同步显示count的数?请在下面的评论写下你的答案。
6、恢复封装
createStack函数创建stack的实例:
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属性被暴露了,所以任何人能直接修改这个属性。
这确实会破坏stack的封装,按理来说应该只有push和pop方法被公开的,而items就不应该被公开的。
利用闭包的概念来重构上面的createStack函数,实现items不能被初createStack函数之外访问。
function createStack() {
// 写下你的代码
}
const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5
stack.items; // => undefined
答案:
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
7、智能相乘
在multiply函数内,写下两个数相乘。
function multiply(num1, num2) {
// Write your code here...
}
如果multiply有两个参数,则返回两个参数相乘的结果
如果multiply只有一个参数,比如说const anotherFunc = multiply(num1),则返回anotherFunc函数,然后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
小结
对比你的答案:
1、如果正确有5个以及以上,说明你的理解能力强;
2、如果没达到,我推荐你看看闭包的例子
还想挑战吗?来试试这个7个比较难的js面试题
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!