Hiểu về "this" trong JavaScript

Ngày đăng: 10/04/2021   -    Cập nhật: 08/05/2021
Trong bài viết này, mình sẽ bạn sẽ tìm hiểu về giá trị this trong JavaScript và hiểu nó rõ ràng trong các ngữ cảnh khác nhau.


Nếu bạn đang làm việc với các ngôn ngữ lập trình khác như C++, Java và PHP, bạn đã quen thuộc với từ khóa this.


Trong các ngôn ngữ này, từ khóa this đại diện cho thể hiện của đối tượng hiện tại trong phương thức của class.


Và từ khóa this chỉ có liên quan trong một phương thức của class, có nghĩa là bạn không thể sử dụng nó bên ngoài một phương thức.


Tuy nhiên, JavaScript có từ khóa this hoạt động khác với các ngôn ngữ lập trình khác, điều này khiến rất nhiều người bối rối.



this trong JavaScript


Trong JavaScript, bạn có thể sử dụng từ khóa this trong ngữ cảnh toàn cục và ngữ cảnh hàm. Hơn nữa, hành vi của từ khóa this cũng thay đổi giữa chế độ nghiêm ngặt (strict mode) và không nghiêm ngặt (none-strict mode).


this là gì?



Từ khóa this tham chiếu đến đối tượng hiện đang gọi hàm.


Giả sử rằng bạn có một đối tượng được gọi là counter. Đối tượng counter này có một phương thức được gọi là next().


Khi bạn gọi phương thức next(), bạn có thể truy cập đối tượng this.




const counter = {
    count: 0,
    next: function () {
        return ++this.count;
    }
};

counter.next();
 


Bên trong hàm next(), this tham chiếu đến đối tượng counter.


Xem lệnh gọi phương thức sau:




counter.next();
 


next() là một hàm (cũng gọi là thuộc tính hoặc phương thức) của đối tượng counter. Do đó, bên trong hàm next(), this tham chiếu đến đối tượng counter.


> Lưu ý: Khi một hàm là một thuộc tính của một đối tượng, nó được gọi là một phương thức



this trong ngữ cảnh toàn cục



Trong ngữ cảnh toàn cục (global context), this tham chiếu đến đối tượng toàn cục, là đối tượng window trên trình duyệt web hoặc đối tượng global trên Node.js.


Hành vi này nhất quán cho dù chế độ nghiêm ngặt có được áp dụng hay không, ví dụ thử gọi câu lệnh này trong phạm vi cao nhất:




console.log(this === window); // true
 


Nếu bạn gán một thuộc tính cho đối tượng this trong ngữ cảnh toàn cục, JavaScript sẽ thêm thuộc tính vào đối tượng toàn cục như trong ví dụ sau:



this.color'Red';
console.log(window.color); // 'Red'
 


this trong ngữ cảnh hàm



Trong JavaScript, bạn có thể gọi một hàm theo những cách sau:


  • Gọi hàm thông thường
  • Gọi phương thức
  • Gọi hàm khởi tạo
  • Gọi hàm gián tiếp


Mỗi lời gọi hàm xác định ngữ cảnh riêng của nó, do đó, this có thể hoạt động khác với những gì bạn nghĩ.


Case #1: this trong lời gọi hàm thông thường



Trong chế độ không nghiêm ngặt (non-strict mode), this tham chiếu đến đối tượng toàn cục khi hàm được gọi như sau:



function show() {
    console.log(this === window); // true
}

show();
 


Khi bạn gọi hàm show(), this tham chiếu đến đối tượng toàn cục, là đối tượng window trên trình duyệt web và là đối tượng global trên Node.js.


Do đó, lệnh gọi hàm show() ở trên cũng tương đương như sau:




window.show();
 


Trong chế độ nghiêm ngặt (strict mode), để hạn chế hành vi không rõ ràng, lời gọi hàm như vậy sẽ được JavaScript đặt giá trị this thành undefined.


Hãy xem xét ví dụ sau:




"use strict"// Khai báo strict mode

function show() {
    console.log(this === undefined); // true
}

show();
 


Lưu ý:

  • Để thiết lập chế độ nghiêm ngặt, bạn có thể sử dụng chỉ thị "use strict" ở đầu tệp.
  • Nếu bạn chỉ muốn áp dụng chế độ nghiêm ngặt cho một hàm cụ thể, bạn đặt nó ở đầu thân hàm.


