關於this
- this並不是指向函數本身。
- this在任何情況下都不指向函數的詞法作用域。
- this是在運行時進行綁定的,而並不是在編寫時綁定,它的上下文取決於函數調用時的各種條件。
- this的綁定和函數聲明的位置沒有任何關系,只取決與函數的調用方法。
this的綁定規則
this到底綁定或者引用的是哪個對象環境決定於函數被調用的地方。而函數的調用有不同的方式,在不同的方式中調用決定this引用的是哪個對象是由四種規則確定的。
1、默認綁定
這條規則是最常見的,也是默認的。當函數被單獨定義和調用的時候,應用的規則就是綁定全局變量window(嚴格模式下是undefined)。即沒有其他綁定規則存在時的默認規則。
function fn() { console.log( this.a ); } var a = 2; fn(); // 2 -- fn單獨調用,this引用window
為什么說這里應用了默認綁定呢?
因為fn()是直接使用不帶任何修飾的函數引用進行調用的,因此只能使用默認綁定,無法應用其他規則。
2、隱式綁定
隱式調用的意思是,函數調用時擁有一個上下文對象,就好像這個函數是屬於該對象的一樣。必須在一個對象內部包含一個指向函數的屬性,並通過這個屬性間接引用函數,從而把this間接(隱式)綁定到這個對象上。
function fn() { console.log( this.a ); } var obj = { a: 2, fn: fn }; obj.fn(); // 2 -- this引用obj。
當函數引用有上下文對象時,隱式綁定規則會把函數調用中的this綁定到這個上下文對象。
需要說明的一點是,最后一個調用該函數的對象是傳到函數的上下文對象,對象屬性引用鏈中只有上一層或者說最后一層在調用位置中起作用,如下:
function fn() { console.log( this.a ); } var obj2 = { a: 42, fn: fn }; var obj1 = { a: 2, obj2: obj2 }; obj1.obj2.fn(); // 42 -- this引用的是obj2.
如果一個函數中有this,這個函數中包含多個對象,盡管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象
隱式丟失問題:被隱式綁定的函數會丟失綁定對象,也就是說它會默認綁定,從而把this綁定到全局對象或undefined上,取決於是否是嚴格模式。如下:
function fn() { console.log( this.a ); } var obj = { a: 2, fn: fn }; var bar = obj.fn; // 函數引用傳遞,只是函數的別名,而不是調用這個函數 var a = "全局"; // 定義全局變量 bar(); // "全局"
3、顯式綁定
使用bind()\apply()\call()函數:它接收的第一個參數即是上下文對象並將其賦給this
function fn() { console.log( this.a ); } var obj = { a: 2 }; fn.call( obj ); // 2
如果我們傳遞第一個值為簡單值,那么后台會自動轉換為對應的封裝對象。如果傳遞為null,那么結果就是在綁定默認全局變量,如:
function fn() { console.log( this.a ); } var obj = { a: 2 }; var a = 10; fn.call( null); // 10
4、new綁定
如果是一個構造函數,那么用new來調用,那么綁定的是新創建的對象,如下:
function fn(a) { this.a = a; } var bar = new fn( 2 ); console.log( bar.a );// 2
當this碰到return時
如下代碼:
function fn() { this.user = '追夢子'; return {}; } var a = new fn; console.log(a.user); //undefined
function fn() { this.user = '追夢子'; return function(){}; } var a = new fn; console.log(a.user); //undefined
再如:
function fn() { this.user = '追夢子'; return 1; } var a = new fn; console.log(a.user); //追夢子
function fn() { this.user = '追夢子'; return undefined; } var a = new fn; console.log(a.user); //追夢子
總結:
- 如果返回值是一個對象,那么this指向的就是那個返回的對象,如果返回值不是一個對象那么this還是指向函數的實例。
- 還有一點就是雖然null也是對象,但是在這里this還是指向那個函數的實例,因為null比較特殊。
function fn() { this.user = '追夢子'; return null; } var a = new fn; console.log(a.user); //追夢子