1. 什么是闭包? 有什么作用
在一个函数中(父函数)return出另一个函数(子函数),该子函数访问了父函数中的局部变量,使父函数里面的内存不能被释放。
作用:
- 使可以在函数外部访问到函数内部的局部变量
- 维持一个独立的数据空间
如下面的例子:foo()父函数内部return了一个子函数 f(),这个子函数就相当于给我们提供了一个访问父函数内部变量的接口,使我们可以在外部访问到父函数里面的a变量。
function foo(){
var a=10;
return function f(){
return a;
}
return f;
}
foo()(); //10
2. setTimeout 0 有什么作用
setTimeout 0
会把当前函数放到队尾执行,即等所有的JS执行完后再执行。如下面的例子:
setTimeout( function(){
console.log("hello")
},0);
console.log("a");
for (var i=0; i<4;i++){
console.log(i);
}
setTimeout( function(){
console.log("word")
},0);
for (var i=5; i<8;i++){
console.log(i);
}
执行结果如下,可以看到,两个setTimeout 0
里的函数按先后顺序被排到了队尾。
下面为 setTimeout 0 的一个简单应用,可以让我们输入的字符立即转换成大写。
var ipt=document.getElementById("ipt");
ipt.addEventListener("keydown",function(){
var me=this;
setTimeout(function(){
me.value=me.value.toUpperCase();
},0)
})
3.下面的代码输出多少?修改代码让 fnArr[i] () 输出 i。使用两种以上的方法
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() ); //输出为10,因为每一个 fnArr[i]里保存的都是一个函数,这个函数返回 i,而最终循环完后的i值为10。
方法一:使用es6语法let(存在浏览器支持问题), let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。(let的作用域是块,而var的作用域是函数)
var fnArr = [];
for (let i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() ); //3
方法二:通过闭包, 创建一个独立的数据空间,用于保存数据。以下四种写法都可以,大同小异。
// 闭包写法一 将立即执行函数赋值给 fnArr[i], 立即执行函数需要传入参数i
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = (function(n){
return function(){
return n;
}
})(i);
}
console.log( fnArr[3]() );
// 闭包写法二 将立即执行函数赋值给 fnArr[i], 立即执行函数不传参,而是在内部声明一个临时变量n
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = (function(){
var n=i;
return function(){
return n;
}
})();
}
console.log( fnArr[3]() );
// 闭包写法三 for循环内部直接写成一个立即执行函数,传入参数i
var fnArr = [];
for (var i = 0; i < 10; i ++) {
(function(n){
fnArr[n] = function(){
return n;
};
})(i) //立即执行函数传入参数i
}
console.log( fnArr[3]() ); //3
// 闭包写法四 for循环内部直接写成一个立即执行函数,立即执行函数不传参,而是在内部声明一个临时变量n
var fnArr = [];
for (var i = 0; i < 10; i ++) {
(function(){
var n=i;
fnArr[n] = function(){
return n;
};
})()
}
console.log( fnArr[3]() ); //3
4.使用闭包封装一个汽车对象,可以通过如下方式获取汽车状态
var car=(function(){
var speed=0;
function setSpeed(n){
return speed=n;
}
function getSpeed(){
return speed;
}
function accelerate(){
speed +=10;
}
function decelerate(){
speed -=10;
}
function getStatus(){
if(speed>0){
return "running";
}
else{
return "stop";
}
}
return {
setSpeed: setSpeed,
getSpeed: getSpeed,
accelerate: accelerate,
decelerate: decelerate,
getStatus: getStatus
}
})();
5.写一个函数使用setTimeout模拟setInterval的功能
<input id="ipt1" type="text" >
<input id="ipt2" type="text" >
<script>
var n=0,m=0;
var ipt1=document.getElementById("ipt1");
var ipt2=document.getElementById("ipt2");
//setInterval
setInterval(function(){
n +=1;
ipt1.value=n;
},1000)
//setTimeout
function Count(){
ipt2.value=m;
m +=1;
setTimeout(Count,1000);
}
Count();
</script>
6.写一个函数,计算setTimeout平均最小时间粒度
function getMini(){
var i=0;
var start=Date.now();
var timer=setTimeout(function (){
i++;
if (i==1000){
var end=Date.now();
clearTimeout(timer);
console.log((end-start)/i);
}
timer=setTimeout(arguments.callee,1);
},1);
}
getMini(); //测试的谷歌、火狐、欧明在5ms左右,部分其它浏览器在16ms左右
7.下面这段代码输出结果是? 为什么?
var a = 1;
setTimeout(function(){
a = 2; console.log(a); // 最后输出2
}, 0);
var a ;
console.log(a); // 1
a = 3;
console.log(a); // 3
依次输出1,3,2,因为 setTimeout 0会把当前函数放到队尾执行,即,函数 function(){ a = 2; console.log(a);
会被放到最后才执行,所以最后输出的一项是2。
8.下面这段代码输出结果是? 为什么?
var flag = true;
setTimeout(function(){
flag = false;
},0)
while(flag){ }
console.log(flag);
没有输出, setTimeout设为0,里面的函数被放到队尾执行,那么while循环里flag的值一直是true,while循环一直在进行,执行空语句,因而没有输出。
9.下面这段代码输出?如何输出delayer: 0, delayer:1...(使用闭包来实现)
for(var i=0;i<5;i++){
setTimeout(function(){
console.log('delayer:' + i );
}, 0);
console.log(i);}
先依次输出0,1,2,3,4,然后输出5个 delayer: 5
。
使用闭包实现输出delayer: 0, delayer:1...,代码如下:
// 写法一
for(var i=0;i<5;i++){
setTimeout((function(n){
console.log('delayer:' + n );
})(i), 0);
console.log(i);
}
执行结果如下:
// 写法二
for(var i=0;i<5;i++){
(function(n){
setTimeout(function(){
console.log('delayer:' + n );
}, 0);
})(i)
console.log(i);
}
执行结果如下: