知乎一道前端面試題詳解,關於this的使用

請說明要輸出正確的myName的值要如何修改程序?並解釋緣由
foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = function(){
    alert(this.myName);
}
foo.prototype.bar = function(){
    setTimeout(this.sayHello, 1000);
}
var f = new foo;
f.bar();

 

先跟蹤一下函數的執行。windows

全局環境下,聲明一個變量,實例化foo賦值給f,函數未執行。打印f,結果是:app

很顯然,f就是一個foo的副本,它是一個對象,副本內部的函數就是該對象的方法,能夠點式調用。foo是函數不能夠直接做爲對象調用內部方法。函數

console.log(typeof f); //object
console.log(typeof foo);  //functionthis

 

tips:函數foo內部聲明的屬性或方法前加this目的在於保護變量同時能夠被實例化的對象訪問,若是直接聲明私有變量,沒法實例化後使用,而若成爲全局變量又可能形成污染。好比去掉setTimeout前的this,那麼sayHello變成了全局變量,而若全局中未聲明這個函數,就會形成錯誤。spa

console.log(f.name);//Foo functionprototype

 

對象f調用bar以後,被賦值的函數執行,this指向這個對象,而後setTimeout開始執行,指向window,f的方法sayHello在5s後被調起,此時它處在windows環境中,所以alert(this.myName)會嘗試去window環境獲取這個值。以下:3d

var myName = "江太公";
//or this.myName = "江太公";
function sayHello(){alert("江太公");}
foo = function(){
this.myName = "Foo function.";
}
foo.prototype.sayHello = function(){
alert(this.myName);
}
foo.prototype.bar = function(){
setTimeout(this.sayHello, 5000);
}
var f = new foo;
console.log(f);
f.bar();
console.log(f.bar);
console.log(foo.bar);
console.log(typeof f);
console.log(typeof foo);
// console.log(f.myName);code

結果彈出:江太公。證明個人想法。對象

 

ok,整個執行流程很簡單,但中間的this轉換可能讓人困惑。下面給出這道題的4種解決方案。blog

方案一:用bind對this進行轉向。

foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = function(){
    alert(this.myName);
}
foo.prototype.bar = function(){
    setTimeout(this.sayHello.bind(this), 5000);
}
var f = new foo;
f.bar();

方案二:用call/apply進行轉向。

foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = function(){
    alert(this.myName);
}
foo.prototype.bar = function(){
    setTimeout(this.sayHello.apply(this), 5000);
}
var f = new foo;
f.bar();

方案三:用that進行hack。

 

foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = function(that){
    alert(that.myName);
}
foo.prototype.bar = function(){
    var that = this;
    setTimeout(function(){that.sayHello(that);}, 5000);
}
var f = new foo;
f.bar();

 

方案四:使用箭頭函數。

 

foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = function(){
    alert(this.myName);
}
foo.prototype.bar = function(){
    setTimeout(()=>{this.sayHello()}, 5000);
}
var f = new foo;
f.bar();

 或者:

foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = ()=>{alert(this.myName)};
foo.prototype.bar = function(){
    setTimeout(this.sayHello, 1000);
}
var f = new foo;
f.bar()

方法五:還有一種特特簡單的辦法,將構造函數的this也轉向到全局。

foo = function(){
    this.myName = "Foo function.";
}
foo.prototype.sayHello = function(){
    alert(this.myName);
}
foo.prototype.bar = function(){
    setTimeout(this.sayHello, 1000);
}
var f = new foo;
foo();
f.bar()

 

發現其餘途徑煩請告我一聲,謝謝。

相關文章
相關標籤/搜索