this 繫結解析

sandy_anqi發表於2019-03-18

1.this 一般繫結

在全域性執行上下文中,this 指向 全域性的window物件。在函式執行上下文中,this的值取決於該函式的呼叫方式,若是通過被一個引用物件呼叫,那麼 this 會被設定成那個物件,否則,this 繫結在 全域性 window 物件上或是 undefined(嚴格模式上)
    let foo = {
        a: 'foo',
        bar: function() {
            console.log(this, this.a)
        }
    }

    foo.bar(); // 指向 foo,a==foo
    var a = 'window';
    let bar = foo.bar;
    bar(); // 指向 window ,a==window,若對a 的定義,使用let,則this.a為undefined,因為 let 定義變數不會繫結全域性作用域複製程式碼


2.使用箭頭函式改變 this 的繫結 

請大家考慮:

var a='window';
let foo={
	a:'foo',
	bar:()=>{
	    console.log(this,this.a)
	}
}
foo.bar()
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …} "window"複製程式碼

儘管我們以 foo.bar( ) 的形式呼叫,this.a 依舊不是指向 foo 這個物件。this 指向 wondow 的原因是,它是從包圍的作用域中詞法繼承而來的 this 。(換句話說,就是箭頭函式的 this 指向當前作用域的父級作用域)

注:箭頭函式實現原理看下面第四點~

3.其他常見 this 修改繫結

  • call : fn.call(targetObj,a,b ...)

targetObj 表示繫結的物件,a , b ... 表示呼叫函式 fn 的引數,引數展開寫就可以

var fn={
	a:'fn',
	make:function(m,n) {console.log(this.a,m+n)}
}
var bar={
	a:'bar'
}
fn.make.call(bar)
// bar 3複製程式碼

  • apply : fn.apply(targetObj,[a,b,...])

targetObj 表示繫結的物件,a , b ... 表示呼叫函式 fn 的引數,引數存放在陣列

var fn={
	a:'fn',
	make:function(m,n) {console.log(this.a,m+n)}
}
var bar={
	a:'bar'
}
fn.make.apply(bar,[1,2])
// bar 3複製程式碼

  • bind : fn.bind(targetObj , a ,b ... )()

targetObj 表示繫結的物件,a,b ... 表示呼叫函式的引數,引數展開書寫即可。bind 區別於 call 和 apply ,bind 返回的是函式,需要呼叫才會執行

var fn={
	a:'fn',
	make:function(m,n) {console.log(this.a,m+n)}
}
var bar={
	a:'bar'
}
fn.make.bind(bar,1,2)()
// bar 3複製程式碼

4.箭頭函式實現原理補充

箭頭函式的主要設計目的就是以特定的方式改變 this 的行為特徵。

接下來我們來觀察它是如何實現的,請看以下程式碼:

var controller = {
      make:function(...) {
          btn.addEventListener ("click",function(){
                this.make();
        },false)
      }
}
複製程式碼

以上程式碼執行時是會報語法錯誤的。錯誤的原因即是:this 繫結是動態性的,程式碼中的 this 和make()本身的this繫結是不同的,所以會造成錯誤。

以下是上面程式碼的正確寫法,使用 var self = this 這一hack(變數 self 依賴於詞法作用域的可預測性)

ar controller = {
      make:function(...) {
          var self = this;
          btn.addEventListener ("click",function(){
                self.make();
        },false)
      }
}
複製程式碼

在前面的程式碼中,如果使用箭頭函式作為回撥, this 則如我們所願是可預測的。


考慮:

var controller = {
      make:function(...) {
          btn.addEventListener ("click",()=>{
                this.make();
        },false)
      }
}
複製程式碼

前面程式碼的箭頭函式回撥中的詞法 this 現在與封裝函式 make()指向同樣的值,也就是說,=> 是 var self = this 的詞法替代形式


你的喜歡就是我寫作的最大動力 ~

                                                     歡迎大家留言共同討論 ~ 


相關文章