知乎一道前端面試題詳解,關於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();

 

先跟蹤一下函數的執行。

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

很顯然,f就是一個foo的副本,它是一個對象,副本內部的函數就是該對象的方法,可以點式調用。foo是函數不可以直接作為對象調用內部方法。

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

 

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

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

 

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

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

結果彈出:江太公。證實我的想法。

 

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

方案一:用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()

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM