JS面试经典题
闭包经典题:
1.

执行结果:5 5 6 7 8 9
JS单线程执行机制问题:先执行执行栈中的同步任务,遇到异步函数就放入消息队列中等待,同步任务执行完毕,再按顺序将异步任务放入执行栈中继续进行。
执行栈内为同步任务即for循环的i++和log函数,将for循环内部的异步任务setTimeout放入消息队列,由于for循环则进行了五次内部的log(i++)放入消息队列中。
开始先从执行栈中进行,先进行五次i++,在输出i即5。再进行五次异步的定时器内的输出i++,即5,6,7,8,9。
2.利用闭包实现循环点击按钮打印索引:
思路:闭包+立即执行函数
<body>
<ul class="nav">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<script>
let lis = document.querySelector('.nav').querySelectorAll('li');
// 利用闭包实现
for (var i = 0; i < lis.length; i++) {
// 利用for循环创建了四个立即执行函数
// 立即执行函数也称为小闭包,立即执行函数中的任意一个函数都能使用它的变量
(function (i) {
// 闭包产生
lis[i].onclick = function () {
console.log(i);
}
})(i);
}
</script>
</body>
采取立即执行函数,解决异步问题。
如果不使用立即执行函数,内部点击事件是异步任务,会等到for循环结束完毕才从消息队列中回到执行栈,此时由于i变量声明是var,造成循环遍历泄露。导致i成为4,故点击时会报错,因为不存在下标为4的li。
立即执行函数和闭包搭配使用,在每次i遍历的时候,由于内部点击事件需要i故每次点击都会循环创建立即执行函数,又由于i的声明,产生了闭包。给立即执行函数赋值i,所以内部的点击事件可以访问到外部闭包中的i值,每次点击都会获取到对应的下标i,即达到所需的结果。
3.利用闭包实现3秒后打印所有li标签中的内容
思路:闭包+立即执行函数
<body>
<ul class="nav">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<script>
// 3秒后打印所有li的内容
let lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function (i) {
setTimeout(() => {
console.log(lis[i].innerHTML);
}, 3000);
})(i);
}
</script>
</body>
如果贸然使用setTimeout延迟函数去打印lis[i]的innerHTML值,此时会因为延迟函数是异步任务的问题,等到循环结束后才打印i下标的li的内容,此时i变为4,故不合法。
故采用立即执行函数,循环的同时创建了立即执行函数并执行,访问到了i值即闭包。
4.利用闭包实现出租车计价问题
题目:打车价起步13(3公里内),之后每多一公里加收5块钱,用户输入公里数即可计算打车价格,若有拥堵情况,多收10元拥堵费
<script>
// 打车价起步13(3公里内),之后每多一公里加收5块钱,用户输入公里数即可计算打车价格,若有拥堵情况,多收10元拥堵费
let km = prompt('请输入公里');
var car = (function () {
var start = 13;
var total = 0;
return {
price: function(n){
if(n <= 3) {
total = start;
} else {
total = start + (n - 3) * 5;
}
return total;
}, //正常总价
mess: function(flag){
return flag ? total + 10 : total;
} //拥堵费用
}
})();
</script>
声明了一个立即执行函数car,并采用高阶函数的方式返回一个函数对象price和mess,分别计算正常总价和拥堵时的费用。此时由于start和total是局部变量的问题,故会产生闭包,在进行价格的计算后,由于闭包的存在,变量total不会被清理,在进行mess的判断时依然可以被访问到。
5.思考下列函数的执行结果:
<script>
var name1 = 'The window';
var object1 = {
name: 'My Object',
getNameFunc: function() {
return function() {
return this.name1;
}
}
}
console.log(object1.getNameFunc()());
var name2 = 'The window';
var object2 = {
name: 'MyObject',
getNameFunc: function() {
var that = this;
return function() {
return that.name2;
}
}
}
console.log(object2.getNameFunc()());
</script>
答:‘The window’和‘MyObject’
解释:第一个函数由于执行输出this的name,由于是匿名函数,故this指向window,则window下的name1为the window,第二个函数由于that存储了object2对象,存在闭包,故输出that的name为object2的name为MyObject。

浙公网安备 33010602011771号