Javascript this 的一些學習總結01【轉自cnblogs的JKhuang】

摘要編程

相信有C++、C#或Java等編程經驗的各位,對於this關鍵字再熟悉不過了。因爲Javascript是一種面向對象的編程語言,它和C++、C#或Java同樣都包含this關鍵字,接下來咱們將向你們介紹Javascript中的this關鍵字。瀏覽器

正文編程語言

因爲許多面向對象的編程語言都包含this關鍵字,咱們會很天然地把this和麪向對象的編程方式聯繫在一塊兒,this一般指向利用構造器新建立出來的對象。而在ECMAScript中,this不只僅只用來表示建立出來的對象,也是執行上下文的一個屬性:函數

activeExecutionContext = {
  // Variable object.
  VO: {...},
  this: thisValue
};

全局代碼中的thisthis

// Global scope
// The implicit property of 
// the global object
foo1 = "abc";
alert(foo1); // abc
 
// The explicit property of 
// the global object
this.foo2 = "def";
alert(foo2); // def

// The implicit property of 
// the global object
var foo3 = "ijk";
alert(foo3); // ijk

前面咱們經過顯式和隱式定義了全局屬性foo一、foo2和foo3,因爲this在全局上下文中,因此它的值是全局對象自己(在瀏覽器中是window object);接下來咱們將介紹函數中的this。code

函數中的this對象

當this在函數代碼中,狀況就複雜多了,而且會引起不少的問題。ip

函數代碼中this值的第一個特性(同時也是最主要的特性)就是:它並不是靜態的綁定在函數上。ci

正如此前提到的,this的值是在進入執行上下文(Excution context)的階段肯定的,而且在函數代碼中的話,其值每次都不盡相同。it

然而,一旦進入執行代碼階段,其值就不能改變了。若是要想給this賦一個新的值是不可能的,由於在那時this根本就不是變量了。

接下來,咱們經過具體的例子說明函數中的this。

首先咱們定義兩個對象foo和person,foo包含一個屬性name,而person包含屬性name和方法say(),具體的定義以下:

// Defines foo object.
var foo = {
    name: "Foo"
};

// Defines person object.
var person = {
    name: "JK_Rush",
    say: function() {
        alert(this === person);
        alert("My name is " + this.name);
    }
};

person.say();  // My name is JK_Rush

// foo and person object refer to 
// the same function say
foo.say = person.say;

foo.say();    // My name is Foo.

經過上面的代碼,咱們發現調用person的say()方法時,this指向person對象,當經過賦值方式使得foo的say()方法指向peson中的say()方法時。咱們調用foo的say()方法,發現this不是指向person對象,而不是指向foo對象,這到底是什麼緣由呢?

首先,咱們必須知道this的值在函數中是非靜態的,它的值肯定在函數調用時,具體代碼執行前,this的值是由激活上下文代碼的調用者決定的,好比說,調用函數的外層上下文;更重要的是,this的值是由調用表達式的形式決定的,因此說this並不是靜態的綁定在函數上

因爲this並不是靜態地綁定在函數上,那麼咱們是否能夠在函數中動態地修改this的值呢?

// Defines foo object.
var foo = {
    name: "Foo"
};

// Defines person object.
var person = {
    name: "JK_Rush",
    say: function() {
        alert(this === person);
        this = foo;  // ReferenceError
        alert("My name is " + this.name);
    }
};

person.say();  // My name is JK_Rush

如今咱們在方法say()中,動態地修改this的值,當咱們從新執行以上代碼,發現this的值引用錯誤。這是因爲一旦進入執行代碼階段(函數調用時,具體代碼執行前),this的值就肯定了,因此不能改變了。

引用類型

前面咱們提到this的值是由激活上下文代碼的調用者決定的,更重要的是,this的值是由調用表達式的形式決定的;那麼表達式的形式是如何影響this的值呢?

首先,讓咱們介紹一個內部類型——引用類型,它的值能夠用僞代碼表示爲一個擁有兩個屬性的對象分別是:base屬性(屬性所屬的對象)以及該base對象中的propertyName屬性:

// Reference type.
var valueOfReferenceType = {
  base: mybase,
  propertyName : 'mybasepropertyName' 
};

引用類型的值只有多是如下兩種狀況:

  • 當處理一個標識符的時候

  • 或者進行屬性訪問的時候

標識符其實就是變量名、函數名、函數參數名以及全局對象的未受限的屬性

// Declares varible.
var foo = 23;

// Declares a function
function say() {
    // Your code.
}

中間過程當中,對應的引用類型以下:

// Reference type.
var fooReference = {
  base: global,
  propertyName: 'foo'
};
 
var sayReference = {
  base: global,
  propertyName: 'say'
};

咱們知道Javascript中屬性訪問有兩種方式:點符號和中括號符號:

// Invokes the say method.
foo.say();
foo['say']();

因爲say()方法是標識符,因此它對應於foo對象引用類型以下:

// Reference type.
var fooSayReference = {
  base: foo,
  propertyName: 'say'
};

咱們發現say()方法的base屬性值爲foo對象,那麼它對應的this屬性也將指向foo對象。

假設,咱們直接調用say()方法,它對應的引用類型以下:

// Reference type.
var sayReference = {
  base: global,
  propertyName: 'say'
};

因爲say()方法的base屬性值爲global(一般來講是window object),那麼它對應的this屬性也將指向global。

函數上下文中this的值是函數調用者提供而且由當前調用表達式的形式而定的。若是在調用括號()的左邊有引用類型的值,那麼this的值就會設置爲該引用類型值的base對象。 全部其餘狀況下(非引用類型),this的值老是null。然而,因爲null對於this來講沒有任何意義,所以會隱式轉換爲全局對象。

函數調用以及非引用類型

前面咱們提到,當調用括號左側爲非引用類型的時,this的值會設置爲null,並最終隱式轉換爲全局對象。

如今咱們定義了一個匿名自執行函數,具體實現以下:

// Declares anonymous function
(function () {
  alert(this); // null => global
})();

因爲括號()左邊的匿名函數是非引用類型對象(它既不是標識符也不屬於屬性訪問),所以,this的值設置爲全局對象。

// Declares object.
var foo = {
  bar: function () {
    alert(this);
  }
};
 
(foo.bar)();          // foo.
(foo.bar = foo.bar)(); // global?
(false || foo.bar)();  // global?
(foo.bar, foo.bar)();  // global

這裏注意到四個表達式中,只有第一個表達式this是指向foo對象的,而其餘三個表達式則執行global。

如今咱們又有疑問了:爲何屬性訪問,可是最終this的值不是引用類型對象而是全局對象呢?

咱們注意到表達式二是賦值(assignment operator),與表達式一組操做符不一樣的是,它會觸發調用GetValue方法(參見11.13.1中的第三步)。 最後返回的時候就是一個函數對象了(而不是引用類型的值了),這就意味着this的值會設置爲null,最終會變成全局對象。

第三和第四種狀況也是相似的——逗號操做符和OR邏輯表達式都會觸發調用GetValue方法,因而相應地就會丟失原先的引用類型值,變成了函數類型,this的值就變成了全局對象了。

相關文章
相關標籤/搜索