1. 程式人生 > >Javasctipt學習筆記(this關鍵字)

Javasctipt學習筆記(this關鍵字)

this 關鍵字

目錄

涵義

this關鍵字是一個非常重要的語法點。毫不誇張地說,不理解它的含義,大部分開發任務都無法完成。

首先,this總是返回一個物件,簡單說,就是返回屬性或方法“當前”所在的物件。

this.property

上面程式碼中,this就代表property屬性當前所在的物件。

下面是一個實際的例子。

var person = {
  name: '張三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

person
.describe() // "姓名:張三"

上面程式碼中,this.name表示describe方法所在的當前物件的name屬性。呼叫person.describe方法時,describe方法所在的當前物件是person,所以就是呼叫person.name

由於物件的屬性可以賦給另一個物件,所以屬性所在的當前物件是可變的,即this的指向是可變的。

var A = {
  name: '張三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

var B = {
  name: '李四'
}; B.describe = A.describe; B.describe() // "姓名:李四"

上面程式碼中,A.describe屬性被賦給B,於是B.describe就表示describe方法所在的當前物件是B,所以this.name就指向B.name

稍稍重構這個例子,this的動態指向就能看得更清楚。

function f() {
  return '姓名:'+ this.name;
}

var A = {
  name: '張三',
  describe: f
};

var B = {
  name: '李四',
  describe: f
}; A.describe() // "姓名:張三" B.describe() // "姓名:李四"

上面程式碼中,函式f內部使用了this關鍵字,隨著f所在的物件不同,this的指向也不同。

只要函式被賦給另一個變數,this的指向就會變。

var A = {
  name: '張三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

var name = '李四';
var f = A.describe;
f() // "姓名:李四"

上面程式碼中,A.describe被賦值給變數f,內部的this就會指向f執行時所在的物件(本例是頂層物件)。

再看一個網頁程式設計的例子。

<input type="text" name="age" size=3 onChange="validate(this, 18, 99);">

<script>
function validate(obj, lowval, hival){
  if ((obj.value < lowval) || (obj.value > hival))
    console.log('Invalid Value!');
}
</script>

上面程式碼是一個文字輸入框,每當使用者輸入一個值,就會呼叫onChange回撥函式,驗證這個值是否在指定範圍。回撥函式傳入this,就代表傳入當前物件(即文字框),然後就可以從this.value上面讀到使用者的輸入值。

總結一下,JavaScript 語言之中,一切皆物件,執行環境也是物件,所以函式都是在某個物件之中執行,this就是這個物件(環境)。這本來並不會讓使用者糊塗,但是 JavaScript 支援執行環境動態切換,也就是說,this的指向是動態的,沒有辦法事先確定到底指向哪個物件,這才是最讓初學者感到困惑的地方。

如果一個函式在全域性環境中執行,那麼this就是指頂層物件(瀏覽器中為window物件)。

function f() {
  return this;
}

f() === window // true

上面程式碼中,函式f在全域性環境執行,它內部的this就指向頂層物件window

可以近似地認為,this是所有函式執行時的一個隱藏引數,指向函式的執行環境。

使用場合

this的使用可以分成以下幾個場合。

(1)全域性環境

在全域性環境使用this,它指的就是頂層物件window

this === window // true

function f() {
  console.log(this === window); // true
}

上面程式碼說明,不管是不是在函式內部,只要是在全域性環境下執行,this就是指頂層物件window

(2)建構函式

建構函式中的this,指的是例項物件。

var Obj = function (p) {
  this.p = p;
};

Obj.prototype.m = function() {
  return this.p;
};

上面程式碼定義了一個建構函式Obj。由於this指向例項物件,所以在建構函式內部定義this.p,就相當於定義例項物件有一個p屬性;然後m方法可以返回這個p屬性。

var o = new Obj('Hello World!');

o.p // "Hello World!"
o.m() // "Hello World!"

(3)物件的方法

當 A 物件的方法被賦予 B 物件,該方法中的this就從指向 A 物件變成了指向 B 物件。所以要特別小心,將某個物件的方法賦值給另一個物件,會改變this的指向。

請看下面的程式碼。

var obj ={
  foo: function () {
    console.log(this);
  }
};

obj.foo() // obj

上面程式碼中,obj.foo方法執行時,它內部的this指向obj

但是,只有這一種用法(直接在obj物件上呼叫foo方法),this指向obj;其他用法時,this都指向程式碼塊當前所在物件(瀏覽器為window物件)。

// 情況一
(obj.foo = obj.foo)() // window

// 情況二
(false || obj.foo)() // window

// 情況三
(1, obj.foo)() // window

上面程式碼中,obj.foo先運算再執行,即使值根本沒有變化,this也不再指向obj了。這是因為這時它就脫離了執行環境obj,而是在全域性環境執行。

可以這樣理解,在 JavaScript 引擎內部,objobj.foo儲存在兩個記憶體地址,簡稱為M1M2。只有obj.foo()這樣呼叫時,是從M1呼叫M2,因此this指向obj。但是,上面三種情況,都是直接取出M2進行運算,然後就在全域性環境執行運算結果(還是M2),因此this指向全域性環境。

上面三種情況等同於下面的程式碼。

// 情況一
(obj.foo = function () {
  console.log(this);
})()
// 等同於
(function () {
  console.log(this);
})()

// 情況二
(false || function () {
  console.log(this);
})()

// 情況三
(1, function