Chế độ nghiêm ngặt đã có sẵn kể từ ECMAScript 5.1. Chế độ nghiêm ngặt áp dụng cho cả hàm và các hàm lồng nhau. Đây là một ví dụ:



function show() {
    "use strict";
    console.log(this === undefined); // true

    function display() {
        console.log(this === undefined); // true
    }
    display();
}

show();
 


Kết quả:



true
true
 




Trong hàm bên trong display(), this cũng được đặt thành undefined bởi vì "use strict" có tác dụng.

 

Case #2: this trong lời gọi phương thức



Khi bạn gọi một phương thức của một đối tượng, JavaScript sẽ đặt this cho đối tượng sở hữu phương thức.


Xem đối tượng car sau:




let car = {
    brand: 'Vinfast',
    getBrand: function () {
        return this.brand;
    }
}

console.log(car.getBrand()); // Vinfast
 


Trong ví dụ này, đối tượng this trong phương thức getBrand() tham chiếu đến đối tượng car.


Và vì một phương thức là thuộc tính của một đối tượng, cũng là một giá trị, thế nên bạn có thể lưu trữ nó trong một biến như thế này:




let brand = car.getBrand;
 


Và sau đó, gọi phương thức thông qua biến rất bình thường như sau:



console.log(brand()); // undefined
 


Kết quả, bạn nhận được undefined thay vì Vinfast như mong đợi.


Bởi vì, khi bạn gọi một phương thức mà không chỉ định đối tượng của nó, JavaScript sẽ đặt this thành đối tượng toàn cục ở chế độ không nghiêm ngặt và undefined trong chế độ nghiêm ngặt.


Để xử lý tình huống này, bạn có thể sử dụng phương thức bind() của đối tượng Function.prototype.


Phương thức bind() tạo một hàm mới có từ khóa this được đặt thành một giá trị được chỉ định.


 


let brand = car.getBrand.bind(car);
console.log(brand()); // Vinfast
 



Trong ví dụ trên, khi bạn gọi phương thức brand(), từ khóa this được liên kết với đối tượng car bởi bind()


Một ví dụ khác, sử dụng bind() để liên kết đến đối tượng chỉ định.


 


let car = {
    brand: 'Vinfast',
    getBrand: function () {
        return this.brand;
    }
}

let bike = {
    brand: 'Thống Nhất'
}

let brand = car.getBrand.bind(bike);
console.log(brand());
 



Kết quả:

 


Thống Nhất
 



Trong ví dụ này, phương thức bind() đặt giá trị this cho đối tượng bike, do đó, bạn thấy giá trị thuộc tính brand của đối tượng bike trong kết quả.

 

Case #3: this trong lời gọi hàm khởi tạo



Khi bạn sử dụng từ khóa new để tạo một thể hiện của một đối tượng hàm, bạn sử dụng hàm như một phương thức khởi tạo (constructor).


> Đọc chi tiết hơn về Constructor trong JavaScript


Ví dụ sau khai báo một hàm Car, sau đó gọi nó như một hàm tạo:




function Car(brand) {
    this.brand = brand;
}

Car.prototype.getBrand = function () {
    return this.brand;
}

var car = new Car('Vinfast');
console.log(car.getBrand());
 


Biểu thức new Car('Vinfast') là một lệnh gọi hàm tạo của hàm Car.


JavaScript tạo một đối tượng mới và đặt đối tượng this thành đối tượng mới được tạo (Cách này hoạt động tốt nhưng có một vấn đề tiềm ẩn)


Bây giờ, bạn có thể gọi Car() dưới dạng một hàm hoặc như một phương thức khởi tạo.


Nếu bạn bỏ qua từ khóa new như sau:




var kia = Car('Kia');
console.log(kia.brand);
// TypeError: Cannot read property 'brand' of undefined
 


Vì giá trị this trong Car() được đặt thành đối tượng toàn cục, do đó kia.brand trả về không xác định.


Để đảm bảo rằng hàm Car() luôn được gọi bằng cách gọi hàm tạo, bạn thêm kiểm tra vào đầu hàm Car() như sau:




function Car(brand) {
    if (!(this instanceof Car)) {
        throw Error('Phải sử dụng từ khóa new');
    }
    this.brand = brand;
}
 


