本文共 1065 字,讀完只需 4 分鐘javascript
在 JAVA 中,this 的概念很透徹,就是指向當前對象(方法和屬性的持有者),在編譯的時候就能肯定 this 指代,而因爲 JavaScript 中 this 是動態綁定,或稱爲運行期綁定的,在絕大多數狀況下,函數的調用方式決定了 this 的值,因此在 JS 中不能在定義時決定地定義 this 是哪一個上下文對象。java
this 的指向只和函數的調用位置(方式)有關,和函數聲明的位置無關。node
本文就從 this 應用場景調用方式的角度,解析 this 的用法。瀏覽器
首先,要知道,this 的做用是什麼?閉包
函數體內部,指代函數當前的運行上下文。app
在全局上下文中,this 指向全局對象,在瀏覽器中指向 window,在 NodeJs 中指向 global。函數
var a = "全局";
console.log(this) // 瀏覽器:window
console.log(this) // nodejs:global
console.log(this.a) // "全局"
複製代碼
這是 JS 中的默認綁定,在全局上下文中,this 會默認綁定到 全局對象。post
在非嚴格模式下,未加關鍵字 var 聲明的變量,會成爲全局對象下的屬性,因此,此時 在嚴格模式下,this 將保持他進入執行上下文時的值,因此下面的 this 將會默認爲 undefined。ui
function foo() {
"use strict";
console.log(this);
}
foo(); // undefined 嚴格模式
複製代碼
上述也是 JS 中 this 的默認綁定,在函數定義中,函數中的 this 會默認綁定到全局對象或者 undefined。this
當函數做爲對象裏的方法被調用時,函數中 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 函數的形式。
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 的值,但最終都指向了調用了它的那個上下文對象。
歡迎關注個人我的公衆號「謝南波」,專一分享原創文章。