關於JavaScript中的this


1.關於this的誤會。

  誤會(1):this指向所在函數本身。

    我們常常會對this產生各種誤會,比如說我們可能認為this會指向所在函數本身,但實際上並非如此。

  

1 function foo (){
2     this.count ++;
3 }
4 foo.count = 0;
5 for(var i=0;i<5;i++){
6     foo();
7 }
8 console.log(foo.count);

    上面的例子旨在使用函數的this指向this,通過foo函數的count屬性計算foo被調用的次數。根據這個目的,輸出應該是5,因為for循環了五次,foo函數被調用了5次。但實際上呢?

    我們新建一個js文件,命名為test.js,代碼如下:

    實際輸出如下:

    輸出的foo.count值為0。看上去foo中的this並沒有指向foo,那么this指向了哪里呢?

  

 

    通過chrome JavaScript調試器可以發現,this指向了window全局作用域,並沒有如我們預期的指向foo本身。

  誤會(二):this指向函數所在作用域

    通過上面的例子,可能你很快就能得出結論:this指向所在函數所在的作用域。比如上一個例子中,函數foo位於全局作用域(在宿主環境中就是window),foo中的this便指向了全局作用域,但是果真如此嗎?

    

 1 function foo (){
 2     var count = 0;
 3     function bar (){
 4            this.count ++;
 5     }
 6     for(var i=0;i<5;i++){
 7            bar();          
 8     }
 9     return count;
10 }

    上面的代碼,旨在foo內部,聲明一個bar函數用於控制foo作用域內的count變量,實現計算bar被調用次數的功能。理論上,bar函數中的this應該會指向bar所在的作用域,所以this也可以調用count(和bar函數同作用域),應該輸出為5。但實際輸出呢?

    實際輸出仍然為0!說明this根本沒有指向bar所在的作用域,那么this指向哪了呢?

    實際上,this還是指向了window作用域,真是非常神奇。

    要想了解this的工作方式,我們先了解一下this的綁定方式。

2.this的綁定規則

   (1)默認綁定

      當函數獨立調用時,這條規則就是無法應用其他規則時的默認規則。

       直接使用不帶任何修飾的函數,this會指向全局環境。

        

1 function foo (){
2      this.count = 100;
3 }
4 foo();         //直接使用,函數未經修飾
5 console.log(window.count);       //輸出全局環境中的count變量,就是函數中的this.count,結果為100

        但是this不總是指向全局環境,當使用嚴格模式時,this會被禁止指向全局環境。

1 function foo (){
2      "use strict";    //使用嚴格模式
3      this.count = 100;
4 } 
5 foo();
6 console.log(window.count);  //輸出:Uncaught TypeError: Cannot set property 'count' of undefined

    (2)隱式綁定:

       

1 function foo (){
2      console.log(this.count);
3 }
4 var obj = {
5      count:100,
6      foo:foo
7 };
8 obj.foo();    //輸出100

        當所調用的函數是某個對象的成員函數時,函數中的this會指向函數所在的對象。

        隱式綁定可能會存在綁定丟失的場景,當函數作為參數傳入到另外一個函數時,作為參數的函數所綁定的this會失效。

 1 function foo(){
 2      console.log(this.count);
 3 }
 4 function bar (func){
 5      func();
 6 }
 7 var count = 0;
 8 var obj = {
 9      count : 100,
10      foo : foo
11 };
12 bar(obj.foo);      //會輸出0

        如上例,當obj.foo作為參數傳入到函數bar時,原來綁定的this指向obj被修改為指向全局變量window。所以使用回調函數,可能會修改傳入參數函數的this指向。

    (3)顯式綁定

       使用call()或者apply()函數可以顯式強制的綁定函數的this。

        

function foo (){
     console.log(this.count);
}
var count = 'window!';
var obj1 = {
     count : 100,
     foo : foo
};
var obj2 = {
     count : 200,
     foo : foo
};
foo.call(obj1);   //輸出100
foo.call(obj2);   //輸出200

        如上例所示,call兩次修改了foo的this指向。使其指向某個固定的對象。當call的傳入的第一個參數為null時,所修改函數的this指向不會被顯式修改。

     (4)new 綁定

         使用new操作符,可以將函數的this指向新創建的對象。

       

function Foo(name, age){
     this.name = name;
     this.age = age; 
} 
var obj = new Foo('Tom',99);
console.log(obj);

        輸出如下:

 

          新構建的obj對象具有了一系列屬性,都是用函數Foo中的this所實現。

        通過這個原理,我們可以簡單的實現一個_new_函數,以實現new操作符的功能。

         

function _new_ (func , arr){
    var obj = {};
    func.apply(obj,arr);
    return obj;
}
function Foo (name, age){
    this.name = name;
    this.age = age;
}
var obj = _new_(Foo,['Jerry',99]);
console.log(obj);

         輸出的obj如下:

        說明基本的傳參構造對象功能已經實現了。

 

3.四種綁定規則的優先級

    new綁定 > 顯示綁定 >隱式綁定 > 默認綁定

    判斷this綁定的順序:

      1.判斷是否是new調用,是的話就是new綁定,函數中的this會指向新構造的對象。

          2.判斷是否是顯示綁定,即是否是通過函數原型中的apply方法或者call方法調用 (還要注意bind返回的函數,this指向也會被修改)。

          3.判斷是否是隱式綁定,及通過某個對象調用。是的話,this會指向所屬對象。

          4.如果都沒有的話,就是默認綁定,this指向全局對象window;嚴格模式下指向undefined。

 

 

……更過this相關,有待補充,如有錯誤,歡迎指正!

 

 

  

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: