this指向調用它的對象
首先要明確,this指向調用方,誰調用,this指向誰。
直接調用
舉個栗子:
var
test = 'window'
;
function testThis () {
var test = 'inner';
this.test = 'test change';
console.log(this.test)
}
testThis(); // test change
console.log(window.test) // test change
在chrome中執行后可以發現,外部掛在window下的test被修改了,因為這個testThis的函數,是被window調用的,它只會讀取window下的test。
構造函數調用
再舉個栗子:
var
test = 'window'
;
function testThis () {
var test = 'inner';
console.log(this.test)
this.test = 'test change';
console.log(this.test)
}
var newTestThis = new testThis();
// undefined
// test change
console.log(window.test) // window
在chrome中執行以下可以發現,依次輸出undefined、test change、window。
這個栗子與上面的區別在於調用了new。此時,該函數作為構造函數調用,我們都知道,構造函數中的this都指向new出來的對象。所以this指向了這個新生成的newTestThis。自然地,window下test就沒有被修改。
嵌套調用
接下來舉一個栗子,來說明在函數嵌套調用時的this指向:
var x = 'global'
function testThis () {
// this.x = 'fuck';
// console.log(this)
console.log(this.x)
}
function innerObj () {
this.x = 'inner';
testThis();
this.innerTestThis = testThis;
this.innerTestThis();
}
function wrapObj () {
this.x = 'wrap';
// var test = new testThis();
// console.log(test.x)
testThis();
this.wrapTestThis = testThis;
this.wrapTestThis();
this.innerTestThis = new innerObj();
}
var wrap = new wrapObj();
wrapObj();
// global
// wrap
// global
// inner
// wrap
// wrap
// wrap
// inner
很明顯,在函數嵌套時,如果不給函數指定調用對象,則不論被調用函數是在哪個函數的作用域里,被調用的函數的this都是指向window的。
我們可以這樣理解,在直接調用時,這些函數除了擁有自己的作用域外,就像是把這幾行代碼寫到了相應的位置。可以想一下,所有的js代碼最后都拼到一起,很明顯,他們的調用方都是window。
總結一下:1.不論函數在哪里被調用,只要沒有指定調用方,則this都指向window。指定了調用方,就指向調用方。2.作為構造函數中調用,this指向新生成的對象。
分析一下:setTimeout和setInterval
bind的作用就是給函數一個指定的thisArg,經常使用bind的地方就是setTimeout和setInterval了。為什么呢?
setTimeout和setInterval都有一個特點,它會將回調函數的作用域轉移到window上面。其實結合我們上面說的,很容易知道為什么。
以setTimeout為例:翻看MDN下setTimeout的定義,可以發現,setTimeout是把一段callback代碼延遲執行。寫過callback的同學都知道,callback的代碼其實就是占了位,然后去調用一行行的代碼,所以,callback中的this也會指向window。
實際開發中,我們不希望this指向window,故而常使用bind來使this指向我們希望的對象。
bind、apply、call
說到了bind,就還需要提一下另外的可以改變this指向的方法:apply和call。
這兩個函數大同小異,只是傳參有區別。不論使用apply還是call,都會傳入一個thisArg,作為函數調用方,讓函數中的this指向thisArg。
在下一篇,我會介紹一下apply和call。