ES6 đã giới thiệu một thuộc tính meta có tên new.target cho phép bạn phát hiện xem một hàm được gọi như một lời gọi hàm đơn giản hay như một hàm tạo.


Bạn có thể sửa đổi hàm Car() sử dụng new.target như sau:




function Car(brand) {
    if (!new.target) {
        throw Error('Phải sử dụng từ khóa new');
    }
    this.brand = brand;
}
 


 

Case #4: this trong lời gọi hàm gián tiếp



Trong JavaScript, các hàm là first-class citizens. Nói cách khác, các hàm là các đối tượng, là các thể hiện của kiểu Function.


Kiểu Function có hai phương thức: call()apply(). Các phương thức này cho phép bạn đặt giá trị this khi gọi một hàm.


Ví dụ:


 


function getBrand(prefix) {
    console.log(prefix + this.brand);
}

let vinfast = {
    brand: 'Vinfast'
};
 
let kia = {
    brand: 'Kia'
};

getBrand.call(vinfast"Đây là ");
getBrand.call(kia"Đây là ");
 



Kết quả:

 


Đây là Vinfast
Đây là Kia
 



Trong ví dụ này, chúng ta đã gọi hàm getBrand() một cách gián tiếp bằng cách sử dụng phương thức call() của hàm getBrand.


Chúng ta đã chuyển đối tượng vinfastkia làm đối số đầu tiên của phương thức call(), do đó, chúng ta có thương hiệu tương ứng trong mỗi lần gọi.


Phương thức apply() tương tự như phương thức call() ngoại trừ đối số thứ hai của nó là một mảng các đối số.


 


getBrand.apply(vinfast"Đây là "); // Đây là Vinfast
getBrand.apply(kia"Đây là "); // Đây là Kia
 


 

this trong Arrow Function



ES6 đã giới thiệu một khái niệm mới có tên là Arrow Function, bạn cũng có thể gọi đến this trong đó.


Tuy nhiên, arrow function không tạo bối cảnh thực thi của riêng nó, mà kế thừa this từ hàm bên ngoài nơi arrow function được định nghĩa.


Xem ví dụ sau:




let getThis = () => this;
console.log(getThis() === window); // true
 


Trong ví dụ này, giá trị this được đặt thành đối tượng toàn cục, tức là window trong trình duyệt web.


Và vì một hàm mũi tên không tạo ngữ cảnh thực thi của riêng nó, nên việc xác định một phương thức bằng arrow function sẽ gây ra sự cố.


Ví dụ:




function Car() {
    this.speed = 100;
}

// Thêm vào đối tượng Car một hàm
// bằng arrow function
Car.prototype.getSpeed = () => {
    return this.speed;
}

var car = new Car();
car.getSpeed(); // TypeError
 


Bên trong phương thức getSpeed​(), giá trị this tham chiếu đến đối tượng toàn cục, không phải đối tượng Car.


Do đó, lời gọi car.getSpeed​​() gây ra lỗi vì đối tượng toàn cục không có thuộc tính speed.



Tổng kết về cái "this" trong JavaScript



Như vậy, qua bài viết này bạn đã hiểu về hành vi của this trong JavaScript, cụ thể nó hoạt động như thế nào trong ngữ cảnh toàn cục, ngữ cảnh hàm và khi sử dụng Arrow function.


Mình cũng đã phân chia ra các trường hợp this trong các cách gọi hàm, hi vọng giúp bạn hiểu và vận dụng this trong JavaScript tốt hơn.


> Nếu bạn đang tích cực học JavaScript và muốn học nhanh hơn, bài bản hơn để đi làm thì hãy đăng ký HỌC FRONT END ngay hôm nay!



---
HỌC VIỆN ĐÀO TẠO CNTT NIIT - ICT HÀ NỘI
Học Lập trình chất lượng cao (Since 2002). Học thực tế + Tuyển dụng ngay!
Đc: Tầng 3, 25T2, N05, Nguyễn Thị Thập, Cầu Giấy, Hà Nội
SĐT: 02435574074 - 0383.180086
Email: hello@niithanoi.edu.vn
Fanpage: https://facebook.com/NIIT.ICT/
 
