面向對象語言中 this 表示當前對象的一個引用。但在 JavaScript 中 this 不是固定不變的,它會隨著執行環境的改變而改變。 單獨使用(包括嚴格模式下),this 表示全局對象 在函數中,this 表示全局對象 在函數中,在嚴格模式下,this 是未定義的(undefined) 在對象 ...
面向對象語言中 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