This trong JS
Bài đăng này đã không được cập nhật trong 7 năm
Ta có thể hiểu this
trong JS cũng giống như trong ngôn ngữ tự nhiên của tiếng Anh. Nó giống như một danh từ để thay thế cho danh từ khác tránh việc lặp đi lặp lại.
Ví dụ
Michael is handsome because he is rich
danh từ he ở trên là để tránh việc lặp lại Michael
Xét tiếp ví dụ tiếp về sử dụng this trong JS
var person = {
firstName: "Michael",
lastName: "Scofield",
fullName: function () {
console.log(this.firstName + " " + this.lastName);
// ta cũng có thể viết theo cách này
console.log(person.firstName + " " + person.lastName);
}
}
person.fullName()
Michael Scofield
Michael Scofield
- Như ví dụ trên có thể thấy việc dùng this hay chính object đó để gọi là tương đương đều in ra 2 dòng fullName như nhau
Nhưng khi dùng object
person
để gọi thì có vấn đề khác đó là có thể có một global variable nào đó bên ngoài cũng có tênperson
và khi gọiperson
có thể nó sẽ không lấy giá trị từ bên trong object mà bạn muốn. - Điều đó dễ gây ra bug cũng như Việc debug sẽ trở nên khó khăn hơn.
Javascipt this
Tất cả các function trong JS đều có các properties, nó cũng giống như các object. Khi thực thi function nó sẽ lấy this
property của object
this
luôn luôn refer và giữ giá trị của object. Nó thường được sử dụng trong function hoặc method.
this
được sử dụng bên trong function (giả sử là function A), nó chứa giá trị của object mà gọi đến function A
Chúng ta cần this
để accesss vào các method và thuộc tính của object mà nó gọi đến function A, đặc biệt alf khi chúng ta không biết tên của object được gọi và đôi khi là một một object không có tên.
this
là shortcut để refer tới invoking object.
$ (".button").click (function (event) {
console.log ($ (this).prop ("name"));
});
$(this)
Là jQuery syntax nó tương tự như this
trong JavaScript, được sử dụng trong anonymous function. Anonymous function này sẽ thực thi phương thức click và lý do mà $this
được bind tới button object là vì jQuery library bind $(this)
tới object mà nó gọi phương thức click do đó $(this)
sẽ có giá trị của $(".button")
object.
this
không được gán giá trị cho tới khi một object gọi function mà this
được định nghĩa trong function này
Sử dụng this ở global scope
- Ở global scope khi code được thực thi ở browser, tất cả các global variable và các function được định nghĩa bên trong window object. Do đó, khi chúng
ta sử
this
ở global function nó sẽ refer, và lấy giá trị của global window object.
var firstName = "Peter",
lastName = "Ally";
function showFullName () {
// "this" sẽ chứa giá trị của window object bởi vì fullName được định nghĩa ở global scope, giống như firstName, lastName
console.log (this.firstName + " " + this.lastName);
}
var person = {
firstName :"Penelope",
lastName :"Barrymore",
showFullName:function () {
// `this` trong trường hợp này tham chiếu tới person object, bởi vì hàm showFullName này sẽ được gọi bởi person object
console.log (this.firstName + " " + this.lastName);
}
}
showFullName (); // Peter Ally
// window là một object mà nó có thể gọi được tất cả các biến hay các function được định nghĩa ở global
window.showFullName (); // Peter Ally
// this ở bên trong showFullName method được định nghĩa bên trong person object do đó khi gọi nói sẽ lấy object là person
person.showFullName (); // Penelope Barrymore
Khi this được sử dụng bên trong method, được truyền qua callback function
var user = {
data:[
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],
clickHandler:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // lấy random 0 hoặc 1
console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
}
}
// Outut là undefined bởi vì không button jQuery không có data property nào cả
$ ("button").click (user.clickHandler); // Cannot read property '0' of undefined
Đoạn code ở trên chúng ta đang truyền user.clickHandler
tới click function của jQuery object như một callback
Và khi đó this
bên trong user.clickHandler
sẽ không còn tham chiếu tới user object nữa, lúc này nó sẽ tham chiếu tới object,
object mà đang gọi user.clickHandler
method, Mà object mà ta gọi user.clickHandler
chính là jQuery object $("button")
thực thi click function
Để tránh bị như vậy nó cần được làm rõ khi mà context thay đổi, khi chúng ta thực thi một phương thức ở một phức thức khác, this keyword sẽ không còn được tham chiếu tới object định nghĩa ra nó nữa, nó sẽ tham chiếu tới object gọi method có định nghĩa this bên trong
Solution để fix:
Như ở ví dụ trên chúng ta cần this
tham chiếu tới user object thay vì jQuery object $("button")
, chúng ta có thể sử dụng bind()
, apply()
, call()
method
để set giá trị cho this
thay vì gọi như cách cũ
$ ("button").click (user.clickHandler);
ta sẽ sử dụng bind()
method để gán lại giá trị cho this
$("button").click (user.clickHandler.bind (user)); // P. Mickelson 43
this
trong closure
Một ví dụ khác về việc dùng this ở trong một inner method
(hay còn gọi là closure). Một chú ý quan trọng đó là closure không thể access
this của outer function bằng cách dùng keyword this
bởi vì this
chỉ có thể access bên trong function của chính nó không phải một inner function
var user = {
tournament: "The Masters",
data: [
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],
clickHandler:function () {
// khi gọi `this.data` ở đây vẫn được bởi vì ở dưới ta gọi `user.clickHandler` nên this ở đây refer tới object gọi phương thức định nghĩa nó (chính là user)
this.data.forEach (function (person) {
// Nhưng ở đây thì không đây là một `anonymous function` và this bên trong function này không còn tham chiếu tới user object nữa
console.log ("What is This referring to? " + this); //[object Window]
console.log (person.name + " is playing at " + this.tournament);
// T. Woods is playing at undefined
// P. Mickelson is playing at undefined
})
}
}
user.clickHandler(); // What is "this" referring to? [object Window]
this
bên trong anonymous function không thể access this ở outer function, và nó thuộc về global window object
Solution để fix:
Để giải quyết vấn đề khi gọi this bên trong anonymous function truyền qua forEach
method, đó là gán this object cho một biến trước khi
chúng ta gọi forEach
var user = {
tournament: "The Masters",
data:[
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],
clickHandler:function (event) {
var theUserObj = this;
this.data.forEach (function (person) {
console.log (person.name + " is playing at " + theUserObj.tournament);
})
}
}
user.clickHandler();
// T. Woods is playing at The Masters
// P. Mickelson is playing at The Masters
Khi this
được sử dụng trong method mà method này được gán bởi một biến khác
//data này ở global scope
var data = [
{name:"Samantha", age:12},
{name:"Alexis", age:14}
];
var user = {
// biến data này thuộc về user object
data :[
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],
showData:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1
console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
}
}
// gán method user.showData cho một biến
var showUserData = user.showData;
//khi gọi showUserData function ở global scope, giá trị in ra sẽ là dữ liệu biến data của global scope chứ không phải `data` của user object
showUserData (); // Samantha 12 (from the global data array)
Solution để fix:
sử dụng bind
method để set value cho this
var showUserData = user.showData.bind(user);
showUserData ();
Khi this
được định nghĩa ở một biến nhưng lại được sử dụng bởi một biến khác
// Chúng ta có 2 object một có method `avg()` và object còn lại thì không
// Ta sẽ mượn `avg()` method
var gameController = {
scores:[20, 34, 55, 46, 77],
avgScore:null,
players :[
{name: "Tommy", playerID: 987, age: 23},
{name: "Pau", playerID: 87, age: 33}
]
}
var appController = {
scores:[900, 845, 809, 950],
avgScore: null,
avg: function () {
var sumOfScores = this.scores.reduce (function (prev, cur, index, array) {
return prev + cur;
});
this.avgScore = sumOfScores / this.scores.length;
}
}
//avgScore của gameController object sẽ lấy giá trị avg của appController từ score của appController chứ không phải từ score của gameController object
gameController.avgScore = appController.avg();
this
vẫn này không tham chiếu tới gameController object nó vẫn thuộc về appController bởi vì nó được gọi ở appController vậy để làm sao this có thể tham chiếu tới gamController object
*Solution để fix: *
sử dụng method apply()
appController.avg.apply (gameController, gameController.scores);
console.log (gameController.avgScore); // 46.4
console.log (appController.avgScore); // null
gameController
mượn avg method của appController
để gán giá trị cho avgScore của gameController
object
this
bên trong appController.avg() sẽ được gán cho gameController object bởi vì chúng ta đã truyền gameController vào apply method ở tham số đầu tiên
Nguồn tham khảo
http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ You dont know JS
All rights reserved