关于setTimeout的一些习题

1. setTimeout参数详解

setTimeout(func|code, delay) // 第一个参数是函数执行体,后面一个是延时时间

但是setTimeOut还可以在后面增加多个参数,比如:

setTimeout(func|code, delay,a,b,c ..)  // 第一个参数是执行体,第二个参数是延时时间,后面的参数可以作为参数传入第一个函数执行体内作为参数使用

setTimeOut的参数:

第一个参数是执行体,第二个参数是延时时间,

后面的参数可以作为参数传入第一个函数执行体内作为参数使用。

比如:

for (var b = 0; b < 4; b++) {
    setTimeout(function(c) {
        console.log( c);
    }, 1000, b);
}
console.log(c);
//打印出来
4,0,1,2,3

这是因为整个for循环是几乎是一瞬间执行完毕,相当于同一时间设置了四个定时器,每个定时器都是延时1s以后执行,并且每一个定时器都保存了创建它的时候b的值,所以,最后是先打印出4,然后过一秒几乎同时打印出0,1,2,3.

2. 设计一个循环定时器,每隔一秒打印一次

for(let i=0;i<5;i++){
  setTimeout(()=>{
    console.log(i)
  },1000*i)
}//打印结果 依次打印0,1,2,3,4 时间间隔为1s

但是将let改成var之后

for(var i=0;i<5;i++){
  setTimeout(function(){
    console.log(i)
  },i*1000)
}
//打印结果 依次打印5,5,5,5,5 时间间隔为1s

总结:setTimeouti值,是一个全局变量i(可以跨块级作用域,for是块级作用域),每次循环这个值都会改变,指向的是最外层也就是全局的i值,当1秒后打印的时候,i的值已经变成了5,所以打印出来的是55let是块级作用域内有效,setTimeouti值指向的是每个循环体中的i值。

专业一点的解释:

  • var: 由于JavaScript是单线程的,按顺序执行,setTimeout是异步函数,它会将内部函数放到任务队列中,而此时会先将循环执行完毕再执行内部函数,因此当执行内部函数时i已经等于5了,所以最终会输出55
  • let: let块级作用域,for循环外无法获取i,因为for循环头部的let不仅将i绑定到for循环中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过var定义的变量是无法传入到这个函数执行域中的,通过使用let来声明块变量能作用于这个块,所以function就能使用i这个变量了。

使用闭包解决:

for (var i = 0; i < 5; i++) {
  (function (i) {
    setTimeout(function() {
      console.log(i);
    }, 1000*i);
  })(i)
}//打印结果 依次打印0,1,2,3,4 时间间隔为1s

通过闭包,将i的变量驻留在内存中,当console时,引用的是外部匿名函数的变量值ii的值是根据循环来的。

3. 综合运用习题

let obj = {
        a: 10,
        b: function () {
          console.log('普通函数', this.a)
        }
      }
  setTimeout(obj.b(), 5000); //10
  setTimeout(obj.b, 1000); //undefined

这里第一个setTimeout虽然设置了间隔时间,但是内部的函数是对obj.b方法的立即执行(从字面意思理解:立即函数就是立即执行无需等待回调,代码加载就立即执行)。所以会立马打印出: 普通函数 10

第二个setTimeout可以看成是:

setTimeout(function() {
   console.log('普通函数', this.a)
},1000)

正常的间隔一秒打印 普通函数 undefined, 定时器thiswindowwindow没有a属性。

涉及知识点: 立即执行函数、setTimeoutthis指向

全部评论

相关推荐

投递腾讯等公司10个岗位
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务