2016-08-03 43 views
2

在這裏,我複製的代碼片段從MDN:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind的setTimeout,結合這

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(); 
// after 1 second, triggers the 'declare' method 

最令人困惑的部分是:window.setTimeout(this.declare.bind(this), 1000);

我瞭解this工程和this裏面的setTimeout總是勢必對全球對象。我知道可以有var selfvar裏面bloom功能。

該行有兩個this,但其中this指的是什麼以及如何工作是完全混淆。

工作原理?

+0

這兩個'這'是同一個對象。 'Bind'返回帶有上下文或明確設置的this的函數。所以當'setTimeout'最終運行時,它不能覆蓋'this'到全局,所以它仍然被設置爲'bloom'方法的'this'。 – ste2425

回答

2

MSDN定義Function.prototype.bind()如,

的bind()方法創建一個新的功能,調用它時,有其 這個關鍵字設置爲所提供的值,與設置的前述任何 參數的給定序列當新功能被調用時。

使用.bind(this)我們傳遞this的功能declare

看到這個片段。

function LateBloomer() { 
 
    console.log(this.constructor); 
 
    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.undefinedbloom = function() { 
 
    window.setTimeout(this.declare, 1000); 
 
}; 
 

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

 
var flower = new LateBloomer(); 
 
flower.bloom(); 
 
flower.undefinedbloom();

在功能undefinedbloom我們只是調用聲明函數。因此該對象將是window對象。它沒有屬性petalCount所以它的undefined。

在功能bloom我們的LateBloomerthis結合聲明函數由我們將有權訪問LateBloomer的對象petalCount

this在JavaScript中是一個非常難以理解的問題。

MDN鏈接:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this所有的

+0

但是爲什麼這不是指全局對象。它在settimeout裏面對嗎? – Siddharth

3

首先閱讀this link。有關this如何工作的非常好的解釋。

.bind(this, args)只是幫助的你傳遞你的函數內部this上下文(因爲它裏面,在你的榜樣默認thisundefined或引用window)。

而且bind是一個不錯的選擇,這樣的:

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

而且隨着es6最後一點,你可以做這樣:

window.setTimeout(() => { 
    //do some stuff 
}, 1000); 

,而不是

window.setTimeout(function() { 
    //do some stuff 
}.bind(this), 1000); 

這讓你不用考慮this

0
function LateBloomer() { 
    this.name = 'triven'; //simplified property 
} 

// Some thoughts we discuss main requirement. 
LateBloomer.prototype.bloom = function() { 
    window.setTimeout(function() {console.log(this);}, 1000); //Logs window: We all know that keyword this INSIDE CALLBACK 
                  //function refers to Window [Comment 1] 
    //window.setTimeout(console.log(this), 1000); /Attentions: Here it is very easy to MISUNDERSTAND 
               //that keyword this is inside setTimeout and it should refer to window. 
               //Please note that here keyword this is not INSIDE CALLBACK function so here 
               //keyword this will refer to object on which its wrapper function is 
               //executed(in our case flower). [Comment 2] 
}; 

//The requirement: We need to call .bloom and it should log name after 1 second. 
LateBloomer.prototype.bloom = function() { 
    //here keyword this refers to object 

    //window.setTimeout(function() {console.log(this);}, 1000); //But inside callback keyword this refers to window. 

}; 

//We need some way to access object inside call back function so that its name can be accessed after 1 sec. 

//step 1; Taking out anonymous function and adding it as a prototype property 
LateBloomer.prototype.bloom = function() { 
    //window.setTimeout(this.callback, 1000); //Note: Keyword this is not inside callback so 
              //it is referring to object (not window). We can access newly 
              //defined function on the object. Also keyword this placed inside callback 
              //function(below) will still refer to window. 

}; 
LateBloomer.prototype.callback = function() {console.log(this.name);} 

//step 2; bringing .bind into picture. 

    //Definition of .bind as per MDN : The bind() method creates a new function 
    //that, when called, has its this keyword set to the provided value 

LateBloomer.prototype.bloom = function() { 
    window.setTimeout(this.callback.bind(this), 1000); // Okay now we are now invoking .callback method on the object and 
                //passing the same object to bind. 
                // The keyword this inside newly return function (as a result of bind) will now refer to object 
                // we passed as argument to bind and we should not be able to access name property of our object. 
                // Note : Here both this keywords refers to same object ie on which which are calling .bloom. 
                //Note : we are no longer using passing callback function defined below. Instead we are now passing 
                // and exact copy of it but configuring it in such a way that keyword this start refering to object we passed. 

}; 
LateBloomer.prototype.callback = function() {console.log(this.name);}