本文共 1065 字,讀完只需 4 分鐘
概述
在 JAVA 中,this 的概念很透徹,就是指向當前物件(方法和屬性的持有者),在編譯的時候就能確定 this 指代,而由於 JavaScript 中 this 是動態繫結,或稱為執行期繫結的,在絕大多數情況下,函式的呼叫方式決定了 this 的值,所以在 JS 中不能在定義時決定地定義 this 是哪個上下文物件。
this 的指向只和函式的呼叫位置(方式)有關,和函式宣告的位置無關。
本文就從 this 應用場景呼叫方式的角度,解析 this 的用法。
首先,要知道,this 的作用是什麼?
函式體內部,指代函式當前的執行上下文。
一、全域性上下文
在全域性上下文中,this 指向全域性物件,在瀏覽器中指向 window,在 NodeJs 中指向 global。
var a = "全域性";
console.log(this) // 瀏覽器:windowconsole.log(this) // nodejs:globalconsole.log(this.a) // "全域性"複製程式碼
這是 JS 中的預設繫結,在全域性上下文中,this 會預設繫結到 全域性物件。
二、函式宣告
在非嚴格模式下,未加關鍵字 var 宣告的變數,會成為全域性物件下的屬性,所以,此時在嚴格模式下,this 將保持他進入執行上下文時的值,所以下面的 this 將會預設為 undefined。
function foo() { "use strict";
console.log(this);
}foo();
// undefined 嚴格模式複製程式碼
上述也是 JS 中 this 的預設繫結,在函式定義中,函式中的 this 會預設繫結到全域性物件或者 undefined。
當函式作為物件裡的方法被呼叫時,函式中 this 是呼叫該函式的物件。
function foo() {
console.log("foo");
}var obj = {
this.bar = "bar";
this.foo = foo;
}obj.foo();
// "foo"複製程式碼
在呼叫位置,是 obj 物件呼叫了 foo 函式,此時 this 就指向了 obj 物件。
function foo() {
console.log(this.bar);
}var obj2 = {
bar: "2", foo: foo
}var obj1 = {
bar: "1", obj2: obj2
}obj1.obj2.foo() // "2";
複製程式碼
這是 JS 中 this 的隱式繫結,this 會隱式繫結到呼叫的最近一層上下文物件。
三、call &
apply
其實在函式中,函式正確的呼叫應該是用 call, apply 函式的形式。
function foo() {
console.log(this.bar);
}let obj = {
bar: "1", foo: foo
}obj.foo();
// `.` 點呼叫其實是語法糖foo.call(obj) // 1 正確的姿勢foo.apply(obj) // 1複製程式碼
這是 JS 中 this 的顯式繫結,函式通過從 call 和 apply 函式可以顯式指定函式的呼叫物件。
ES5 提供了一個 bind()方法:
let obj2 = {
a: 2
}let foo = function () {
console.log(this.a);
}let bar = foo.bind(obj2);
bar() // 2;
複製程式碼
就是 JS 中 this 的硬繫結,bind() 函式會返回一個指定了呼叫物件的函式,返回的函式的被指定了 this 且 this 無法改變。
四、建構函式
當函式加上關鍵字 new 後,函式會變成一個建構函式,此時建構函式中的 this 指向即將建立的物件例項,同時物件例項會關聯到建構函式的原型物件 prototype 上。
function Foo() {
this.a = 3;
}var obj = new Foo();
obj.a // 3複製程式碼
五、箭頭函式
ES6 中,提供了函式定義的語法糖,讓定義函式變得更簡潔(沒有 arguments, 沒有原型)。同時上面四條繫結規則在箭頭函式中不適用,使得 this 的查詢更可控。
// 一般函式:var a = 1;
var obj = {
a: 2, say: function() {
console.log(this.a)
}
}obj.say();
// console.log 列印值為 2// 箭頭函式var a = 1;
var obj = {
a: 2, say: () =>
{
console.log(this.a)
}
}obj.say();
// 1 !!!複製程式碼
由於箭頭函式定義時, obj {
} 不是執行上下文,say 變數引用的箭頭函式,其 this 是父級執行上下文,也就是全域性上下文,所以 this.a 就是 全域性變數 a: 1;
在箭頭函式中,this 與封閉詞法上下文的 this 保持一致,this 被永久繫結到了它最近一層非箭頭函式的 this,而與函式的呼叫位置無關。
總結
在絕大多數情況下,函式的呼叫方式決定了 this 的值,但最終都指向了呼叫了它的那個上下文物件。
歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。