js for循环_JS 函数的执行时机(深入理解6个6)

定时器:setTimeout()

setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式

提示: 1000 毫秒= 1 秒。 提示: 如果你只想重复执行可以使用 setInterval() 方法。 提示: 使用 clearTimeout() 方法来阻止函数的执行。

语法:setTimeout(x,y,z)

  • x 函数function()
  • y 时间(time)
  • z 参数(会自动传入第一个参数,也就是函数的参数中) 可省略
setTimeout(function(){
  alert("Hello"); 
}, 3000);

因为setTimeout含义是定时器,需要通过设置(触发)时间来调用代码

假使设置的时间为3000,则在3000毫秒数弹出对话框“Hello” 假使设置的触发时间为“0”时,含义则为尽快调用

打个比喻:老板让你清点运来的箱子,当数到第50个,老板和你说把结果写到纸上交给我。
当下肯定不能进行记录,因为箱子还未清点完成;只有最后数完箱子后,才能在写到纸上交给老板

先把主代码执行完,之后才尽快执行setTimeout中的代码


JS执行(调用)时机

面试题:6个6

思考:以下代码会打印出什么?

let i=0
for(i=0;i<6;i++){
  setTimeout(()=>{console.log(i)},1000)
}

运行上面代码,看看会打印出什么结果

let i=0
for(i=0;i<6;i++){
  setTimeout(()=>{console.log(i)},1000)
}

a1b63e80cbb69accb2d3e7c3a77aa335.png
  • JS函数的调用时机不同,得到的结果不同。
  • setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式;其意思就是尽快,而不是马上。

解释:因为setTimeout是一个异步任务,执行到这里的操作会被浏览器丢到另一个任务队列里去, 浏览器这时候会继续执行for循环。每一次for循环的时候,setTimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了6次,就放了6次,当主线程执行完成后,才进入任务队列里面执行。这时候因为for循环i=6了,所以输出的全部都是6。

如何理解异步呢?

异步代码不等待结果,直接进行下面的代码,所以定时器只是开启了,而没有立即执行里面的代码,等到当前运行坏境的代码执行完之后再回来执行定时器里面的代码。总结:异步就是不等待结果的代码。

解释二:如案例中所示,setTimeout的调用时间为“0”(尽快调用),只有当主代码执行完一遍后才会执行setTimeout(定时器),但这时i已经为6,所以打印出数值6.

又因为条件:i<6,共执行了6次(当i等于6时跳出循环),所有结果为一共打印出6次6。

思考:那么怎么正确显示?(如何打印出0、1、2、3、4、5)


方法一:let关键字

原理:每次进入进入循环时,JS会把当前的复制一份路i在循环空间里(i=0,i=1...) 不会跟随新的i跟变化

