Từ khóa this trong JavaScript: nó trỏ về đâu và cách kiểm soát

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

this là một trong những thứ khiến người học JavaScript đau đầu nhất, vì giá trị của nó không cố định mà phụ thuộc vào cách hàm được gọi, chứ không phải nơi hàm được viết. Khi nắm được vài quy tắc, bạn sẽ đoán đúng this trong hầu hết tình huống.

Quy tắc cốt lõi: nhìn vào nơi gọi

Với hàm thường, hãy nhìn xem hàm được gọi như thế nào:

  1. Gọi như phương thức doiTuong.ham(): this là doiTuong (phần trước dấu chấm).
  2. Gọi độc lập ham(): this là undefined ở strict mode (module và class luôn là strict), hoặc đối tượng toàn cục ở chế độ lỏng.
  3. Gọi với new: this là đối tượng mới được tạo.
  4. Gọi với call, apply, bind: this là giá trị bạn chỉ định.

Ví dụ phương thức của object

const nguoi = {
  ten: 'Lan',
  chao() {
    console.log('Xin chào, tôi là ' + this.ten);
  },
};

nguoi.chao(); // 'Xin chào, tôi là Lan'

const f = nguoi.chao;
f(); // this không còn là nguoi, this.ten lỗi hoặc undefined

Dòng cuối là lỗi kinh điển: tách phương thức ra khỏi đối tượng làm mất ngữ cảnh. Điều này hay xảy ra khi truyền phương thức làm callback, ví dụ button.addEventListener('click', nguoi.chao).

Cố định this bằng bind, call và apply

const chaoLan = nguoi.chao.bind(nguoi);
chaoLan(); // luôn đúng

function gioiThieu(loi) {
  console.log(loi + ', ' + this.ten);
}
gioiThieu.call({ ten: 'Nam' }, 'Chào');       // truyền đối số lần lượt
gioiThieu.apply({ ten: 'Mai' }, ['Chào']);    // truyền đối số bằng mảng

bind trả về hàm mới với this đã khóa, còn call và apply gọi ngay lập tức. Cách ghi nhớ: apply dùng mảng, call dùng danh sách.

Arrow function: this theo phạm vi bao quanh

Arrow function không có this riêng. Nó dùng this của nơi nó được viết (lexical this). Điều này giải quyết nhiều rắc rối trong callback:

const dongHo = {
  giay: 0,
  chay() {
    setInterval(() => {
      this.giay++;                 // this là dongHo nhờ arrow function
      console.log(this.giay);
    }, 1000);
  },
};
dongHo.chay();

Nếu thay arrow function bằng function () {} thường trong setInterval, this sẽ không còn là dongHo. Ngược lại, đừng dùng arrow function làm phương thức của object khi bạn cần this trỏ về chính object:

const sai = {
  ten: 'Lan',
  chao: () => console.log(this.ten), // this không phải sai
};

this trong class

class NutDem {
  constructor() {
    this.dem = 0;
    this.tang = this.tang.bind(this); // cố định this
  }
  tang() {
    this.dem++;
  }
}

// hoặc dùng trường class với arrow function
class NutDem2 {
  dem = 0;
  tang = () => {
    this.dem++;
  };
}

Hai cách trên đều đảm bảo phương thức tang luôn gắn với đúng đối tượng, kể cả khi bạn truyền nó làm callback cho sự kiện. Trong React với class component, đây từng là điều bạn phải làm thường xuyên.

this trong trình xử lý sự kiện DOM

Với hàm thường dùng làm trình xử lý sự kiện, this là phần tử đã gắn trình lắng nghe (event.currentTarget). Với arrow function thì không. Vì sự khác biệt dễ gây nhầm, nhiều người chọn dùng event.currentTarget trực tiếp thay vì this.

Mẹo thực tế

  • Nếu hàm không cần this, đừng dùng nó. Hàm thuần dễ kiểm thử hơn.
  • Khi gặp lỗi "Cannot read properties of undefined", hãy console.log(this) để xem ngữ cảnh.
  • Ưu tiên arrow function cho callback bên trong phương thức, hàm thường cho phương thức của object.
  • Dùng chế độ strict (module ES mặc định đã strict) để tránh this rơi vào đối tượng toàn cục.

Bài tập tự kiểm tra

Hãy thử đoán đoạn này in ra gì:

const obj = {
  ten: 'A',
  a() { return this.ten; },
  b: () => typeof this,
  c() { return [1].map(() => this.ten)[0]; },
};
console.log(obj.a()); // ?
console.log(obj.c()); // ?

Cả obj.a() và obj.c() đều cho 'A': ở a, this là obj vì gọi bằng dấu chấm; ở c, arrow function bên trong mượn this của phương thức bao ngoài. Riêng b là arrow function ở cấp module hoặc toàn cục nên this không phải obj. Việc tự đoán trước khi chạy giúp bạn rèn phản xạ rất tốt.

Kết luận

Hãy nhớ câu hỏi chính: "hàm này được gọi như thế nào?". Với arrow function thì câu hỏi là: "nó được viết ở đâu?". Chỉ cần vậy, bạn đã giải thích được đa số trường hợp this gây khó chịu.

Bạn có thể ôn tập chủ đề này cùng nhiều khái niệm JavaScript cốt lõi khác trong các khóa học tại codebem.com.

author_photo
Nguyễn Đình Cường

0 comment