1. 程式人生 > >javascript中this用法例項詳解

javascript中this用法例項詳解

JavaScript中的this含義非常豐富,它可以是全域性物件,當前物件或者是任意物件,這都取決於函式的呼叫方式。函式有以下幾種呼叫方式:作為物件方法呼叫、作為函式呼叫、作為建構函式呼叫、apply或call呼叫。

物件方法呼叫

作為物件方法呼叫的時候,this會被繫結到該物件。

?

1

2

3

4

5

6

7

8

9

var point = {

 x : 0,

 y : 0,

 moveTo : function(x, y) {

   this.x = this.x + x;

   

this.y = this.y + y;

   }

};

point.moveTo(1, 1)//this 繫結到當前物件,即 point 物件

這裡我想強調一點內容,就是this是在函式執行的時候去獲取對應的值,而不是函式定義時。即使是物件方法呼叫,如果該方法的函式屬性以函式名的形式傳入別的作用域,也會改變this的指向。我舉一個例子:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

var a = {

  aa : 0,

  bb : 0,

  fun : function(x,y){

    this.aa = this.aa + x;

    this.bb = this.bb + y;

  }

};

var aa = 1;

var b = {

  aa:0,

  bb:0,

  fun : function(){return this.aa;}

}

a.fun(3,2);

document.write(a.aa);

//3,this指向物件本身

document.write(b.fun());//0,this指向物件本身

(function(aa){//注意傳入的是函式,而不是函式執行的結果

  var c = aa();

  document.write(c);//1 , 由於fun在該處執行,導致this不再指向物件本身,而是這裡的window

})(b.fun);

這樣就明白了吧。這是一個容易混淆的地方。

函式呼叫

函式也可以直接被呼叫,這個時候this被繫結到了全域性物件。

?

1

2

3

4

5

6

var x = 1;

function test(){

  this.x = 0;

}

test();

alert(x); //0

但這樣就會出現一些問題,就是在函式內部定義的函式,其this也會指向全域性,而和我們希望的恰恰相反。程式碼如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

var point = {

 x : 0,

 y : 0,

 moveTo : function(x, y) {

   // 內部函式

   var moveX = function(x) {

   this.x = x;//this 繫結到了全域性

  };

  // 內部函式

  var moveY = function(y) {

  this.y = y;//this 繫結到了全域性

  };

  moveX(x);

  moveY(y);

  }

};

point.moveTo(1, 1);

point.x; //==>0

point.y; //==>0

x; //==>1

y; //==>1

我們會發現不但我們希望的移動呢效果沒有完成,反而會多出兩個全域性變數。那麼如何解決呢?只要要進入函式中的函式時將this儲存到一個變數中,再運用該變數即可。程式碼如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

var point = {

 x : 0,

 y : 0,

 moveTo : function(x, y) {

   var that = this;

   // 內部函式

   var moveX = function(x) {

   that.x = x;

   };

   // 內部函式

   var moveY = function(y) {

   that.y = y;

   }

   moveX(x);

   moveY(y);

   }

};

point.moveTo(1, 1);

point.x; //==>1

point.y; //==>1

建構函式呼叫

在javascript中自己建立建構函式時可以利用this來指向新建立的物件上。這樣就可以避免函式中的this指向全域性了。

?

1

2

3

4

5

6

var x = 2;

function test(){

  this.x = 1;

}

var o = new test();

alert(x); //2

apply或call呼叫

這兩個方法可以切換函式執行的上下文環境,也就是改變this繫結的物件。apply和call比較類似,區別在於傳入引數時一個要求是陣列,一個要求是分開傳入。所以我們以apply為例:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

var name = "window";

var someone = {

  name: "Bob",

  showName: function(){

    alert(this.name);

  }

};

var other = {

  name: "Tom"

};

someone.showName();   //Bob

someone.showName.apply();  //window

someone.showName.apply(other);  //Tom

可以看到,正常訪問物件中方法時,this指向物件。使用了apply後,apply無引數時,this的當前物件是全域性,apply有引數時,this的當前物件就是該引數。

箭頭函式呼叫

這裡需要補充一點內容,就是在下一代javascript標準ES6中的箭頭函式的 this始終指向函式定義時的 this,而非執行時。我們通過一個例子來理解:

?

1

2

3

4

5

6

7

8

9

10

var o = {

  x : 1,

  func : function() { console.log(this.x) },

  test : function() {

    setTimeout(function() {

      this.func();

    }, 100);

  }

};

o.test(); // TypeError : this.func is not a function

上面的程式碼會出現錯誤,因為this的指向從o變為了全域性。我們需要修改上面的程式碼如下:

?

1

2

3

4

5

6

7

8

9

10

11

var o = {

  x : 1,

  func : function() { console.log(this.x) },

  test : function() {

    var _this = this;

    setTimeout(function() {

      _this.func();

    }, 100);

  }

};

o.test();

通過使用外部事先儲存的this就行了。這裡就可以利用到箭頭函數了,我們剛才說過,箭頭函式的 this始終指向函式定義時的 this,而非執行時。所以我們將上面的程式碼修改如下:

?

1

2

3

4

5

6

7

8

var o = {

  x : 1,

  func : function() { console.log(this.x) },

  test : function() {

    setTimeout(() => { this.func() }, 100);

  }

};

o.test();

這回this就指向o了,我們還需要注意一點的就是這個this是不會改變指向物件的,我們知道call和apply可以改變this的指向,但是在箭頭函式中是無效的。

?

1

2

3

4

5

6

7

var x = 1,

  o = {

    x : 10,

    test : () => this.x

  };

o.test(); // 1

o.test.call(o); // 依然是1

這樣就可以明白各種情況下this繫結物件的區別了。