this in JavaScript in detail

English 简体中文 繁体中文 ภาษาไทย Tiếng Việt
Summary

The this keyword in JavaScript is dynamically bound, with its value determined by the function's execution context rather than its definition. In global scope or pure function calls, this typically refers to the global object, becoming undefined in strict mode, whereas a method call sets this to the invoking object. When used in a constructor, this points to the newly created instance, but within nested functions, it often defaults back to the global object, requiring workarounds. To explicitly control this in such scenarios, or within callbacks and event handlers, developers can leverage call(), apply(), or bind(). Ultimately, this consistently references the object responsible for calling the function.

在 JavaScript 中,this 總是令人困惑,它是 JavaScript 中最常見的陷阱之一。在 JavaScript 中,這不是一個好的設計(您可以參考 JavaScript 的其他一些設計缺陷這裡),由於它的惰性綁定特性,它可以是一個全域物件、當前物件,或是...。有些人甚至避免在 JavaScript 中使用 this

實際上,如果您掌握了 this 的工作原理,那麼您就會知道如何避開這些陷阱。讓我們看看在以下情況下 this 指向什麼。

1. 在全域範圍程式碼中

alert(this)//window

在全域範圍程式碼中,this 將指向全域物件(通常在 Web 瀏覽器中是 window)。

2. 在純函數呼叫中

function fooCoder(x) {
	this.x = x;
}
fooCoder(2);
alert(x);// Global variable x's value is 2

這裡 this 也指向全域物件,因為在全域範圍中定義的函數實際上是全域物件的一個方法。所以 this 將是全域物件。在嚴格模式下,this 將是 undefined

3. 在物件的方法呼叫中

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		console.log(this.name + " says " + sth);
	}
}
person.hello("hello world");

輸出將是 "foocoder says hello world"。this 將指向 person 物件,也就是呼叫該方法的當前物件。

4. 在建構子中

new FooCoder();

在建構子中,this 將指向使用 new 新建立的物件。

5. 在私有函數呼叫中

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		var sayhello = function(sth) {
			console.log(this.name + " says " + sth);
		};
		sayhello(sth);
	}
}
person.hello("hello world");//clever coder says hello world

在私有函數中,this 不會綁定到外部方法的物件,而是綁定到全域物件。這被認為是 JavaScript 的設計缺陷,因為沒有人希望私有函數中的 this 在這裡指向全域物件。一般的解決方案是將 this 賦值給另一個變數,並在私有函數中引用該變數。

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		var that = this;
		var sayhello = function(sth) {
			console.log(that.name + " says " + sth);
		};
		sayhello(sth);
	}
}
person.hello("hello world");//foocoder says hello world

6. 在 call() 或 apply() 中

person.hello.call(person, "world");

apply()call() 類似,唯一的區別是第一個參數之後傳入的參數。在 apply() 中,其他參數將以陣列形式傳入,而在 call() 中,其他參數將分別傳入。

call( thisArg [,arg1,arg2,… ] );  // Parameter list,arg1,arg2,...
apply(thisArg [,argArray] );     // Parameter list,argArray

傳入的第一個參數是 this 將指向的物件。我們可以指定任何要讓 this 指向的物件。

7. 其他

我們可能會經常看到以下程式碼:

$("#some-ele").click = obj.handler;

如果我們在 handler 中使用 thisthis 會綁定到 obj 嗎?顯然不會,在賦值之後,函數是在回呼函數中呼叫的,this 將綁定到 $("#some-div") 元素。這是我們需要理解的——執行上下文。

那麼我們如何在回呼函數中指定 this 物件為我們想要的物件呢?在 ECMAScript 5 中,有一個 bind() 方法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg 將是我們想要成為的 this 物件。

$("#some-ele").click(person.hello.bind(person));

現在 this 將是 person 物件

在 Prototype.js 中,我們可以找到 bind() 的實現:

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

結論

1. 當函數作為物件的方法呼叫時,this 將指向該物件

2. 當在純函數呼叫中時,this 將是全域物件(在嚴格模式下,this 將是 undefined

3. 在建構子中,this 將是新建立的物件

一句話概括,this 總是會指向呼叫該函數的物件。

JAVASCRIPT THIS BIND GUIDE

  RELATED

  COMMENTS

0

No comment for this article.