aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
SAVED POSTS
aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
aedev.net
No Result
View All Result
Lập trình viên chuẩn bị phỏng vấn fresher React Native với laptop, điện thoại và thẻ câu hỏi

Phỏng vấn JavaScript: vì sao tách method thành callback lại mất this?

Suong Nguyen by Suong Nguyen
29/10/2026
in Phỏng vấn
0
585
SHARES
3.2k
VIEWS
Summarize with ChatGPTShare to Facebook

Bạn truyền counter.read cho một hàm nhận callback, rồi code lỗi dù counter.read() vẫn chạy. Khi giải thích trong phỏng vấn, đừng bắt đầu bằng “callback chạy muộn nên mất this”. Vấn đề có thể xuất hiện ngay trong một lời gọi đồng bộ, không liên quan event loop.

Bài đối chiếu tài liệu JavaScript ngày 29/10/2026 và chạy ví dụ trên Node.js 24.18.1. Dùng strict mode rõ ràng để kết quả không phụ thuộc một môi trường có tự thay this bằng global object hay không. Các snippet không dùng timer, DOM hoặc React.

Bắt đầu từ cách gọi

'use strict';

const counter = {
  value: 7,
  read() {
    return this.value;
  },
};

console.log(counter.read());
const detached = counter.read;
try {
  console.log(detached());
} catch (error) {
  console.log(error.name);
}

Kết quả là 7 rồi TypeError. Gán method vào biến lấy ra cùng function, nhưng lời gọi detached() không còn dạng counter.read(). Trong strict mode, lời gọi độc lập ấy truyền this là undefined; đọc .value mới gây lỗi.

Theo MDN this, regular function nhận this theo cách được gọi. Object chứa property không đóng dấu vĩnh viễn rằng function luôn thuộc object đó.

Callback không tự mang theo receiver

function invoke(callback) {
  return callback();
}

try {
  console.log(invoke(counter.read));
} catch (error) {
  console.log(error.name);
}

Vẫn là TypeError. Hàm invoke đã gọi callback ngay lập tức. Điều này giúp loại giả thuyết rằng chỉ setTimeout hoặc Promise mới gây ra lỗi.

Khi đọc code thật, tìm chính xác lời gọi callback. Nếu thư viện gọi callback.call(something), holder.callback() hoặc truyền this theo hợp đồng khác, receiver có thể khác. Không thể suy ra this chỉ từ việc function được truyền vào tham số.

Hai cách giữ lời gọi có chủ đích

const bound = counter.read.bind(counter);
const wrapped = () => counter.read();

console.log(invoke(bound));
console.log(invoke(wrapped));
console.log(bound === counter.read.bind(counter));

Ba kết quả là 7, 7, false. Bind tạo một function mới giữ receiver đã chỉ định. Nếu API cần gỡ callback bằng đúng tham chiếu đã đăng ký, lưu biến bound rồi dùng lại; bind thêm một lần tạo tham chiếu khác.

Arrow wrapper ở đây không đọc this trực tiếp. Nó gọi lại method qua biến counter bằng cú pháp counter.read(). Cách sửa này thể hiện object được chọn ở trong thân callback, thay vì yêu cầu bên gọi truyền receiver đúng.

Hai cách cũng có khác biệt khi method bị thay. Bound giữ function ban đầu; wrapper tra counter.read mỗi lần được gọi. Bạn nên chọn theo hợp đồng mong muốn, không coi chúng đồng nghĩa trong mọi trường hợp. Function.bind giải thích việc tạo function mới và cố định this cho lời gọi thông thường.

Arrow đặt trong object không tự lấy object làm this

Một đáp án sửa sai thường gặp là đổi mọi method sang arrow. Ví dụ dưới đây cố tình tạo object trong một function strict được gọi độc lập:

function makeCounter() {
  'use strict';
  return {
    value: 7,
    read: () => this,
  };
}

const wrong = makeCounter();
console.log(wrong.read() === undefined);
console.log(wrong.read.call({ value: 99 }) === undefined);

Cả hai dòng là true. Arrow không có this binding riêng; nó dùng this của scope tạo ra nó. Dấu ngoặc object literal không tạo một receiver scope cho arrow. Gọi .call(...) không thay được this đã được arrow lấy từ bên ngoài.

Arrow functions reference mô tả sự khác biệt này. Arrow làm callback rất hữu ích, nhưng lý do dùng là ngữ nghĩa scope cần có, không phải quy tắc “arrow luôn sửa lỗi this”.

Cách trả lời và mở rộng bài tập

