有一道簡單的面試題也不怕大家笑話,先上題。
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
。