setTimeout

参考
1. MDN window.setTimeout
2. JavaScript 标准参考教程 - 定时器
3. 你所不了解的setTimeout
4. 彻底理解setTimeout()

API语法

var timerId = setTimeout(func | code[, delay]);
var timerId = setTimeout(func[, delay, param1, param2])
  • API中第一个参数是function或者字符串形式的code,正常情况下使用function
  • Node中第一个参数非function会报错;
  • IE10+才支持带param写法;
  • delay可省略,默认为0;
  • this指向默认为window
  • code形式是没有第三个参数的,即使写了也读取不到arguments

1. 写法对比

// 浏览器
var func = function() {
  console.log(1)
}

// 正常写法,延迟输出1;
setTimeout(func, 1000)

// 此处func()立即执行,返回undefined,相当于
// func()
// setTimeout(undefined, 1000)
// 立即输出1
setTimeout(func(), 1000)

// 字符串写法,同正常写法,延迟输出1
setTimeout('func()', 1000)

2. 异步输出

delay为0依然是异步输出

console.log(1)
setTimeout(function () {
  console.log(2)
}, 0)
console.log(3)
// 1 3 2

3. 见怪不怪的一题

for (var i = 1; i < 5; i++) {
  setTimeout(function () {
    console.log(i)
  }, i * 1000)
}
// 5 5 5 5
  1. for循环中var声明的是全局作用域
  2. setTimeoutfunction现在一边观望
  3. 同步操作完成后,functioni随着作用域链找到全局中的i

使结果预期为1 2 3 4的方法之一就是创建一个作用域用来覆盖全局作用域中的i变量

for (var i = 1; i < 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i)
}
// 1 2 3 4

方法之二是利用API中的第三个参数,传参进去

for (var i = 1; i < 5; i++) {
  setTimeout(function (i) {
    console.log(i)
  }, i * 1000, i)
}
// 1 2 3 4

此时function中的i其实与全局的i没什么关系了,相当于:

for (var i = 1; i < 5; i++) {
  setTimeout(function (j) {
    console.log(j)
  }, i * 1000, i)
}
// 1 2 3 4

方法之三是ES6中let声明的块级作用域

for (let i = 1; i < 5; i++) {
  setTimeout(function () {
    console.log(i)
  }, i * 1000)
}
// 1 2 3 4

那以下代码输出什么呢?

var i = 100;
for (let i = 1; i < 5; i++) {
  setTimeout(function (i) {
    console.log(i)
  }, i * 1000)
}
// undefined undefined undefined undefined

出这题应该很变态了,但想到第一个参数总是一个不能传参的函数,假设是temp,执行时相当于temp(),并没有任何参数传入,所以预期的i始终为undefined。感觉可以将每个setTimeout函数都可以如下

var i = 100;
for (let i = 1; i < 5; i++) {
  var temp = function (i){
    console.log(i)
  }
  setTimeout(temp, i * 1000)
}
// undefined undefined undefined undefined

方法之四是使用bind传入参数

for (var i = 1; i < 5; i++) {
  setTimeout(function (i) {
    console.log(i)
  }.bind(null, i), i * 1000)
}
// 1 2 3 4

4. Todo

  1. 传参
  2. debounce--见参考2
posted @ 2018-03-13 12:40  guidetheorient  阅读(157)  评论(0)    收藏  举报