10 Câu hỏi Phỏng vấn Mà Mọi Lập trình viên JavaScript Cần Biết (Phần 2)
Mở đầu:
JavaScript đóng vai trò quan trọng trong việc phát triển ứng dụng web hiện nay. Để trở thành một lập trình viên JavaScript giỏi, bạn cần nắm vững kiến thức cơ bản và hiểu rõ về các khái niệm quan trọng trong ngôn ngữ này. Dưới đây là 10 câu hỏi phỏng vấn mà mọi lập trình viên JavaScript cần biết (Phần 2), giúp bạn chuẩn bị tốt cho các cuộc phỏng vấn và nâng cao kiến thức chuyên môn của mình. Đây chỉ là phần trả lời khi phỏng vấn, nếu bạn chưa có kiến thức về câu hỏi nào thì mình đã có viết khá nhiều bài về Javascript cơ bản và nâng cao các bạn tham khảo nhé.
6. Trong trường hợp nào nên sử dụng kế thừa nguyên mẫu (prototypal inheritance)?
Kế thừa nguyên mẫu có nhiều loại:
- Ủy quyền (delegation), tức là chuỗi nguyên mẫu (prototype chain).
- Nối (concatenative), ví dụ như mixin,
Object.assign()
. - Hàm (functional), không nhầm lẫn với lập trình hàm. Đây là một hàm được sử dụng để tạo một closure cho trạng thái riêng tư/bao đóng (encapsulation).
Mỗi loại kế thừa nguyên mẫu đều có bộ ứng dụng riêng, nhưng tất cả chúng đều có khả năng kết hợp (composition) tốt, tạo ra mối quan hệ "có thể" (can-do), "sử dụng" (uses-a) hoặc "có" (has-a), thay vì mối quan hệ "là" (is-a) do kế thừa lớp (class inheritance) tạo ra.
Điểm cộng:
- Nên sử dụng kế thừa nguyên mẫu khi các module hoặc lập trình hàm không cung cấp một giải pháp rõ ràng.
- Khi cần kết hợp đối tượng từ nhiều nguồn khác nhau.
- Bất kỳ lúc nào cần kế thừa.
Điểm trừ:
- Không biết khi nào nên sử dụng nguyên mẫu.
- Không nhận thức được về mixin hoặc
Object.assign()
.
7. Cụm từ "ưu tiên kết hợp đối tượng hơn kế thừa lớp" (favor object composition over class inheritance) có ý nghĩa gì?
Đây là một trích dẫn từ cuốn sách "Design Patterns: Elements of Reusable Object-Oriented Software". Nó có nghĩa là việc tái sử dụng mã nguồn nên được thực hiện bằng cách kết hợp các đơn vị chức năng nhỏ hơn vào đối tượng mới, thay vì kế thừa từ các lớp và tạo ra hệ thống phân loại đối tượng.
Nói cách khác, hãy sử dụng các mối quan hệ có thể (can-do), có (has-a) hoặc sử dụng (uses-a) thay vì mối quan hệ là (is-a).
Điểm cộng:
- Tránh sử dụng hệ thống kế thừa phức tạp.
- Tránh vấn đề lớp cơ sở dễ gãy (brittle base class problem).
- Tránh sự kết nối chặt chẽ (tight coupling).
- Tránh hệ thống phân loại cứng nhắc (rigid taxonomy) (các mối quan hệ "là" bị ép buộc mà sau này không phù hợp với các trường hợp sử dụng mới).
- Tránh vấn đề "khỉ đột giữ chuối" (gorilla banana problem) ("bạn muốn có một quả chuối, nhưng bạn lại nhận được một con khỉ đột giữ quả chuối và cả khu rừng xung quanh").
- Làm cho mã nguồn linh hoạt hơn.
Điểm trừ:
- Không đề cập đến bất kỳ vấn đề nào ở trên.
- Không thể phân biệt sự khác biệt giữa kết hợp đối tượng và kế thừa lớp, hoặc lợi ích của việc kết hợp đối tượng.
8. Hai chiều ràng buộc dữ liệu (two-way data binding) và dòng dữ liệu một chiều (one-way data flow) là gì và sự khác biệt giữa chúng là gì?
Hai chiều ràng buộc dữ liệu có nghĩa là các trường giao diện người dùng (UI) được ràng buộc động với dữ liệu mô hình, khi một trường UI thay đổi, dữ liệu mô hình cũng thay đổi theo và ngược lại.
Dòng dữ liệu một chiều có nghĩa là mô hình là nguồn sự thật duy nhất. Thay đổi trong giao diện người dùng kích hoạt các tin nhắn thông báo ý định của người dùng đến mô hình (hoặc "store" trong React). Chỉ mô hình mới có quyền truy cập để thay đổi trạng thái của ứng dụng. Kết quả là dữ liệu luôn luôn chảy theo một hướng duy nhất, giúp dễ hiểu hơn.
Dòng dữ liệu một chiều là xác định, trong khi ràng buộc dữ liệu hai chiều có thể gây ra hiệu ứng phụ, khó theo dõi và hiểu.
Điểm cộng:
- React là ví dụ tiêu chuẩn mới về dòng dữ liệu một chiều, việc đề cập đến React là một tín hiệu tốt. Cycle.js cũng là một cách triển khai phổ biến của dòng dữ liệu đơn hướng.
- Angular là một framework phổ biến sử dụng ràng buộc dữ liệu hai chiều.
Điểm trừ:
- Không hiểu ý nghĩa của hai chiều ràng buộc dữ liệu và dòng dữ liệu một chiều. Không thể phân biệt sự khác biệt giữa chúng.
9. Ưu và nhược điểm của kiến trúc đơn khối (monolithic) so với kiến trúc vi dịch vụ (microservice) là gì?
Kiến trúc đơn khối (monolithic) có nghĩa là ứng dụng của bạn được viết dưới dạng một đơn vị mã nguồn liền mạch, các thành phần được thiết kế để làm việc cùng nhau, chia sẻ cùng không gian bộ nhớ và tài nguyên.
Kiến trúc microservice có nghĩa là ứng dụng của bạn được tạo thành từ nhiều ứng dụng nhỏ hơn, độc lập, có khả năng chạy trong không gian bộ nhớ riêng của chúng và mở rộng độc lập với nhau trên nhiều máy tính khác nhau.
Ưu điểm của kiến trúc đơn khối: Ưu điểm lớn của kiến trúc đơn khối là hầu hết các ứng dụng thường có nhiều vấn đề chéo như ghi log, giới hạn tốc độ và các tính năng bảo mật như đường dẫn kiểm tra và bảo vệ chống tấn công từ chối dịch vụ (DOS).
Khi tất cả mọi thứ đều chạy qua cùng một ứng dụng, việc kết nối các thành phần với những vấn đề chéo trở nên dễ dàng.
Có thể có lợi thế về hiệu năng, vì truy cập bộ nhớ chia sẻ nhanh hơn so với giao tiếp giữa các tiến trình (IPC).
Nhược điểm của kiến trúc đơn khối: Các dịch vụ ứng dụng đơn khối thường bị kết nối chặt chẽ và rối rắm khi ứng dụng phát triển, khiến việc cô lập các dịch vụ cho mục đích như mở rộng độc lập hoặc bảo trì mã nguồn trở nên khó khăn.
Kiến trúc đơn khối cũng khó hiểu hơn, bởi vì có thể có các phụ thuộc, hiệu ứng phụ và "ma thuật" không rõ ràng khi bạn xem xét một dịch vụ hoặc điều khiển cụ thể.
Ưu điểm của kiến trúc microservice: Kiến trúc microservice thường được tổ chức tốt hơn, vì mỗi microservice có một công việc rất cụ thể và không liên quan đến công việc của các thành phần khác. Các dịch vụ không liên kết cũng dễ dàng hơn để tổng hợp và cấu hình lại để phục vụ mục đích của các ứng dụng khác nhau (ví dụ: phục vụ cả khách hàng trên web và API công khai).
Chúng cũng có thể có lợi thế về hiệu năng tùy thuộc vào cách tổ chức, bởi vì có thể cô lập các dịch vụ nóng và mở rộng chúng độc lập với phần còn lại của ứng dụng.
Nhược điểm của kiến trúc microservice: Khi bạn xây dựng một kiến trúc microservice mới, bạn có thể phát hiện ra nhiều vấn đề chéo mà bạn không dự đoán được trong quá trình thiết kế. Một ứng dụng đơn khối có thể thiết lập các trợ giúp kỳ diệu được chia sẻ hoặc các lớp trung gian để xử lý các vấn đề chéo mà không cần nhiều nỗ lực.
Trong kiến trúc microservice, bạn sẽ cần chịu chi phí của các module riêng biệt cho từng vấn đề chéo hoặc đóng gói các vấn đề chéo vào một lớp dịch vụ khác mà tất cả lưu lượng truy cập đều được định tuyến qua đó.
Cuối cùng, ngay cả kiến trúc đơn khối cũng có xu hướng định tuyến lưu lượng truy cập qua một lớp dịch vụ ngoài cho các vấn đề chéo, nhưng với kiến trúc đơn khối, bạn có thể hoãn chi phí công việc đó cho đến khi dự án trưởng thành hơn.
Các microservice thường được triển khai trên các máy ảo hoặc container riêng biệt của chúng, dẫn đến việc làm nhiều công việc quản lý máy ảo. Các tác vụ này thường được tự động hóa bằng các công cụ quản lý container.
Điểm cộng: - Thái độ tích cực đối với kiến trúc microservice, mặc dù chi phí ban đầu cao hơn so với ứng dụng đơn khối. Nhận thức được rằng các microservice thường hoạt động và mở rộng tốt hơn trong dài hạn. - Thực tế về kiến trúc microservice và đơn khối. Cấu trúc ứng dụng sao cho các dịch vụ độc lập với nhau ở cấp độ mã nguồn, nhưng dễ dàng kết hợp lại thành một ứng dụng đơn khối ở giai đoạn đầu. Chi phí vận hành của kiến trúc microservice có thể được hoãn lại cho đến khi trở nên thực tế hơn để trả giá. Điểm trừ: - Không hiểu sự khác biệt giữa kiến trúc đơn khối và kiến trúc microservice. - Không nhận thức được hoặc không thực tế về chi phí vận hành bổ sung của kiến trúc microservice. - Không nhận thức được chi phí hiệu suất bổ sung do IPC và giao tiếp mạng trong kiến trúc microservice. - Quá tiêu cực về nhược điểm của kiến trúc microservice. Không thể diễn đạt được các cách mà ứng dụng đơn khối có thể được tách ra thành các dịch vụ vi mạch khi đến lúc thích hợp. - Đánh giá thấp lợi thế của việc mở rộng độc lập các microservice.
10. Lập trình bất đồng bộ là gì và tại sao lại quan trọng trong JavaScript?
Lập trình đồng bộ có nghĩa là, trừ điều kiện và lời gọi hàm, mã được thực thi tuần tự từ trên xuống dưới, chặn các tác vụ kéo dài như yêu cầu mạng (Call API) và đọc/ghi đĩa IO....
Lập trình bất đồng bộ có nghĩa là động cơ (engine) chạy trong một vòng lặp sự kiện (even loop). Khi cần thực hiện một hoạt động chặn, yêu cầu được bắt đầu và mã tiếp tục chạy mà không chặn kết quả. Khi phản hồi sẵn sàng, một ngắt được kích hoạt, khiến trình xử lý sự kiện được chạy, nơi mà luồng điều khiển tiếp tục. Bằng cách này, một luồng chương trình đơn có thể xử lý nhiều hoạt động đồng thời.
Giao diện người dùng UI có tính bất đồng bộ theo bản chất và dành phần lớn thời gian chờ đợi đầu vào người dùng để ngắt vòng lặp sự kiện và kích hoạt trình xử lý sự kiện.
Node.js cũng hoạt động theo cơ chế bất đồng bộ mặc định, có nghĩa là máy chủ hoạt động theo cách tương tự, chờ đợi trong một vòng lặp cho một yêu cầu mạng và chấp nhận nhiều yêu cầu đến trong khi yêu cầu đầu tiên đang được xử lý.
Điều này rất quan trọng trong JavaScript, bởi vì nó rất phù hợp cho mã giao diện người dùng và rất có lợi cho hiệu năng trên máy chủ.
Điểm cộng:
- Hiểu được ý nghĩa của việc Blocking IO và hậu quả về hiệu năng.
- Hiểu được xử lý sự kiện và tại sao nó lại quan trọng đối với mã giao diện người dùng.
- Even loop
Điểm trừ:
- Không quen với thuật ngữ bất đồng bộ hoặc đồng bộ.
- Không thể diễn đạt được hậu quả về hiệu năng hoặc mối quan hệ giữa mã bất đồng bộ và mã giao diện người dùng.
Kết luận
Đối với nhà tuyển dụng thì, nếu ứng viên có thể trả lời những câu hỏi này, điều đó thường có nghĩa là họ có đủ kinh nghiệm lập trình để nắm bắt những điểm đặc biệt và cú pháp của ngôn ngữ trong vài tuần, ngay cả khi họ không có nhiều kinh nghiệm với JavaScript.
Điều mà nhà tuyển dụng thực sự cần biết là: "Ứng viên này có hiểu cách xây dựng một ứng dụng hay không?"
Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.
Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.
Momo: NGUYỄN ANH TUẤN - 0374226770
TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)
All rights reserved