闭包和定时器
setTimeout的语法
更新于2017年4月9号
setTimeout(func,time,params) //一定time后,传入回调函数的参数params,并调用回调函数
setTimeout(func,time) // 一定time后调用回调函数
setTimeout(code,time) //一定time后调用代码块(不推荐)
问题
1.什么是闭包?有什么作用
闭包:一个变量,一个函数(环境),函数内部可以访问到这个变量就是一个闭包。
闭包的作用:1.可以访问函数内部的变量。2. 使变量可以一直保存在内存中。
2.setTimeout 0有什么作用
由于js的渲染机制是单线程序,无法同时执行多个不同的代码,当一个代码正在执行的时候,其他的代码都需要等待,直到正在运行的代码运行完后,才能运行下个等待的代码。所以一次点击事件,setTimeout,ajax异步请求都不是立刻的执行,而是立刻的排队。一旦线层空闲下来,就立刻执行。所以setTimeout 0不会立刻执行,而是排队等已经在执行的执行完,然后执行。
var c= 0 ;
function play(){
console.log(c)
}
function add(){
setTimeout(()=>{c+=1},100)
}
add()
play()
// 输出0
console.log(1)
setTimeout(function(){console.log},0)
console.log(3)
执行顺序
console.log('start')
setTimeout(function (){console.log("hello,200ms")},200)
setTimeout(function (){console.log("hello,100ms")},100)
console.log('end')
//start
//end
//hello,100ms
//hello,200ms
console.log('start')
setTimeout(function (){console.log("hello,200ms")},200)
for(var i=0;i<10000;i++){console.log(1)}
setTimeout(function (){console.log("hello,100ms")},100)
console.log('end')
//start
//10000个1
//end
//hello,200ms
//hello,100ms
setTimeout会被异步到另一个内存中,当程序流执行完成后,如果时间程序流运行完,setTimeout的时间还没有到,就谁最短谁就呈现然后再执行setTimeout的程序。
代码题
1.下面的代码输出多少?修改代码让fnArr[i]()
输出 i。使用两种以上的方法
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() ); //10
修改后
- 通过闭包来实现获取i
var fnArr=[];
for(var i=0;i<10;i++){
fnArr[i]=function (n){
var num =n;
return function () {
return num;
}
}(i)}
console.log(fnArr[5]())
2.得不到i,无非就是你手速慢了,当你运行函数的时候,i的值就已经等于10了, 通过立即执行函数来获取i
//第二种方法
var fnArr=[];
for(var i=0;i<10;i++){
fnArr[i]=(function(){
var obj ={};
obj.i=i;
return obj.i
})()
}
var fnArr=[];
for(var i=0;i<10;i++) {
(function(n){
var num= n;
fnArr[n] = function(){
return num;
}
})(i)
}
2. 使用闭包封装一个汽车对象
var Car = (function () {
var obj = new Object();
obj.speed=0;
obj.setSpeed=function (s) {
obj.speed=obj.speed+s;
return;
}
obj.getSpeed=function () {
return obj.setSpeed;
}
obj.accelerate=function () {
obj.speed=obj.speed+10;
return
}
obj.decelerate =function (){
obj.speed=obj.speed-10;
}
obj.getStatus =function (){
if(obj.speed===0){
return 'stop'
}
else{
return 'running'
}
}
return obj;
})()
3.写一个函数使用setTimeout
模拟setInterval
的功能
setTimeout(function sayHello(){
console.log("hello");
setTimeout(sayHello,1000);
},1000)
拓展
具名函数,全局函数,局部函数的区别
-
具名函数 :setTimeout里面的函数就是具名函数,只能在setTimeout里面使用,如果在外部调用会报错。
具名函数 - 全局函数:在任何的作用域都可以使用,就像window自带的方法和属性
- 局部函数:只能在其父元素的函数作用域中使用(闭包除外)
局部函数
4.写一个函数,计算setTimeout平均最小时间粒度
让setTimeout执行1000次,然后我们除以执行的次数
function getMini2() {
var now = Date.now();
console.log(now);
var i =0;
var clock=setTimeout(function () {
i++;
if(i===1000){
clearTimeout(clock);
var fnow = Date.now();
console.log((fnow-now)/i);
}
setTimeout(arguments.callee,0);
},0)
}
5.函数输出的内容
var a = 1;
setTimeout(function(){
a = 2;
console.log(a);
}, 0);
var a ;
console.log(a);
a = 3;
console.log(a);
//1,3,2
知识点1.变量的声明前置。2.setTimeout的异步加载处理
由于setTimeout,所以匿名函数中的内容会在程序加载完成的空闲时间去执行,所以会被放到最后一个console.log(a)后执行。
6.输出结果分析
var flag = true;
setTimeout(function(){
flag = false;
},0)
while(flag){}
console.log(flag);
//无限死循环,没有任何输出
Javascript引擎(JS引擎)是单线程的,在某一个特定的时间内只能执行一个任务,并阻塞其他任务的执行,也就是说这些任务是串行的。我们可以通过异步处理方法,当主线程在执行的过程中,异步处理的代码会被交到另一个模块去执行,当满足它执行的条件后,会被推到任务执行队列,在主线程全部加载完成,空闲下来后,就会去检查任务队列,执行里面的代码。
所以上面的setTimeout(function(){flag=false},0)会被最后执行,这样while就死循环了
7.下面这段代码输出?如何输出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 delayer: 5(5次)
分析
setTimeout(function(){
console.log('delayer:' + i );
}, 0);
上面一个代码块会在for(var i=0;i<5;i++),执行完后再执行,所以得到的i就是5
使用闭包输出delayer:0
for(var i=0;i<5;i++){
//我们把i传递到函数中
(function(n){
//用一个参数来接受它,然后返回一个函数调用这个参数
var m = n;
return setTimeout(function(){
return console.log('delayer:' + m);
},0)//通过setTimeout自动让它执行
})(i)//立即执行它,得到几个函数
}