Master "this" trong JavaScript

I.Mở bài

Ở bài viết này, mình sẽ giải thích về this con trỏ trong javascript

Khi mới học, ta thấy this cũng khá đơn giản và vô hại
Ban đầu khi mới học javscript bạn sẽ thấy sử dụng con trỏ this rất đơn giản
. Nếu bạn đã từng làm qua Java hoặc C#, chắc bạn cũng nhớ từ khóa this dùng để trỏ tới object gọi hàm đó. Trong javascript, từ khóa this cũng đóng vai trò tương tự. Chúng ta hãy xem ví dụ bên dưới về việc con trỏ this trở tới person

    var person = {
    firstName   :"Penelope",
    lastName    :"Barrymore",
    showFullName:function () {
    console.log (this.firstName + " " + this.lastName);
    }

    person.showFullName (); // Penelope Barrymore

Nếu sử dụng person.firstName và person.lastName thì code sẽ trở nên mơ hồ. Liệu rằng có thể có một biến global mang tên person. Trong một vài trường hợp còn có thể gây ra lỗi. Vì vậy nên sử dung "this" giúp code trở nên rõ ràng dễ hiểu hơn.

Một ví dụ khác , khi ta khai báo biến global hoặc hàm global, toàn bộ các biến và hàm đó sẽ nằm trong một object có tên là window. Lúc này, khi ta gọi hàm showName, object window chính là đối tượng gọi hàm đó, con trỏ this sẽ trỏ tới object window.

var firstName = 'Penelope', lastName = 'Barrymore';
// 2 biến này nằm trong object window

function showName()
{
  console.log(this.firstName + ' '+ this.lastName);
}

window.showName(); // Penelope Barrymore. this trỏ tới object window
showName(); //Penelope Barrymore. Object gọi hàm showName vẫn là object window

II.Những trường hợp khó khăn khi sử dụng this

Nếu chỉ sử dụng theo 2 cách nêu trên, this sẽ khá dễ hiểu vào không gây ra mấy khó khăn khi sử dụng. Chúng ta hãy xem xét thêm các trường hợp mà this gây ra nhầm lẫn

1. Hàm được truyền vào như một callback

Giả sử, ta muốn khi người dùng click vào một button, ta sẽ gọi hàm clickHandler của user.Lúc đó ta chỉ cần truyền hàm clickHandler vào như một callback cho hàm click là xong.

    var user = {
    data:[
    {name:"T. Woods", age:37},
    {name:"P. Mickelson", age:43}
    ],
    clickHandler:function (event) {
    var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1

    // Xuất ra ngẫu nhiên tên và tuổi
    console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
    }

    // button được bao trongjQuery $ , vậy nó là 1 jQuery object
    $ ("button").click (user.clickHandler); // lỗi undefined

vì con trỏ this ở đây là chính button ta đã click vào, chứ không phải là object user nên sẽ gặp lỗi .

Trong trường hợp này, ta có thể sử dụng anonymous function, hoặc dùng hàm bind để xác định tham số this cho hàm truyền vào là được.

$("button").click (user.clickHandler.bind (user)); // P. Mickelson 43

2. Sử dụng this trong anonymous function

Giả sử, object person có một danh sách bạn bè, bạn muốn viết một function show toàn bộ bạn bè của person đó.

var user = {
tournament:"The Masters",
data      :[
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],

clickHandler:function () {

this.data.forEach (function (person) {

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]

khi ta dùng hàm forEach, truyền vào một anonymous function, this ở đây lại thành object window, do đó trường tournament bị underfined.

Trong trường hợp này, cách giải quyết ta thường dùng là tạo một biến để gán giá trị this vào, và truy xuất tới giá trị đó trong anonymous function.

    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

3.Khi hàm được gán vào một biến

Trường hợp này ít khi xảy ra. Đó là trường hợp khi ta gán một hàm vào một biến, sau đó gọi hàm đó. Hàm sẽ không chạy như ta mong muốn, vì object gọi hàm lúc này chính là object window.

  // This data variable is a global variable
    var data = [
    {name:"Samantha", age:12},
    {name:"Alexis", age:14}
    ];

    var user = {
    // ở đây các giá trị vẫn thuộc object user
    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 user.showData
    var showUserData = user.showData;

    // Khi chúng ta thực thi hàm showUserData, các giá trị được in ra console là từ global data array, không phải array từ user object
    //
    showUserData (); // Samantha 12 (from the global data array)

Để giải quyết, ta cũng sử dụng hàm bind như trường hợp trên

    // Bind showData vào object user
    var showUserData = user.showData.bind (user);

    // lấy dữ liệu từ user object
    showUserData (); // P. Mickelson 43

III.Kết

Qua bài viết này hy vọng các bạn có thể hiểu thêm về con trỏ this trong javascript.
Hãy cẩn thận khi sử dụng this với callback functions, khi được gọi bằng một object khác .

III.Tham Khảo

http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/#