post-image

Từ khoá “this” trong JavaScript

Hướng đối tượng

Đây không phải một chủ đề xa lạ gì trong lập trình hướng đối tượng, tuy nhiên việc có thể sử dụng mượt mà this không phải là việc dễ dàng với những bạn bắt đầu làm việc với JavaScript. Vì vậy hôm nay mình quyết định chọn chủ đề này vừa để ôn lại kiến thức vừa giúp các bạn mới có thể hiểu kỹ hơn về Từ khoá “this” trong JavaScript.


Nhớ lại một chút nhé, dưới đây là đoạn code cơ bản trong lập trình hướng đối tượng Java:

class User {
    String username;
    
    public void setName(String name) {
        username = name;
    }

    public String getName(){
        return this.username;
    }
}

User user = new User();
String name = user.getName();

Khi code được biên dịch thì ở function getName() con trỏ this lúc này được đại diện cho đối tượng User và this.username chính là việc chỉ định thuộc tính username của class User.

Ở Java việc hoạt động của this khá tường minh như vậy, tuy nhiên trong JavaScript thì câu chuyện đã trở nên magic hơn rất nhiều.

Về cơ bản, cách gọi của this trong JavaScript không khác gì với Java, ví dụ:

var name = {
    firstName: 'Anh',
    lastName: 'Nguyen',
    fullName: function () {
        console.log(this.firstName + ' ' + this.lastName);
        ​// Hoặc có thể viết
        console.log(name.firstName + ' ' + name.lastName);
    }
}

name.fullName(); // Anh Nguyen

Tuy nhiên, điều mình cần chú ý ở bài viết này đó là CONTEXT hay ngữ cảnh, trong JavaScript mỗi đoạn code được thực hiện trong một ngữ cảnh nhất định và thực hiện một cách tuần tự, Và trong mỗi ngữ cảnh đó sẽ có một this đại diện. Vì vậy khi ngữ cảnh thay đổi thì this sẽ cần được đánh giá lại.

Có 3 loại ngữ cảnh chính:

Global

Đây là ngữ cảnh đầu tiên thực thi chương trình, ở đây mình nói riêng với trình duyệt đó sẽ là đối tượng window. Ví dụ:

var firstName = 'Anh', lastName = 'Nguyen';
// 2 biến này nằm trong đối tượng window

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

window.showFullName(); // Anh Nguyen this trỏ tới đối tượng window
showName(); // Anh Nguyen  Đối tượng gọi hàm showName vẫn là object window

Function

Ngữ cảnh toàn cục:

Ở ngữ cảnh này, this sẽ tham chiếu tới đối tượng toàn cục. Ví dụ:

function globalMethod() {
    console.log(this); // đối tượng toàn cục - global object
}

globalMethod();

var obj = {
    method: function() {
        return (function() {
            console.log(this); // đối tượng toàn cục
        });
    }
};

obj.method();

Thông qua đối tượng:

Ở đây, this sẽ tham chiếu tới đối tượng tương ứng chứa hàm. Ví dụ:

var obj = {
    method: function() {
        console.log(this);
    }
};

obj.method();    // this sẽ tương ứng với đối tượng obj

// Gắn method cho đối tượng khác
var anotherObj = {
    name: "new Obj"
};
anotherObj.method = obj.method;

anotherObj.method(); // this sẽ tương ứng với đối tượng anotherObj

Tuy nhiên nếu truyền vào như một callback cho một hàm khác thì sao? Giả sử:

var obj = {
    method: function() {
        console.log(this);
    }
};
$('#button').click(obj.method);

Lúc này thì surprise :v this đã tham chiếu đến button chứ không phải là obj nữa. Vậy làm sao để this có thể tham chiếu đến đối tượng trong trường hợp này?

JavaScript cho chúng ta cách giải quyết đó là đưa ngữ cảnh của this vào đối tượng bằng hàm bind(), nó sẽ giúp chúng ta xác định được ngữ cảnh cho this.

// Dùng bind
$('#button').click(obj.method.bind(obj)); //this ở đây vẫn là object obj

// Hoặc có thể dùng anonymous function
$('#button').click(function(){ obj.method() });

Thông qua một biến:

var name = "Anh";
var user = {
    name: "Anh Nguyen",
    getName: function () {
        return this.name; // this sẽ tương ứng với đối tượng user
    }
};

user.getName(); // Anh Nguyen

var getUserName = user.getName; // Tuy nhiên ở đây gán cho biến global
getUserName(); // Anh 

Như ở ví dụ trên, để có thể lấy đúng giá trị của name trong đối tượng user chúng ta có thể viết lại như sau:

var name = "Anh";
var user = {
    name: "Anh Nguyen",
    getName: function () {
        return this.name; // this sẽ tương ứng với đối tượng user
    }
};

var getUserName = user.getName.bind(user); // Tuy nhiên ở đây gán cho biến global
getUserName(); // Anh Nguyen

Vừa rồi là một số ví dụ về các trường hợp của this trong JavaScript và cách giải quyết vấn đề bằng bind(), ngoài ra các bạn có thể tìm hiểu thêm call() và apply() để có thể sử dụng this linh hoạt hơn.

Kết luận

Đã có khá nhiều bài viết về con trỏ this trong JavaScript tuy nhiên mình vẫn quyết định viết và tổng hợp lại vì đây là kiến thức quan trọng để có thể xử lý tình huống trơn tru và giải quyết vấn đề tốt hơn khi làm việc. Mong các bạn có thể tìm thấy phần mình cần ở đây.

Nguồn: https://viblo.asia/p/this-trong-javascript-gDVK2MGX5Lj

Các bạn có thể tham khảo các bài viết hay về JavaScript tại đây.


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Trở thành lập trình viên từ con số 0
Tags:
,

Leave a Reply

Your email address will not be published. Required fields are marked *