淺談 javascript 中的this綁定問題

javascript語言是在運行時前即進行編譯的,而this的綁定也是在運行時進行綁定的。也就是說,this其實是在函數被調用時候發生綁定的,它指向什麼徹底取決於函數在哪裏被調用。

1.默認綁定javascript

例如直接在全局做用域下聲明:java

var a=2;
console.log(this.a);
  • 在全局做用域下聲明的變量或者函數等,都會做爲window對象的屬性。
  • 這個時候,默認this是綁定到全局做用域下的window對象,若是你去console.log(this);你會發現,你打印出來的是window,儘管你沒有聲明this就是window,可是js進行了默認綁定。
以致於你運行如下的代碼片斷:
function foo(){
console.log(this.a);
}
var a=2;
foo();
瀏覽器控制檯打印出來的是 2 ;

2.隱式綁定程序員

當函數引用有上下文對象時,在函數調用時,會進行隱式綁定。這麼說確定很抽象,仍是舉例說明吧。
var a=4;
function foo(){
console.log(this.a);
}
var obj={
  a:2,
  foo:foo
}
foo();
obj.foo();
兩次會打印出來什麼呢?猜一下?
  • foo()會打印出來4,obj.foo()會打印出來2
  • 第一個foo() 使用了默認綁定,this綁定到了全局對象window,打印 this.a 就是打印window.a;
  • 第二個foo()外層的foo函數引用做爲obj.foo的屬性值,經過obj進行調用,此時的obj就是這個函數引用的上下文對象,this會隱式綁定到obj這個對象上。此時打印的this.a就是obj.a了。

3.顯式綁定瀏覽器

在上面兩種綁定中,咱們都沒有去明確地進行強制綁定,而是使用了默認規則的綁定,那麼若是咱們想要在調用某個函數時特定地改變this的綁定,這個時候就能夠用顯式綁定了。

仍是上代碼,而後進行分析。app

var a=4;
function foo(){
console.log(this.a);
}
var obj={
  a:2,
  foo:foo
}
var foo1=foo.bind(obj);
foo();
foo.call(obj);
foo.apply(obj);
foo.call(window);
foo1();
按照順序打印出的是 4 ,2 ,2, 4,2
  • 第一次打印了4 使用了默認綁定,foo函數的this綁定到了window。
  • 第二次打印了2 使用了call函數,顯式地將foo函數的this綁定到obj對象。
  • 第三次打印了2 apply方法的效果跟call方法同樣。
  • 第四次打印了4 call方法顯示地將foo函數的this綁定到了obj對象,效果跟默認綁定同樣了。
  • 第五次打印了2,bind方法顯示地將foo函數的this綁定到了obj,而且返回了一個硬編碼後的新函數,賦值給foo1變量進行調用,硬編碼就是新函數內部this直接綁定到了指定的對象,也就是obj。

4.new 綁定框架

使用new方式進行調用函數時,會發生構造函數的調用。怎麼解釋呢,仍是直接上代碼加分析。
function foo(a){
 this.a=a;
}
foo(3);
var test=new foo(2);
console.log(a);
console.log(test.a);
打印出來的是 3 ,2
  • foo函數只是一個普通的函數,直接調用foo(3)只是做爲普通函數的調用,會使用默認綁定將this綁定到window上,對window.a也就會全局變量a進行賦值,因此打印出來的是3;
  • foo函數,進行構造調用,this綁定到test對象,故而this.a做爲test對象的屬性並進行傳參賦值。打印出來的test就是{a:2},this.a就是2了。
先上圖,而後根據文字閱讀

圖片描述

使用new 調用函數以後,該foo函數才做爲構造函數進行調用,構造一個全新的對象賦值給test,而test對象的_proto_
指向了test的prototype對象,test的prototype對象有一個屬性constructor,指向test的構造函數foo,這個就是javascript的原型鏈,也是javascript的特性。對於test對象調用的方法以及屬性,會先在test對象進行尋找,若是找到的話,就直接進行調用,尋找中止。若是尋找不到,順着原型鏈,在test對象的prototype對象尋找,若是找到的話,進行調用,尋找中止,若是仍是找不到,會在prototype對象的原型上進行尋找,這個時候_proto_指向了Object的prototype對象,Object的prototype的constructor指向了Object()自己,而一些Obejct的函數如toString等等就是在這個原型上進行調用的,這個時候若是仍是找不到須要屬性或者方法,那麼就是語法錯誤,未定義了。由於Object的prototype的_proto_指向是null了,也就沒有任何對象屬性以及方法了。

不是說程序員能夠new 不少個對象嘛,可是new出來的對象 原型最終結果倒是指向了 空(null),因此仍是本身動手豐衣足食吧,哈哈。函數

通常狀況下,使用new函數以後構造的對象,會優先將函數調用到的this綁定到這個對象,若是函數沒有返回其它對象,會自動調用返回這個新對象。this

總結:編碼

只有對於this綁定的狀況有了基本的瞭解,才能在編寫代碼時候,避免產生因爲綁定帶來的未知bug。若是你在調用某個框架插件或者綁定事件的時候,發現this很差用了,有多是你的this使用綁定錯了,打印下console.log(this)在控制檯看一看,也許就發現問題了。

若是在閱讀中遇到什麼問題,歡迎評論以及留言。同時歡迎個人博客陳建光的博客spa

歡迎評論以及留言,同時歡迎關注個人博客定時不斷地更新個人文章 陳建光的博客

相關文章
相關標籤/搜索