鍍金池/ 問答/Java  網(wǎng)絡(luò)安全  HTML/ javascript setInterval回調(diào)函一點(diǎn)疑惑

javascript setInterval回調(diào)函一點(diǎn)疑惑

本人新手, 學(xué)習(xí)javascript定時(shí)器的時(shí)候遇到了一點(diǎn)疑惑, 可能是個(gè)老生常談的問題了, 但是還是想請(qǐng)教一下各位前輩, 問題與代碼如下:

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');
}

問題描述:
我定義了一個(gè)Cat類(用的工廠模式), 然后這個(gè)類里面有一個(gè)方法say(), 同時(shí)還有一個(gè)setInterval執(zhí)行這個(gè)'方法', 然后實(shí)例化這個(gè)類, 重新聲明一次say()這個(gè)方法.

我的困惑:
在于, 輸出是'Hello', 而不是我一開始定義的那個(gè)類里面的那個(gè)方法, 這個(gè)地方不是特別理解

個(gè)人理解:
由于setInterval傳進(jìn)來的回到函數(shù)是一個(gè)方法, 實(shí)際上那個(gè) o 指代的是實(shí)例化以后的那個(gè)實(shí)例對(duì)象, 而不是一開始的那個(gè)類?

但是感覺好像有點(diǎn)懂了, 但是又有點(diǎn)不懂, 或者其實(shí)根本不懂, 到底該如何正確清晰理解這段代碼的運(yùn)行過程, 希望各位前輩能有一個(gè)詳細(xì)的解答, 多謝.

回答
編輯回答
淚染裳

o本來就是實(shí)例化后的對(duì)象,你每執(zhí)行一次Cat,就會(huì)有一個(gè)新的o生成。o的實(shí)例化在執(zhí)行完var o = ...后就完成了。

試運(yùn)行以下代碼:

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');
}

這時(shí)輸出就是

Say something

這個(gè)問題其實(shí)和setInterval無關(guān),你提供的代碼中的setInterval的回調(diào)函數(shù)持有的是對(duì)o這個(gè)實(shí)例的引用,而不是對(duì)o.say的引用,因此一秒后這個(gè)回調(diào)執(zhí)行的時(shí)候,就會(huì)先找到o,然后再去找o.say;而我提供的代碼中的setInterval的回調(diào)函數(shù)持有的是對(duì)o.say這個(gè)函數(shù)的引用,并且是對(duì)舊的o.say的引用,因此一秒后這個(gè)回調(diào)執(zhí)行的時(shí)候,就會(huì)直接找到舊的o.say。

不知這樣你是否清楚了。

2018年1月25日 21:46
編輯回答
卟乖

代碼簡化一下就是

var o = {
    say: function() {
        console.log('say something');
    }
}
setInterval(function(){
    o.say()
}, 1000);
var cat = o;

cat.say = function() {
    console.log('Hello');
}

畫個(gè)圖:

flow.png

  1. o和Cat變量都指向0x0001地址,那里存放了一個(gè)對(duì)象;
  2. 對(duì)象上有一個(gè)say指針指向0x0002,那里是say函數(shù);
  3. 后來,對(duì)這個(gè)say指針重新賦值,指向了0x0003地址,那是一個(gè)新的say函數(shù);
  4. 最后,setInterval函數(shù)調(diào)用的是0x0003的say函數(shù),而不是0x0002的say函數(shù)。

雖然setInterval的代碼寫在前面,但因?yàn)榍叭蕉际峭饺蝿?wù),所以會(huì)先執(zhí)行。
可以搜索一下JS的事件循環(huán),同步任務(wù)代碼先執(zhí)行,setInterval和setTimeout這種宏任務(wù)會(huì)放在異步隊(duì)列中等待同步任務(wù)完成后再執(zhí)行。

2018年3月30日 17:17
編輯回答
你好胸

先是執(zhí)行Cat()這個(gè)函數(shù),在對(duì)象中定義了say()方法,接著遇到了setInterval,這是個(gè)異步任務(wù),所以加入到異步隊(duì)列中。然后接著執(zhí)行cat.say = function() {console.log('Hello'},這時(shí),實(shí)例對(duì)象cat的的say方法已經(jīng)被重寫。接著,同步任務(wù)執(zhí)行完了,執(zhí)行之前加入異步隊(duì)列中的回調(diào)函數(shù),所以輸出結(jié)果為Hello.

2017年9月16日 16:16
編輯回答
不舍棄

要輸出'say something'關(guān)鍵要在定時(shí)器回調(diào)中運(yùn)行Cat中o的確切引用,也可以這樣:

var Cat = function() {
var another;
    var o = {
        say: function() {
            console.log('say something');
        }
    }
    another = o.say;
    setInterval(function(){
        another ();
    }, 1000)
    return o
}


2017年4月25日 03:17