JS变态之处:把let声明写入for循环中,则会正常打印出 0、1、2、3、4、5 (服了JS,迎合新人)
for(let i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

219645004b9775a9f31026d3633e2482.png

解释:因为let变量的作用域只能在当前函数中,所以每次for循环生成的都是一个新的i,setTimeout里输出的i就是这个新的i,这个i是不会变化的,所以输出的就是正常的。

迦南:var、let、consts在JavaScript变量/常量的定义​zhuanlan.zhihu.com
95c1c3144291dbd1966d4e980af4eaec.png

除了使用 for let 配合,还有什么其他方法可以打印出 0、1、2、3、4、5?

方法二:

for(i=0;i<6;i++){
  let j = i
  setTimeout(()=>{console.log(j)},1000)
}

方法三:闭包

for(var i=0;i<6;i++){
  !function(i){  //这是里面的i //在匿名函数前加上运算符‘ !’,不生成新的全局变量(防止污染全局)
     setTimeout(()=>{console.log(i)},1000)  //这是里面的i
   }(i)  //这是外面的i //在匿名函数后加个()立即执行,并把i当作参数value传入匿名函数循环执行,参数i和匿名函数组成了闭包
}

99bdf98e09bb44b51bf98805e242974f.png

原理:

  • 声明匿名函数 function(value){} 包裹 setTimeout()
  • 然后再匿名函数前加上运算符‘ !’,防止生成新的全局变量(避免污染全局)
  • 在匿名函数后加个()立即调用,并把 i 当作参数 value 传入匿名函数进行调用

注意:参数i和匿名函数会组成了闭包

通过闭包,将i的变量驻留在内存中,当输出j时,引用的是外部函数A的变量值i,i的值是根据循环来的,执行setTimeout时已经确定了里面的的输出了。

方法四:利用 setTimeout 的第三个参数,将i传进去

let i
for(i = 0; i<6; i++){
    setTimeout((value)=>{
      console.log(value)
    },0,i)   //setTimeout 第三个参数,声明后这个参数可以将自身传给第一个参数 function(value),
}

原理:

使用setTimeout 的第三个参数--这个参数可以将自身传给第一个参数
也就是匿名函数function(value)中,作为所需要的参数value,value可默认不写
而 i 共传入6次(0,1,2,3,4,5),通过匿名函数即可打印出
通常不写第三个三处,如果默认不写第三个参数,则不会传入函数

由于每次传入的参数是从for循环里面取到的值,所以会依次输出0~5

简单一句换:setTimeout的第三个参数作用,它就是当作setTimeout第一个函数的参数

方法五:const关键字

let i
for(i = 0; i<6; i++){
    const x = i
    setTimeout(()=>{
      console.log(x)
    })
}

拓展例1:

function sum(x,y,z){
    console.log(x+y+z);
}
setTimeout(sum,1000,1,2,3);

fadf2f6b2d969d909652c01049214bfa.png

拓展例2:

var i=0;
setTimeout(function(){
    console.log('第二次'+i)
},3000,setTimeout(function(){
    console.log('第一次'+i);
    i++;
},1000));

66041f3c75a77103cfbb823f8ac5e517.png
最后依次输出为 第一次0 第二次1
可以看到第三个参数还可以是先执行,然后再执行函数

不过还要注意一点就是:

这种传参方式在IE9及更低的版本下是不起作用的

setTimeout的意思

setTimeout(fn(),1000)
f2()

1000ms后尽快执行fn(),不代表马上执行,如f2()中写了10000行代码,需要花10秒执行完,那么,fn()会在10秒之后执行。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`Vue.nextTick`是Vue提供的一个API,它可以让我们在DOM更新之后执行一些操作。在Vue中,当数据发生变化时,Vue会异步执行DOM更新操作。也就是说,当我们修改了Vue实例中的某个属性,Vue并不会立即去更新DOM,而是先将这个更新操作加入到一个队列中,在下一个事件循环时,Vue会清空这个队列,依序执行其中的更新操作。 由于Vue的异步更新机制,有时候我们需要在DOM更新之后执行一些操作,比如获取更新后的DOM节点的尺寸或位置等。此时,我们就可以使用`Vue.nextTick`来确保这些操作是在DOM更新后执行的。 下面是一个使用`Vue.nextTick`的例子: ```javascript new Vue({ el: '#app', data: { message: 'Hello Vue.js!' }, methods: { updateMessage: function () { this.message = 'Updated!' this.$nextTick(function () { // DOM已经更新 console.log(this.$el.textContent) // "Updated!" }) } } }) ``` 在`updateMessage`方法中,我们首先修改了`message`属性的值,然后调用了`this.$nextTick`方法,在回调函数打印了`this.$el.textContent`。由于`this.$nextTick`方法会在DOM更新之后执行回调函数,所以打印出来的是更新后的内容。 需要注意的是,`Vue.nextTick`不是立即执行的,而是在下一个事件循环执行的。这意味着如果我们在某个方法中多次调用`Vue.nextTick`,那么这些回调函数会被加入到同一个队列中,在下一个事件循环时一起执行。这个特性可以帮助我们避免不必要的DOM操作,从而提高性能。 总的来说,`Vue.nextTick`可以帮助我们更好地掌控Vue的异步更新机制,避免出现一些奇怪的bug。同时,它也为我们提供了一个优化性能的机会,让我们能够更好地利用Vue的异步更新机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值