由一道面試題引發的setTimeout的用法思考

有一道簡單的面試題也不怕大家笑話,先上題。

var A={
    name:'guguji'
    };
var B={
    name:'dukuan',
    sayName:function(){
        console.log(this.name)
        }
    }       

問:如何通過調用sayname方法輸出‘guguji’?
obviously,是想通過改變函數的作用域來實現的,我告訴面試官B.sayName.call(A)可以,apply亦然,但是面試官問我還有啥方法嗎?我沒答出(好菜自己)。another answer is the Bind function。
面試官大神說了,回家趕緊一通查bind。裏邊有這麼一段demo很好奇,不加bind會發生什麼。

function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒鐘後, 調用'declare'方法

bind去掉,bloom方法改成醬紫。

LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare(), 1000);
};

發現可以正確的打印出信息,咦~不對,是直接打印的,沒有延時1s。好好回想一下自己用settimeout的時候,是這麼寫的。settimeout(function(){console.log('guguji')},1000),就明白了,這裏也擺上settimeout的定義,原來settimeout裏邊可以傳三個以上的參數。第一個是方法,第二個是delay延時,第三個param是方法調用時候傳入的參數。通俗點理解就是執行到settimeout的時候,會往調用堆棧裏放入一個函數,delay後執行,參數爲param。而我上邊那樣寫呢,settimeout傳入的第一個不是方法名,而直接調用了一個方法,所以,就直接執行咯。
改成方法名的話settimeout(this.declare,1000)就會在declare執行的時候遇到this指向window的情況,所以必須像文檔上寫的bind(this)一下。(注:bind的這個括號,只是改變function的this指向,並沒有調用)

settimeout這個函數默認會把this指向window,JavaScript自己也明白這個缺陷,所以在文檔了也列出瞭解決方法,1、像我常用的的那樣,套個function(){ ‘把你想執行的方法放在這裏’}。2、使用箭頭函數。


section one

 LateBloomer.prototype.bloom = function() {
      setTimeout(function(){
        this.declare();
      }, 1000);
    };

醬紫肯定報錯啊,window下邊肯定沒有declare方法,咋辦尼肯定得把lateBloomer傳進去纔對。別忘了settimeout有第三個參數,大抵是這樣。

 LateBloomer.prototype.bloom = function() {
      setTimeout(function(This){
        This.declare();
      }, 1000,this);
    };

section two

 LateBloomer.prototype.bloom = function() {
      setTimeout(()=>{
        this.declare();
      }, 1000);
    };

Unexpectedly it works.箭頭函數裏的this並不是window??the answer is no.阮一峯blog的解釋“函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。”一些有關箭頭函數的資料,mdn定義why not use arrow function

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章