面向物件語言中 this 表示當前物件的一個參考,但在 JavaScript 中 this 不是固定不變的,它會隨著執行環境的改變而改變,
- 單獨使用(包括嚴格模式下),this 表示全域物件
- 在函式中,this 表示全域物件
- 在函式中,在嚴格模式下,this 是未定義的(undefined)
- 在物件方法中,this 表示該方法所屬的直接物件
- 在事件中,this 表示接收事件的元素
- 類似 call()、apply()、bind() 方法可以將 this 參考到任何物件
this 的指向在函式定義的時候是確定不了的,只有函式執行的時候才能確定 this 到底指向誰,實際上 this 最終指向的是那個呼叫它的物件,
單獨使用 this
單獨使用 this,則它指向全域(Global)物件,在瀏覽器中,Window 就是該全域物件,
var x = this;
x // [object Window]
嚴格模式下,如果單獨使用,this 也是指向全域(Global)物件,
"use strict";
var x = this;
x // [object Window]
函式中使用 this
在函式中,this 指向呼叫函式的物件
var color = 'Global color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // [Object Windwo]
console.log(this.color); // 'Global color'
}
myFunction(); // 實質是全域物件window在呼叫函式 ==> window.myFunction();
在嚴格模式下,this 是 undefined
"use strict"
var color = 'Global color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // undefined
console.log(this.color); // TypeError: Cannot read property 'color' of undefined
}
myFunction();
物件方法中使用 this
在物件方法中,this 表示該方法所屬的直接物件
var color = 'Global color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // [Object myObj]
console.log(this.color); // 'Object color'
}
var myObj = {
color: 'Object color',
foo: myFunction
};
myObj.foo();
有嵌套物件的場景(下列代碼中 myFunction 方法所屬的直接物件為 subObj ):
var color = 'Global color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // [Object subObj]
console.log(this.color); // 'SubObject color'
}
var subObj = {
color: 'SubObject color',
foo: myFunction
};
var myObj = {
color: 'Object color',
subObj: subObj
};
myObj.subObj.foo();
物件普通屬性中使用 this
物件屬性由 普通屬性 + 方法 構成,當對普通屬性使用 this. 賦值時,this 始終指向全域物件(?? 沒有完全理解)
// 示例一(觀察 myFunction 中 this.dangerColor 的輸出)
var color = 'Global color';
var dangerColor = 'Global Danger color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // [Object myObj]
console.log(this.color); // 'Object color'
console.log(this.dangerColor); // 'Global Danger color'
}
var myObj = {
color: 'Object color',
dangerColor: this.dangerColor, // 此處 this 指向全域物件 Window
foo: myFunction
};
myObj.foo();
// 示例二,有嵌套物件的場景,父物件、子物件單獨定義(觀察 myFunction 中 this.dangerColor 的輸出)
var color = 'Global color';
var dangerColor = 'Global Danger color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // [SubObject myObj]
console.log(this.color); // 'SubObject color'
console.log(this.dangerColor); // 'Global Danger color' (?? 這個輸出有點不太理解)
}
var subObj = {
color: 'SubObject color',
dangerColor: this.dangerColor, // 此處 this 就確定了? 指向全域物件 Window? (?? 不太理解)
foo: myFunction
};
var myObj = {
color: 'Object color',
dangerColor: 'Object Danger color',
subObj: subObj
};
myObj.subObj.foo();
// 示例三,有嵌套物件的場景,子物件直接在父物件中定義(觀察 myFunction 中 this.dangerColor 的輸出)
var color = 'Global color';
var dangerColor = 'Global Danger color';
function myFunction() {
var color = 'Function color';
console.log(color); // 'Function color'
console.log(this); // [SubObject myObj]
console.log(this.color); // 'SubObject color'
console.log(this.dangerColor); // 'Global Danger color' (?? 這個輸出有點不太理解)
}
var myObj = {
color: 'Object color',
dangerColor: 'Object Danger color',
// 子物件直接在父物件中定義
subObj: {
color: 'SubObject color',
dangerColor: this.dangerColor, // 此處 this 就確定了? 指向全域物件 Window? (?? 不太理解)
foo: myFunction
}
};
myObj.subObj.foo();
說明:當對 物件普通屬性使用 this. 賦值時,感覺 this 始終指向全域物件,目前還不太理解??
事件中的 this
在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素
<button onclick="this.style.display='none'">點我后我就消失了</button>
this 的四種系結規則
this 的四種系結規則分別是:默認系結、隱式系結、顯示系結、new 系結
默認系結
獨立函式呼叫
var color = 'Global color';
function myFunction() {
console.log(this.color); // 'Global color' (嚴格模式下有 undefined 的問題)
}
myFunction();
隱式系結
函式的呼叫是在某個物件上觸發的,呼叫位置上存在背景關系物件(上文中的“物件方法中使用 this ”)
var color = 'Global color';
function myFunction() {
console.log(this.color); // 'Object color'
}
var myObj = {
color: 'Object color',
foo: myFunction
};
myObj.foo();
隱式丟失(函式別名)
var color = 'Global color';
function myFunction() {
console.log(this.color); // 'Global color'
}
var myObj = {
color: 'Object color',
foo: myFunction
};
var bar = myObj.foo; // 不直接執行
bar();
說明:myObj.foo 是參考屬性,賦值給 bar 的實際上就是foo函式(即:bar 指向 foo 本身),那么,實際的呼叫關系是:通過 bar 找到 foo 函式,進行呼叫,整個呼叫程序并沒有myObj 的參與,所以是默認系結,輸出結果為全域變數 color 的值 'Global color',
隱式丟失(回呼函式)
var color = 'Global color';
function myFunction() {
console.log(this.color); // 'Global color'
}
var myObj = {
color: 'Object color',
foo: myFunction
};
setTimeout(myObj.foo, 1000);
說明:同樣的道理,雖然參傳是 myObj.foo,因為是參考型別,所以傳參實際上傳的就是 foo 物件(函式)本身的參考,對于 setTimeout 的呼叫,還是 setTimeout -> 獲取引數中 foo的參考引數 -> 執行 foo 函式,中間沒有 myObj 的參與,這里依舊進行的是默認系結,
顯示系結
相對隱式系結,this 值在呼叫程序中會動態變化,如果我們就想系結指定的物件,這時就用到了顯示系結,
具體使用上,可以通過call(…)、apply(…) 或 bind(…)來實作,(三個方法的區別)
var person = {
name: 'xx',
age: 'xx',
foo: function() {
console.log(this.name + ', ' + this.age);
}
}
var xiaoming = {
name: '小明',
age: 21
}
var zhangsan = {
name: '張三',
age: 31
}
var lisi = {
name: '李四',
age: 27
}
var bar = person.foo;
bar.call(xiaoming); // 小明, 21
bar.apply(zhangsan); // 張三, 31
bar.bind(lisi)(); // 李四, 27
硬系結
var person = {
name: 'xx',
age: 'xx',
foo: function() {
console.log(this.name + ', ' + this.age);
}
}
var xiaoming = {
name: '小明',
age: 21
}
var zhangsan = {
name: '張三',
age: 31
}
var bar = function() {
person.foo.call(xiaoming);
};
setTimeout(bar, 1000); // 小明, 21
bar.call(zhangsan); // 小明, 21 (!!!,這里需要注意)
說明:雖然最后一行代碼, bar 被顯示系結到 zhangsan 上,對于 bar,function(){…} 中的 this 確實被系結到了 zhangsan 上,但 person.foo 因為通過 person.foo.call( xiaoming) 已經顯示系結了 xiaoming,所以在 foo 函式內,this 指向的是 xiaoming,不會因為 bar 函式內指向 zhangsan 而改變自身,所以列印的是 "小明, 21",
在顯示系結中,系結 null 或 undefined,實際上會進行默認系結,導致函式中可能會使用到全域變數,與預期不符,對于要忽略 this 的情況,可以傳入一個空物件,該物件通過Object.create(null) 創建,
var name = 'Window';
var age = '100';
var person = {
name: 'xx',
age: 'xx',
foo: function() {
console.log(this.name + ', ' + this.age);
}
}
var xiaoming = {
name: '小明',
age: 21
}
var emptyObj = Object.create(null);
var emptyObj2 = Object.create({});
person.foo.call(null); // Window, 100
person.foo.call(undefined); // Window, 100
person.foo.call(xiaoming); // 小明, 21
person.foo.call(emptyObj); // undefined, undefined
person.foo.call(emptyObj2); // undefined, undefined
new 系結
作為建構式呼叫,this 指代 new 實體化的物件
function Person(name) {
this.name = name;
}
var xiaoming = new Person('小明');
console.log(xiaoming.name); // 小明
var zhangsan = new Person('張三');
console.log(zhangsan.name); // 張三
當 this 碰到 return 時,如果回傳值是一個物件,那么 this 指向的就是那個回傳的物件,如果回傳值不是一個物件那么 this 還是指向函式的實體
function Person(name) {
this.name = name;
return {}; // 回傳 Object (函式除外)
}
var xiaoming = new Person('小明');
console.log('name: ', xiaoming.name); // name: undefined
function Person(name) {
this.name = name;
return function() {};
}
var xiaoming = new Person('小明');
console.log('name: ', xiaoming.name); // name: (空值)
function Person(name) {
this.name = name;
return null; // 回傳基本資料型別 Number, String, Boolean, Null, Undefined
}
var xiaoming = new Person('小明');
console.log('name: ', xiaoming.name); // name: 小明
擴展:箭頭函式
(待續...)
參考檔案:
https://www.cnblogs.com/pssp/p/5216085.html
https://blog.csdn.net/cjgeng88/article/details/79846670
https://segmentfault.com/a/1190000019937964?utm_source=tag-newest
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/126438.html
標籤:JavaScript