#niit #icthanoi #niithanoi #niiticthanoi #hoclaptrinh #khoahoclaptrinh #hoclaptrinhjava #hoclaptrinhphp
Bình luận Facebook
Khóa học liên quan đến bài viết

KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS

56 giờ
Học Lập trình Front end hiện đại với ReactJS. Học làm chủ HTML, CSS, JS và thư viện JavaScript phổ biến nhất hiện nay. Sẵn sàng đi thực tập / đi làm ngay sau khóa học.

Khóa học PHP Full stack [2023] cho người mới bắt đầu

96 giờ
Khóa học Lập trình PHP Full stack, phiên bản cập nhật lần thứ 8. Dạy Lập trình PHP bài bản từ Front end đến Back end + Laravel. Hướng dẫn làm 2 Dự Án Web lớn

KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG

50 giờ
Khóa học giúp học viên sử dụng thành thạo ngôn ngữ Lập trình Python (3x). Hiểu và phát triển được Ứng dụng Web với Django Framework. Học thực hành với Giảng viên cao cấp.

Khóa học Java Full stack (IJFD)

104 giờ
Học lập trình Java Fullstack với khóa học được xây dựng theo lộ trình bài bản, từ JAVA CƠ BẢN đến JAVA WEB và nâng cao về JAVA FRAMEWORK như: Spring Boot, Hibernate
Mục lục
Đăng ký tư vấn
Nhân viên gọi điện tư vấn miễn phí sau khi đăng ký
Được cập nhật các ưu đãi sớm nhất
Hotline: 0383180086
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Hãy đăng ký để nhận những thông tin mới nhất về học bổng mới nhất tại NIIT - ICT Hà Nội
top
Đóng lại Đăng ký học tại NIIT - ICT Hà Nội
6260+ học viên đã theo học tại NIIT - ICT Hà Nội và có việc làm tốt trong ngành lập trình. Nắm lấy cơ hội ngay hôm nay!
Chọn khóa học
  • KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS
  • KHÓA HỌC LẬP TRÌNH PHP WEB
  • Khóa học PHP Full stack [2023] cho người mới bắt đầu
  • Khóa học BIG DATA với Hadoop và Spark
  • Khóa học Lập trình Android tại Hà Nội
  • [Tuyển sinh 2023] Lập trình viên Quốc tế DigiNxt
  • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại Hà Nội
  • LẬP TRÌNH GAME
    • Khóa học Lập trình Game Unity
  • LẬP TRÌNH WEB FRONT END
    • KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG
    • KHÓA HỌC ANGULAR & TYPESCRIPT (FRONT END)
  • LẬP TRÌNH WEB BACK END
    • LẬP TRÌNH JAVA WEB VỚI FRAME WORK
    • Lập trình Web với Django
    • Lập trình PHP với Laravel Framework
  • CHƯƠNG TRÌNH ĐÀO TẠO ỨNG DỤNG CÔNG NGHỆ
    • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại TP HCM
  • LẬP TRÌNH WEB FULL STACK
    • Khóa học Java Full stack (IJFD)
  • LẬP TRÌNH MOBILE
    • FRONT-END VỚI REACTJS VÀ REACT NATIVE
    • Lập trình Android Nâng cao
  • ĐÀO TẠO CHO DOANH NGHIỆP
    • KHÓA HỌC BUSINESS ANALYSIC TỪ CƠ BẢN ĐẾN NÂNG CAO 2023
    • Khóa học Magento: Làm chủ CMS TMĐT lớn nhất
    • Khóa học IOT: Xây dựng Sản phẩm IOT với Raspberry Pi
    • Khóa học Automation Testing Chuyên nghiệp
  • KHÓA HỌC DỰ ÁN
    • Học sử dụng bộ Office: Word, Excel, Power Point, Mail chuyên nghiệp
  • KHÓA HỌC KHÁC
    • VBA Excel Toàn Tập (Cơ Bản - Nâng Cao)
    • VBA Excel Nâng cao
    • Khóa học JMeter: Performance Testing
    • Khóa học Tester đạt chuẩn Quốc tế ISTQB Foundation Level
    • Khoá Học Tester đạt chuẩn quốc tế ISTQB Advanced Level
Bạn chưa chọn khóa học cần đăng ký
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Đăng ký học thành công!
Cảm ơn bạn đã đăng ký học tại NIIT - ICT HÀ NỘI!