深刻理解javaScript系列:各類上下文中的this

1.this關鍵字在何處出現?javascript

  this他只能出如今函數中。固然在全局做用域中是個例外,意思是this只可能在兩種情境下出現,一個是在函數體內,另外一個是在全局做用域。java

2.this是什麼?數組

  this是關鍵字,語言規範裏規定他指向函數執行時的當前對象。它表明函數運行時,自動生成的一個內部對象,只能在函數內部使用。瀏覽器

3.this到底指向哪?app

  首先明確this在JavaScript中和函數的執行環境而不是聲明環境相關。函數

  第一條中已經說過,this只能出如今函數中和全局做用域中,全局做用域中this指向全局對象(全局對象在瀏覽器這個環境中指window)。this

  若是this出如今函數中,那就要分狀況來看this到底指向哪了。指向的依據就是函數的執行環境而不是聲明環境。其實能夠以一句話來歸納就是this永遠指向所在函數的全部者,當沒有顯示的全部者的時候,那麼this指向全局對象。spa

4.各類狀況下的this的具體指向?prototype

  (1).全局做用域code

1
console.log( this )

  直接在全局做用域中打印this,其指向爲window。

  因此在全局做用域中this指向全局對象。

  (2).函數做爲某個對象的成員方法調用

1
2
3
4
5
6
7
8
var  name =  "chirenmiao1" ;
var  obj= {
     name:  "chirenmiao2" ,
     getName:  function  () {
         console.log( this .name);
     }
}
obj.getName(); //chirenmiao2

  

  在全局做用域中聲明全局變量name,在obj對象中聲明同時也聲明一個name。當用對象obj調用他的成員方法getName的時候,this指向這個obj,所以打印出來的this.name爲obj的name。

  因此函數做爲某個對象的成員方法調用時this指向該對象。

  (3).函數做爲函數直接使用

1
2
3
4
5
6
7
8
9
var  name =  "chirenmiao1" ;
var  obj= {
     name:  "chirenmiao2" ,
     getName:  function  () {
         console.log( this .name);
     }
}
var  getName= obj.getName;
getName();    //chirenmiao1

  一樣的仍是上邊的一段代碼,只不過此次咱們把getName這個函數直接執行,這時在函數執行的時候他沒有明確的當前對象,因此默認這時this就指向了全局對象。

  因此函數做爲函數直接使用時this指向全局對象。

  

1
2
3
4
function  myFun() {
     console.log( this );
}
myFun();

  還有就是函數聲明直接執行的時候,this也指向全局對象。

  其實上邊三條就已經簡單覆蓋了this指向的全部狀況,下面緊接着講述一些稍微特殊的狀況。

  (4).函數做爲構造函數調用

1
2
3
4
5
6
7
8
9
var  name =  'chirenmiao1' ;
var  Obj =  function  (x, y) {
     this .name =  'chirenmiao2' ;
}
Obj.prototype.getName =  function  () {
     console.log( this .name);
}
var  myObj =  new  Obj();
myObj.getName(); //chirenmiao2

  函數做爲構造函數調用時this指向用該構造函數構造出來的新對象。

  (5).setTimeout和setInterval以及匿名函數

1
2
3
4
5
6
7
8
9
10
11
var  name =  "chirenmiao1" ;
var  obj = {
     name:  "chirenmiao2" ,
     getName:  function  () {
         setTimeout( function  () {
             console.log( this .name);
         }, 1000);
     },
};
 
obj.getName(); //chirenmiao1

  這兩個函數執行的時候第一個參數能夠爲一個匿名函數,也能夠是一個聲明好的函數引用,因此this指向也就是指這個匿名函數或者函數引用的this的指向。經過第一條已經知道匿名函數或者在全局做用域中聲明的函數直接執行的時候,其中的this指向全局對象,因此在這裏也同樣,setTimeout和setInterval二者運行時,this指向全局對象。

  這個時候若是還想輸出的是chirenmiao2,也就是this指向obj的話就須要作點手腳了。

1
2
3
4
5
6
7
8
9
10
11
12
var  name =  "chirenmiao1" ;
var  obj = {
     name:  "chirenmiao2" ,
     getName:  function  () {
         var  self =  this ;
         setTimeout( function  () {
             console.log(self.name);
         }, 1000);
     },
};
 
obj.getName(); //chirenmiao2

  固然這樣是改變不了this指向的,可是能夠經過把this賦值給self,就實現了保存this指向的做用。

  緊接着是匿名函數。

1
2
3
( function  () {
     console.log( this );
})() //window

  匿名函數中的this指向全局對象,由於他沒有顯示的全部者。

  (6)apply、call、bind

  這三個函數是函數對象的一個方法,他們的做用就是爲了改變函數執行時候的this指向,具體用法以下:

  call:call(obj[,arg1][,arg2]);第一個參數爲強制改變須要指向的對象,後邊可選的是該函數的參數,若是不傳obj的話默認爲window。

  apply:apply(obj[,arr]);第一個參數爲強制改變須要指向的對象,後邊可選的是該參數集合的數組形式,若是不傳obj的話默認爲window。

  apply和call的做用和調用形式基本一致,不一樣的是call後面的參數與方法中是一一對應的,而apply的第二個參數是一個數組,數組中的元素是和方法中一一對應的,這就是二者最大的區別。二者均可以不傳參數,此時默認改變指向的對象爲全局對象。

  bind:bind的調用形式和call相同,可是他返回的是改變調用對象後的函數引用,因此還要再執行一次,也就是obj.fun().bind()()。

總結:this做爲函數運行時,自動生成的一個內部對象,只能在函數內部使用。具體this指向誰,要看this的全部函數是誰調用的,具體狀況可分爲全局做用域、做爲某對象的方法調用、直接執行、匿名函數直接執行、call、apply、bind強制改變調用對象等。

相關文章
相關標籤/搜索