this指向淺析

在開發過程中,使用this總會出現問題,時不時的會出現獲取不到自己想要的對象和值,只要寫js就必然要弄懂this指向問題。最近總結了下this指向問題,記錄下來,方便之後鞏固學習,也分享給大家希望能有所幫助。

  • 常見的window方法:alter,document,setTimeout,setInterval,一般使用都不會window.xx,而直接使用xx。如果this指向性是window的話,也可以使用this.xx。

  • use strict:嚴格模式,在腳本或函數的頭部添加 "use strict"; 表達式來聲明。指令只允許出現在腳本或函數的開頭。
    在“use strict”嚴格模式下,沒有直接的掛載者(或稱調用者)的函數中this是指向window。在“use strict”嚴格模式下,沒有直接的掛載者的話,this默認爲undefined。以下都是在非嚴格模式下討論。

  • 普通函數this指向:
    this對象是在運行時基於函數的執行環境綁定的:在全局函數中,this指向的是window;當函數被作爲某個對象的方法調用時,this就等於那個對象。
    1.總是代表着它的直接調用者,如obj.fn,fn裏的最外層this就是指向obj
    2.默認情況下,沒有直接調用者,this指向window,嚴格模式下(設置了'use strict'),this爲undefined
    3.call,apply,bind改變this指向
    call: 第一個參數是this的指向,後面傳入的是一個參數列表。當第一個參數爲null、undefined的時候,默認指向window。如:xx.call(obj, 'xx', 'xx2', 'xx3')
    apply: 方法接收兩個參數,第一個參數是this的指向,第二個參數是一個參數數組。當第一個參數爲null、undefined的時候,默認指向window。如:xx.apply(obj, ['xx', 'xx2', 'xx3'])
    bind :call 方法很相似,第一個參數是this的指向,從第二個參數開始是接收的參數列表。區別在於bind方法返回值是函數以及bind接收的參數列表的使用。低版本瀏覽器沒有該方法,需要自己手動實現.
    三者相似之處:
    1、都是用來改變函數的this對象的指向的。
    2、第一個參數都是this要指向的對象。
    3、都可以利用後續參數傳參。
    區別:
    call和apply都是對函數的直接調用,而bind方法返回的仍然是一個函數,因此後面還需要()來進行調用纔可以
    1.call和apply功能幾乎一致,唯一的區別就是傳參的方式
    2.call和apply的第一個參數如果爲null或者undefined,那麼this指向window
    3.call和apply的第一個參數如果爲值類型的數據,那麼會將這個值類型的數據,轉換成其對應的引用類型的數據,然後再將this指向這個引用類型的數據
    4.call和apply立即執行這個函數,bind方法可以讓對應的函數想什麼時候調就什麼時候調用,並且可以將參數在執行的時候添加,這是它們的區別,根據自己的實際情況來選擇使用。
    5.當參數的個數確定的情況下可以使用call;當參數的個數不確定的情況下可以使用apply

  • 箭頭函數改變this指向
    箭頭函數的this定義:箭頭函數的this是在定義函數時綁定的,不是在執行過程中綁定的。簡單的說,函數在定義時,this就繼承了定義函數的對象。這會很好的解決匿名函數和setTimeout和setInterval的this指向問題。我們不用再去給其用that變量存儲this。
    1.默認指向定義它時,所處上下文的對象的this指向。即ES6箭頭函數裏this的指向就是上下文裏對象this指向,沒有上下文對象,this就指向window。
    2.即使是call,apply,bind等方法也不能改變箭頭函數this的指向。
    3.看箭頭函數定義的環境是什麼 (找上一個 {})。
    4.定義環境執行時 this指向誰,箭頭函數的 this就指向誰。
    5.箭頭函數的this在定義的時候就確定,逐級向上查找找到最近的函數作用域的this。
    6.匿名函數沒有直接調用者,this指向window。

  • 場景
    場景1:

function a(){
    var user = "xx";
    console.log(this.user); //undefined,window全局中沒有定義user,所以是undefined
    console.log(this); //Window
}
a();

this最終指向的是調用它的對象,這裏的函數a是,window調用。

場景2:

var a = {
    user:"xx",
    fn:function(){
        console.log(this.user);  //xx
    }
}
a.fn();

這裏的fn是a在調用,所以fn中的this指向就是指向對象a。強調:this的指向在函數創建的時候是決定不了的,在調用的時候才能決定,誰調用的就指向誰。

場景3:

var obj = {
    a:1,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();

場景1:如果一個函數中有this,但是它沒有被上一級的對象所調用,那麼this指向的就是window,這裏需要說明的是在js的嚴格版中this指向的不是window。
場景2:如果一個函數中有this,這個函數有被上一級的對象所調用,那麼this指向的就是上一級的對象。
場景3:如果一個函數中有this,這個函數中包含多個對象,儘管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象。

var obj = {
    a:1,
    b:{
        // a:12, 註釋掉
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();

我們對象b中沒有屬性a,但是this指向還是對象b,因爲this只會指向它的上一級對象,不管這個對象中有沒有this要的東西。

場景4(特殊情況):

var obj = {
    a:1,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var s = obj.b.fn;
s();

這種情況this指向的是window,因爲具體執行調用方法是在s()執行即window.s(),之前的var s = obj.b.fn;只是被引用,卻沒有執行調用。
this永遠指向的是最後調用它的對象,也就是看它執行的時候是誰調用的,場景4中雖然函數fn是被對象obj所引用,但是在將fn賦值給變量j的時候並沒有執行所以最終指向是window,場景3是不一樣的,場景3是直接執行了fn。

場景5(特殊情況):
如果返回值是一個對象,那麼this指向的就是那個返回的對象,如果返回值不是一個對象那麼this還是指向函數的實例。

//1.1
function fn()  
{  
    this.user = 'xx';  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined,this指向返回的對象。
//1.2
function fn()  
{  
    this.user = 'xx';  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined,,this指向返回的對象。
//2.1
function fn()  
{  
    this.user = 'xx';  
    return 1;
}
var a = new fn;  
console.log(a.user); //xx,this指向實例a。
//2.2
function fn()  
{  
    this.user = 'xx';  
    return undefined;
}
var a = new fn;  
console.log(a.user); //xx,this指向實例a。
//2.3
function fn()  
{  
    this.user = 'xx';  
    return undefined;
}
var a = new fn;  
console.log(a); //fn {user: "xxx"}
//2.4null比較特殊,雖然null也是對象,但是在這裏this還是指向那個函數的實例。
function fn()  
{  
    this.user = 'xx';  
    return null;
}
var a = new fn;  
console.log(a.user); //xx

場景6構造函數this:

function Fn(){
    this.user = "xx";
}
var a = new Fn();
console.log(a.user); //xx

爲什麼this會指向a?首先new關鍵字會創建一個空的對象,然內部機制會將this指向這個空對象,函數內部的this就會被這個空的對象替代。

this指向有很多種情況,需要在實際開發中自己去理解。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章