Một câu trả lời đủ rõ có thể đi theo ba bước: chỉ ra receiver của lời gọi ban đầu, chỉ ra receiver sau khi tách function, rồi sửa đúng tại nơi hợp đồng bị thay. Cuối cùng, chứng minh bằng snippet ngắn thay vì dự đoán nội dung global object.

Để thử thêm, gọi counter.read.call({ value: 20 }) và xác nhận regular function trả 20. Sau đó thay method bằng một function trả 100, gọi bound và wrapped để quan sát bound vẫn dùng phần triển khai cũ. Khôi phục fixture hoặc chạy các thử nghiệm trong process riêng để không lẫn trạng thái.

Các ví dụ đồng bộ này chỉ kiểm tra cơ chế gọi. Chúng không nói một framework sẽ bind handler theo cách nào, cũng không đo chi phí cấp phát callback. Khi đi vào React hoặc event listener native, đọc thêm hợp đồng của API đó.

Lỗi thường gặp

  • Giải thích bằng thời điểm chạy dù lỗi vẫn xảy ra đồng bộ.
  • Nghĩ gán method sang biến đã clone cả object.
  • Gọi bind mỗi lần đăng ký/gỡ listener rồi mong hai callback bằng nhau.
  • Đổi method trong object literal sang arrow mà không kiểm tra this của scope ngoài.

Theo dõi cách gọi giúp bạn giải thích cả lỗi lẫn cách sửa. Khi receiver cần ổn định, hãy thể hiện nó bằng bind hoặc một lời gọi rõ ràng trong callback, rồi giữ tham chiếu đúng nếu API cần đăng ký và gỡ đăng ký.

Nguồn tham khảo

  • MDN: this
  • MDN: Arrow function expressions
  • MDN: Function.prototype.bind

Tags: CallbacksJavaScriptPhỏng vấn
SummarizeShare234
Suong Nguyen

Suong Nguyen

Related Stories

Lập trình viên chuẩn bị phỏng vấn fresher React Native với laptop, điện thoại và thẻ câu hỏi

Phỏng vấn JavaScript: vì sao callback trong vòng lặp đều đọc cùng giá trị?

by Suong Nguyen
28/10/2026
0

Tách vấn đề closure khỏi timer bằng các callback gọi sau vòng lặp, rồi so var, let và hàm tạo binding riêng.

Lập trình viên chuẩn bị phỏng vấn fresher React Native với laptop, điện thoại và thẻ câu hỏi

Phỏng vấn JavaScript: Object.is khác === thế nào với NaN, +0 và -0?

by Suong Nguyen
27/10/2026
0

Giải thích hai khác biệt về số của Object.is và ===, kiểm tra object identity và tránh nhầm Object.is với so sánh sâu.

Lập trình viên chuẩn bị phỏng vấn fresher React Native với laptop, điện thoại và thẻ câu hỏi

JavaScript sort: vì sao số 10 đứng trước 2 và mảng gốc bị đổi?

by Suong Nguyen
26/10/2026
0

Kiểm tra thứ tự mặc định, hợp đồng comparator, tính ổn định và cách dùng toSorted để giữ mảng gốc khi sắp xếp.

Lập trình viên chuẩn bị phỏng vấn fresher React Native với laptop, điện thoại và thẻ câu hỏi

JavaScript: chọn giá trị mặc định mà không làm mất 0, false và chuỗi rỗng

by Suong Nguyen
25/10/2026
0

Phân biệt toán tử OR, nullish coalescing và optional chaining bằng ví dụ chạy được cùng các trường hợp dễ nhầm khi đọc cấu hình.

0 0 votes
Article Rating
Subscribe
Login
Notify of
guest
guest
0 Comments
Oldest
Newest Most Voted
AE Dev

AE Dev mang đến các bài viết về lập trình, mobile app, backend, frontend, WordPress và công nghệ, phù hợp cho developer muốn học hỏi và cập nhật kiến thức thực tế.

Recent Posts

  • React Native TextInput: bàn phím numeric không thay thế validation
  • Phỏng vấn JavaScript: vì sao tách method thành callback lại mất this?
  • Android NumberFormat: tách locale, mã tiền tệ và giá trị cần hiển thị

Categories

  • AI
  • Backend
  • Đánh giá
  • DevOps
  • Flutter
  • Hướng dẫn
  • Lập trình Mobile
  • Phỏng vấn
  • React Native
  • Uncategorized

Weekly Newsletter

  • Buy JNews
  • Support Forum
  • Pre-sale Question
  • Contact Us

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Trang chủ
  • AI
  • Mobile
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
  • Flutter

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

wpDiscuz
0
0
Would love your thoughts, please comment.x
()
x
| Reply