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 引擎內部,obj
和obj.foo
儲存在兩個記憶體地址,簡稱為M1
和M2
。只有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