JavaScript中的this淺談

this在全局中調用時指向的是全局對象。
this在函數中調用時指向調用函數的對象,調用函數的在不一樣狀況下有javascript

1.直接調用,此時函數內部的this指向全局對象
2.做爲對象的方法,此時this指向該對象
3.構造函數,此時this指向構造的實例對象
4.call/apply改變this指向

this是Javascript語言的一個關鍵字。
它表明函數運行時,自動生成的一個內部對象,只能在函數內部使用。好比,html

  function test(){
    this.x = 1;
  }

隨着函數使用場合的不一樣,this的值會發生變化。可是有一個總的原則,那就是this指的是,調用函數的那個對象。
下面分四種狀況,詳細討論this的用法。java

狀況一:純粹的函數調用

這是函數的最一般用法,屬於全局性調用,所以this就表明全局對象global/window(在瀏覽器中全局對象即頂層對象指的是window,在nodejs中全局對象指的是global)。
請看下面這段代碼,它的運行結果是1。node

  function test(){
    this.x = 1;
    alert(this.x);
    alert(this === window);
  test(); 
    // 1
    //true

爲了證實this就是全局對象,我對代碼作一些改變:瀏覽器

  var x = 1;
  function test(){
    alert(this.x);
  }
  test(); // 1

運行結果仍是1。再變一下:app

  var x = 1;
  function test(){
    this.x = 0;
  }
  test();
  alert(x); //0

當調用函數test()後,執行this.x 語句,而這裏的this.x指向的是全局的x,因此全局的x=1在這個時候變成x=0,因此在最後alert(x)的時候數據0。
從這裏能夠看出函數裏的 this.x 指的是全局變量x裏吧。函數

那若是是帶有參數的函數呢?再來看看下面的例子:this

var a = 20;
function fun(a){
    this.a = 1;
    console.log(a);
    console.log(this.a);
};
fun(10); 
//10
//1

當函數帶有參數時,this依舊指向全局的變量,與參數沒有任何關係,上面的寫法就相似於下面的這種寫法。code

var a = 20;
function fun(b){
    this.a = 1;
    console.log(b);
    console.log(this.a);
};
fun(10); 
//10
//1

若是把this.a改爲this.b呢?那this.b指向的是全局的變量仍是函數裏面的變量呢?htm

var a = 20;
function fun(b){
    this.b = 1;            //沒有用var 至關於定義了一個全局變量b,並賦值爲1
    console.log(b);        //10 打印出傳入的參數b
    console.log(this.b);   //1  打印出全局變量b
};
fun(10);
console.log(b); //1 打印出全局變量b

JavaScript裏規定,全局函數裏沒有用var定義的的變量是全局變量,因此這裏的this.b就至關於定義了一個全局的變量b,因此在最後能打印出變量b

如今你能看懂下面兩個函數了吧

var a = 20;
function fun(a){
    this.a = 1;
    console.log(a)
};
console.log(a);//20 沒有執行this.a=1 語句時,全局變量a依舊爲20
fun(10);//10

var a = 20;
function fun(a){
    this.a = 1;
    console.log(a)
};
fun(10);//10
console.log(a);//1 執行this.a=1 語句後,全局變量a變爲1

狀況二:做爲對象方法的調用

函數還能夠做爲某個對象的方法調用,這時this就指這個上級對象。

  function test(){
    alert(this.x);
  }
  var o = {};
  o.x = 1;
  o.m = test;
  o.m(); // 1

或者用對象字面量來建立方法是好理解些,但都是一個意思

var pet = {
    words : 'my dear',
    speak : function(){
        console.log(this.words);   //my dear
        console.log(this === pet); //true
    }
}

pet.speak();

狀況三 做爲構造函數調用

所謂構造函數,就是經過這個函數生成一個新對象(object)。這時,this就指這個新對象。

  function test(){
    this.x = 1;
  }
  var o = new test();
  alert(o.x); // 1

運行結果爲1。爲了代表這時this不是全局對象,我對代碼作一些改變:

  var x = 2;
  function test(){
    this.x = 1;
  }
  var o = new test();
  alert(x); //2

運行結果爲2,代表全局變量x的值根本沒變。
再來看一個在實際應用中的例子

function Pet(words){
    this.words = words;

    this.speak = function(){
        console.log(this.words);
        console.log(this)
    }
}

var cat = new Pet('Miao');
cat.speak();
//當nwe了一個實例對象cat後,cat擁有了本身的word屬性和speak方法,而cat.speak()調用時this指的的是cat對象本身
// Miao
//Pet { words: 'Miao', speak: [Function] }

狀況四 apply、call調用

apply()是函數對象的一個方法,它的做用是改變函數的調用對象,它的第一個參數就表示改變後的調用這個函數的對象。所以,this指的就是這第一個參數。
  var x = 0;
  function test(){
    alert(this.x);
  }
  var o={};
  o.x = 1;
  o.m = test;
  o.m.apply(); //0
apply()的參數爲空時,默認調用全局對象。所以,這時的運行結果爲0,證實this指的是全局對象。
若是把最後一行代碼修改成
  o.m.apply(o); //1
運行結果就變成了1,證實了這時this表明的是對象o。

apply有兩種實際的應用場景:
1.在對象中--調用時才改變this指向,如上例子,也許下面的例子好理解些

var pet = {
    words : 'my dear',
    speak : function(say){
        console.log(say + ' ' +this.words)
    }
}

pet.speak('hello');//hello my dear

//利用apple調用時改變this的指向
var dog = {
    words :'wang'
}
pet.speak.call(dog,'hello');//hello wang
pet.speak('hello')//hello my dear

2.實現繼承時的構造函數--定義時改變this指向

function Pets(words,sex){
    this.words = words;
    this.sex = sex;
    this.speak = function(){
        console.log(this.words + ' ' + this.sex)
    }
}

function Dog(words,sex){
    //Pets.call(this, words, sex);
    //Pets.apply(this,[words, sex])
    Pets.apply(this,arguments)
}

var dog  = new Dog('wang','girl')
dog.speak();//wang,girl



參考資料:
1.《JavaScript的this用法》--阮一峯

相關文章
相關標籤/搜索