为了账号安全,请及时绑定邮箱和手机立即绑定

javascript setInterval回调函一点疑惑

javascript setInterval回调函一点疑惑

婷婷同学_ 2019-03-14 18:15:32
本人新手, 学习javascript定时器的时候遇到了一点疑惑, 可能是个老生常谈的问题了, 但是还是想请教一下各位前辈, 问题与代码如下:var Cat = function() {    var o = {        say: function() {            console.log('say something');        }    }    setInterval(function(){        o.say()    }, 1000)    return o}var cat = Cat()cat.say = function() {    console.log('Hello');}问题描述: 我定义了一个Cat类(用的工厂模式), 然后这个类里面有一个方法say(), 同时还有一个setInterval执行这个'方法', 然后实例化这个类, 重新声明一次say()这个方法.我的困惑:在于, 输出是'Hello', 而不是我一开始定义的那个类里面的那个方法, 这个地方不是特别理解个人理解:由于setInterval传进来的回到函数是一个方法, 实际上那个 o 指代的是实例化以后的那个实例对象, 而不是一开始的那个类?但是感觉好像有点懂了, 但是又有点不懂, 或者其实根本不懂, 到底该如何正确清晰理解这段代码的运行过程, 希望各位前辈能有一个详细的解答, 多谢.
查看完整描述

4 回答

?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

o本来就是实例化后的对象,你每执行一次Cat,就会有一个新的o生成。o的实例化在执行完var o = ...后就完成了。


试运行以下代码:


var Cat = function() {

    var o = {

        say: function() {

            console.log('say something');

        }

    }

    let say = o.say;

    setInterval(function(){

        say();

    }, 1000)

    return o

}


var cat = Cat()


cat.say = function() {

    console.log('Hello');

}

这时输出就是


Say something

这个问题其实和setInterval无关,你提供的代码中的setInterval的回调函数持有的是对o这个实例的引用,而不是对o.say的引用,因此一秒后这个回调执行的时候,就会先找到o,然后再去找o.say;而我提供的代码中的setInterval的回调函数持有的是对o.say这个函数的引用,并且是对旧的o.say的引用,因此一秒后这个回调执行的时候,就会直接找到旧的o.say。


不知这样你是否清楚了。


查看完整回答
反对 回复 2019-03-25
?
呼啦一阵风

TA贡献1802条经验 获得超6个赞

先是执行Cat()这个函数,在对象中定义了say()方法,接着遇到了setInterval,这是个异步任务,所以加入到异步队列中。然后接着执行cat.say = function() {console.log('Hello'},这时,实例对象cat的的say方法已经被重写。接着,同步任务执行完了,执行之前加入异步队列中的回调函数,所以输出结果为Hello.

查看完整回答
反对 回复 2019-03-25
?
翻阅古今

TA贡献1780条经验 获得超5个赞

要输出'say something'关键要在定时器回调中运行Cat中o的确切引用,也可以这样:


var Cat = function() {

var another;

    var o = {

        say: function() {

            console.log('say something');

        }

    }

    another = o.say;

    setInterval(function(){

        another ();

    }, 1000)

    return o

}


查看完整回答
反对 回复 2019-03-25
?
FFIVE

TA贡献1797条经验 获得超6个赞

代码简化一下就是


var o = {

    say: function() {

        console.log('say something');

    }

}

setInterval(function(){

    o.say()

}, 1000);

var cat = o;


cat.say = function() {

    console.log('Hello');

}

画个图:

https://img1.sycdn.imooc.com//5c988ba30001b51804160300.jpg

  1. o和Cat变量都指向0x0001地址,那里存放了一个对象;

  2. 对象上有一个say指针指向0x0002,那里是say函数;

  3. 后来,对这个say指针重新赋值,指向了0x0003地址,那是一个新的say函数;

  4. 最后,setInterval函数调用的是0x0003的say函数,而不是0x0002的say函数。

虽然setInterval的代码写在前面,但因为前三步都是同步任务,所以会先执行。 
可以搜索一下JS的事件循环,同步任务代码先执行,setInterval和setTimeout这种宏任务会放在异步队列中等待同步任务完成后再执行。


查看完整回答
反对 回复 2019-03-25
  • 4 回答
  • 0 关注
  • 526 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信