Trong JavaScript, this
luôn gây nhầm lẫn, nó là một trong những cạm bẫy thường thấy nhất. this
không phải là một thiết kế tốt trong JavaScript (bạn có thể tham khảo một số sai sót thiết kế khác của JavaScript tại đây), vì tính năng liên kết trễ của nó, nó có thể là một đối tượng toàn cục, đối tượng hiện tại hoặc.... Một số người thậm chí tránh sử dụng this
trong JavaScript.
Thực tế, nếu bạn nắm vững cách this
hoạt động, bạn sẽ biết cách tránh xa những cạm bẫy này. Hãy xem this
trỏ đến đâu trong các tình huống dưới đây.
1. Trong mã phạm vi toàn cục
alert(this)//window
this
sẽ trỏ đến đối tượng toàn cục (thường là window
trong trình duyệt web) trong mã phạm vi toàn cục.
2. Trong một lệnh gọi hàm thuần túy
function fooCoder(x) { this.x = x; } fooCoder(2); alert(x);// Biến toàn cục x có giá trị là 2
Ở đây, this
cũng đang trỏ đến đối tượng toàn cục vì hàm được định nghĩa trong phạm vi toàn cục thực chất là một phương thức của đối tượng toàn cục. Vì vậy, this
sẽ là đối tượng toàn cục. Trong chế độ nghiêm ngặt, this
sẽ là undefined
.
3. Trong một lệnh gọi phương thức của một đối tượng
var name = "clever coder"; var person = { name : "foocoder", hello : function(sth){ console.log(this.name + " says " + sth); } } person.hello("hello world");
Kết quả sẽ là "foocoder says hello world". this
sẽ trỏ đến đối tượng person
, tức là đối tượng hiện tại gọi phương thức.
4. Trong một hàm tạo
new FooCoder();
Trong một hàm tạo, this
sẽ trỏ đến đối tượng mới được tạo bằng new
.
5. Trong một lệnh gọi hàm riêng tư
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
Trong một hàm riêng tư, this
không liên kết đối tượng của phương thức bên ngoài, thay vào đó nó liên kết với đối tượng toàn cục. Điều này được coi là một sai sót thiết kế của JavaScript vì không ai muốn this
trong hàm riêng tư trỏ đến đối tượng toàn cục ở đây. Giải pháp chung là gán this
cho một biến khác và tham chiếu biến đó trong hàm riêng tư.
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. Trong call()
hoặc apply()
person.hello.call(person, "world");
apply()
và call()
tương tự nhau, sự khác biệt duy nhất là các tham số được truyền vào sau tham số đầu tiên. Trong apply()
, các tham số khác sẽ được truyền bằng một mảng, trong khi trong call()
, các tham số khác được truyền riêng lẻ.
call( thisArg [,arg1,arg2,… ] ); // Danh sách tham số,arg1,arg2,... apply(thisArg [,argArray] ); // Danh sách tham số,argArray
Tham số đầu tiên được truyền vào là đối tượng mà this
sẽ trỏ đến. Chúng ta có thể chỉ định bất kỳ đối tượng nào để được trỏ đến bởi this
.
7. Khác
Chúng ta có thể thấy đoạn mã dưới đây thường xuyên:
$("#some-ele").click = obj.handler;
Nếu chúng ta sử dụng this
trong handler
, this
sẽ liên kết với obj
? Rõ ràng là không, sau khi gán, các hàm được gọi trong hàm gọi lại, this
sẽ liên kết với phần tử $("#some-div")
. Đây là điều chúng ta cần hiểu ở đây - ngữ cảnh thực thi.
Vậy làm cách nào để chúng ta chỉ định đối tượng this
là đối tượng chúng ta muốn trong hàm gọi lại? Trong ECMAScript 5, có một phương thức bind()
:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
sẽ là đối tượng this
mà chúng ta muốn.
$("#some-ele").click(person.hello.bind(person));
Bây giờ this
sẽ là đối tượng person
Trong Prototype.js, chúng ta có thể tìm thấy cách triển khai của 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))); }; };
Kết luận
1. Khi hàm được gọi là một phương thức của một đối tượng, this
sẽ trỏ đến đối tượng đó
2. Khi trong một lệnh gọi hàm thuần túy, this
sẽ là đối tượng toàn cục (trong chế độ nghiêm ngặt, this
sẽ là undefined
)
3. Trong một hàm tạo, this
sẽ là đối tượng mới được tạo
Trong một câu, this
sẽ luôn trỏ đến đối tượng mà hàm được gọi trên đó.