分享關於JavaScript中執行上下文(this)的使用心得

暴走的snail發表於2018-05-25

接觸JavaScript這門語言已有兩年多了,剛開始使用時覺著這門語言真是通俗易懂,可以說是程式碼隨著想法而出。但用著用著就發現某些功能與你所想要的結果不同(閉包中的this,物件中的函式,物件上的原型...)。期間在網上查閱各種JavaScript學習資料,其中對this這個關鍵的內容佔了不小的一部分,自己也一直想系統對this相關知識進行梳理梳理,最近專案不是太忙就抽了點時間寫一下自己對this的理解,有興趣的小夥伴可以查閱查閱(各位大神就不必浪費你們寶貴的時間了)。

先來張本文的思維導圖:

分享關於JavaScript中執行上下文(this)的使用心得

1.為什麼使用this呢?

先看看不使用this和使用this的程式碼對比:

var me = {
    name: '小明'
}
//不使用this
function name(context){
    console.log("我的名字是"+context.name)
}
name(me)//我的名字是小明
//使用this
function name(){
    console.log("我的名字是"+this.name)
}
name.call(me)//我的名字是小明
複製程式碼

顯而易見,如果沒有this我們就需要給函式顯示的傳入一個上下文物件。對於不使用this來說,如果我們呼叫函式時傳遞的變數越來越複雜,那我們的程式碼肯定會顯得很混亂。反之使用this就不會出現這些情況。 結論:this提供了一種更優雅的方式來隱示的傳遞一個物件的引用,可以使我們的API設計顯得更加簡潔和易於複用。

2.常見的對this理解的誤區

1).this是指向自身的麼? this指向自身,從英語的語法角度可以說的通。但是在JavaScript語法中如果這樣理解,就會產生意想不到的bug。 分析如下程式碼:

foo.myname = "who am I?"
function foo(){
   this.myname = "I am foo"
}
foo()
console.log(foo.myname)// "who am I?"
複製程式碼

如果this是指向自身的話那麼輸出的應該是 I am foo,然而控制檯輸出的是"who am I?"。那麼this.myname指向的哪裡呢?如果此時你在控制檯輸入 console.log(myname)//"I am foo",可見我們建立了一個全域性變數。關於this是否指向自身的結論一目瞭然。答案是NO

2).this指向他所處函式(或物件)的作用域麼? 思考如下程式碼:

function foo(){
    var a=2;
    this.bar()//目的為了聯通foo和bar的作用域
}
function bar(){
    console.log(this.a)
}
foo()//undefined
*程式碼引用你不知道的Javascript上卷80頁,有興趣可以去看看這本書,書中的例子都非常經典*
複製程式碼

上述例子是個很經典的js程式碼片段,表面上看沒有什麼語法錯誤。它的錯誤之處是在於將JavaScript的this和詞法作用域混合使用了,因此這段程式碼是不可能實現的。 結論:無論何時我們都要分清JavaScript中的this和詞法作用域是兩個不同的概念。

3.this到底是什麼?

在JavaScript內部每當js執行時,每一個作用域都會生成一個內部物件,這個內部物件用關鍵字this表示。這句話總結了this是如何出現的(動態的產生,很符合JavaScript這門語言的動態特點),也說明的this的繫結其實跟他的宣告位置沒有半毛錢關係,值取決於函式的呼叫方式。

var obj={
    name:"i am obj",
    func:function (){
        console.log(this==obj)
    }
}
obj.func()//true
複製程式碼

(func:“你是屬於我的。”this:“NO,只是暫時住你這而已,我是屬於obj的.”)

4.用好this的需要理解什麼?

要想將JavaScript中this繫結這個功能化為己用我們還需要理解this的各種呼叫方式即全域性呼叫區域性呼叫

1.全域性呼叫(此時為全域性上下文)不用多說了,此時this相當於window

console.log(this==window)//true
複製程式碼

2.區域性呼叫(此時作為函式上下文)

  • 函式呼叫
function foo(){
   console.log(this == window)//true
}
foo()
複製程式碼

此種呼叫相當於全域性呼叫的結果(符合我們第三節所說的,this的值取決於函式的呼叫方式),因為呼叫函式的位置是在全域性變數下。

  • 方法呼叫 console.log('Hello World!') 1)物件方法呼叫
var myname = "window"
var obj={
    myname:"object",
    func: function(){
        console.log(this.myname)
    }
}
obj.func()//"object"
複製程式碼

當函式作為物件裡的方法被呼叫時,它們的 this 是呼叫該函式的物件.

2)bind方法呼叫

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});//g是與f具有相同函式體和作用域的函式
console.log(g()); // azerty //此時this至指向{a:"azerty"}

複製程式碼

3)建構函式中呼叫

function foo(){
  this.name = "function";
}

var o = new foo();
console.log(o.name); //"function"
複製程式碼

當一個函式用作建構函式時(使用new關鍵字),它的this被繫結到正在構造的新物件。 關於this的呼叫方式MDN中的this章節developer.mozilla.org/zh-CN/docs/…說明比較詳細,有興趣的小夥伴可以去看看。

相關文章