Việc làm

29/09 · Hà Nội · Tại văn phòng

Software Engineer (HTML5, JavaScript/TypeScript, .NET)

Scandinavian Software Park · Fullstack Developer

Xem mô tả & ứng tuyển trên ITviecMô tả công việc, lương và ứng tuyển nằm ở ITviec.

10 câu hỏi có thể gặp khi phỏng vấn

Chọn theo kỹ năng và cấp của tin (JavaScript & TypeScript, C# & .NET). Gợi ý trả lời do Drama Công Ty biên soạn để bạn ôn nhanh, không phải đề của công ty.

  1. 01Phân biệt var, let và const. Hoisting và temporal dead zone là gì?JavaScript & TypeScript · Junior

    Gợi ý trả lời

    var có phạm vi hàm, còn let/const có phạm vi block ({}). const không cho gán lại biến, nhưng object hay array bên trong vẫn sửa được.

    • Hoisting: khai báo được "kéo" lên đầu phạm vi. var được khởi tạo sẵn là undefined, nên dùng trước khi khai báo không báo lỗi.
    • let/const cũng được hoist nhưng chưa khởi tạo. Truy cập trước dòng khai báo ném ReferenceError; khoảng đó gọi là temporal dead zone.
    • Function declaration được hoist cả phần thân, nên gọi được trước khi định nghĩa.
    console.log(a); // undefined
    console.log(b); // ReferenceError
    var a = 1;
    let b = 2;
    

    Người phỏng vấn muốn nghe: mặc định dùng const, cần gán lại mới dùng let, và gần như không dùng var trong code mới.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  2. 02== và === khác nhau thế nào? Những giá trị nào là falsy?JavaScript & TypeScript · Junior

    Gợi ý trả lời

    === so sánh cả kiểu lẫn giá trị. == ép kiểu trước khi so, nên cho ra kết quả khó đoán: "0" == 0 là true, [] == false cũng true.

    • Các giá trị falsy: false, 0, -0, 0n, "", null, undefined, NaN. Mọi thứ khác là truthy, kể cả [], {} và "0".
    • NaN === NaN là false; dùng Number.isNaN(x).
    • Ngoại lệ hay được chấp nhận: x == null để bắt cả null lẫn undefined.

    Hay sai: viết const page = input || 1. Khi người dùng nhập 0, giá trị bị thay bằng 1. Dùng nullish coalescing input ?? 1 để chỉ thay khi là null hoặc undefined.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  3. 03Closure là gì? Giải thích kết quả của vòng lặp for (var i...) với setTimeout.JavaScript & TypeScript · Junior

    Gợi ý trả lời

    Closure là khi một hàm "nhớ" được các biến ở phạm vi nơi nó được tạo ra, kể cả sau khi hàm bên ngoài đã chạy xong.

    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 0);
    }
    // In ra 3, 3, 3
    
    • var chỉ có một biến i cho cả vòng lặp. Khi callback chạy, vòng lặp đã xong và i bằng 3.
    • Đổi sang let thì mỗi vòng lặp có một i riêng, in ra 0, 1, 2.

    Ứng dụng thực tế: tạo biến private, hàm factory, debounce, memoize, và các hook trong React.

    Hay sai: closure giữ tham chiếu đến biến chứ không chụp lại giá trị. Closure giữ object lớn quá lâu (ví dụ trong listener không gỡ) cũng là nguồn rò rỉ bộ nhớ.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  4. 04async/await hoạt động thế nào? Vì sao không nên dùng .Result hay .Wait()?C# & .NET · Junior

    Gợi ý trả lời

    async/await giúp viết code bất đồng bộ như tuần tự: khi gặp await một tác vụ chưa xong, method trả quyền điều khiển, thread được giải phóng, phần còn lại chạy tiếp khi tác vụ hoàn thành. Trình biên dịch biến method thành một state machine.

    • Async giúp không chặn thread khi chờ I/O (DB, HTTP), nhờ vậy server phục vụ được nhiều request hơn; nó không tự làm code chạy nhanh hơn.
    • Việc nặng về CPU mới cần Task.Run.

    Gọi .Result hoặc .Wait() chặn thread đang chờ. Ở môi trường có SynchronizationContext (WinForms, WPF, ASP.NET cũ) dễ gây deadlock; ở ASP.NET Core gây cạn thread pool khi tải cao.

    Hay sai: dùng async void ngoài event handler, exception sẽ không bắt được. Hãy trả về Task và "async all the way".

    Ôn thêm câu hỏi C# & .NET →
  5. 05Interface và abstract class khác nhau thế nào? Khi nào dùng cái nào?C# & .NET · Junior

    Gợi ý trả lời

    Interface mô tả khả năng (hợp đồng) mà nhiều kiểu không liên quan có thể cùng thực hiện; abstract class là lớp cha dùng chung code và trạng thái cho một họ lớp gần nhau.

    • Một class implement nhiều interface nhưng chỉ kế thừa một class.
    • Abstract class có field, constructor, method có sẵn thân.
    • Từ C# 8 interface có default implementation, nhưng vẫn không có field trạng thái.

    Dùng interface cho các phụ thuộc cần thay thế hoặc mock trong test (IEmailSender, IOrderRepository). Dùng abstract class khi các lớp con thật sự chia sẻ logic, vd. BaseHandler xử lý log và retry chung.

    Người phỏng vấn muốn nghe: bạn ưu tiên composition và interface, chỉ dùng kế thừa khi có quan hệ "là một" rõ ràng.

    Ôn thêm câu hỏi C# & .NET →
  6. 06this trong JavaScript được xác định thế nào? Arrow function khác function thường ở điểm nào?JavaScript & TypeScript · Junior

    Gợi ý trả lời

    Với function thường, this phụ thuộc vào cách gọi, không phải nơi định nghĩa:

    • obj.method(): this là obj.
    • Gọi hàm trơn fn(): undefined trong strict mode (module và class luôn là strict).
    • new Fn(): object mới được tạo.
    • fn.call(x), fn.apply(x), fn.bind(x): this là x.

    Arrow function không có this riêng; nó lấy this của phạm vi bao ngoài. Arrow function cũng không có arguments và không dùng được với new.

    const btn = { label: "OK", click() { setTimeout(() => console.log(this.label)); } };
    

    Hay sai: truyền obj.method làm callback (setTimeout(obj.method)) rồi mất this. Cách sửa: bind, hoặc bọc trong arrow function.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  7. 07Event loop của JavaScript hoạt động thế nào? Đoạn code sau in ra theo thứ tự nào?JavaScript & TypeScript

    Gợi ý trả lời

    JavaScript chạy trên một thread. Code đồng bộ chạy hết trên call stack trước, sau đó event loop lấy việc từ hàng đợi. Microtask (Promise .then, await, queueMicrotask) luôn được chạy hết trước khi sang macrotask tiếp theo (setTimeout, sự kiện I/O, sự kiện người dùng).

    console.log(1);
    setTimeout(() => console.log(2));
    Promise.resolve().then(() => console.log(3));
    console.log(4);
    // 1, 4, 3, 2
    
    • Trên trình duyệt, việc render thường diễn ra giữa các macrotask.
    • Một vòng lặp đồng bộ dài, hoặc chuỗi microtask không dứt, sẽ làm treo giao diện.

    Người phỏng vấn muốn nghe: setTimeout(fn, 0) không chạy ngay mà chỉ được xếp hàng, và vì sao microtask được ưu tiên.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  8. 08So sánh Promise.all, Promise.allSettled, Promise.race và Promise.any. Xử lý lỗi với async/await thế nào?JavaScript & TypeScript

    Gợi ý trả lời

    Cả bốn đều chạy nhiều Promise song song, khác nhau ở cách kết thúc:

    • all: chờ tất cả thành công; một cái lỗi là reject ngay.
    • allSettled: chờ tất cả xong, trả về trạng thái từng cái; không bao giờ reject.
    • race: lấy kết quả (thành công hay lỗi) của cái xong đầu tiên; hay dùng để đặt timeout.
    • any: lấy cái thành công đầu tiên; chỉ reject khi tất cả đều lỗi.
    try {
      const [user, orders] = await Promise.all([getUser(id), getOrders(id)]);
    } catch (err) {
      showError(err);
    }
    

    Hay sai: await lần lượt trong vòng lặp các request không phụ thuộc nhau, khiến tổng thời gian cộng dồn. Ngược lại, gọi Promise.all với hàng nghìn request cùng lúc có thể làm quá tải server; khi đó cần giới hạn số request đồng thời.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  9. 09IEnumerable và IQueryable khác nhau thế nào khi dùng LINQ với Entity Framework?C# & .NET · Junior

    Gợi ý trả lời

    IQueryable giữ biểu thức truy vấn (expression tree) để provider như EF Core dịch thành SQL chạy trên DB. IEnumerable chạy LINQ trong bộ nhớ trên dữ liệu đã tải về.

    // Lọc trong SQL: chỉ tải đơn đã thanh toán
    var paid = db.Orders.Where(o => o.Status == Status.Paid).ToList();
    
    // Tải cả bảng rồi mới lọc trong RAM
    IEnumerable<Order> all = db.Orders;
    var paid2 = all.Where(o => o.Status == Status.Paid).ToList();
    
    • Cả hai đều deferred execution: chỉ chạy khi duyệt hoặc gọi ToList(), Count(), First()...
    • Duyệt cùng một IEnumerable lazy nhiều lần có thể chạy truy vấn nhiều lần.

    Hay sai: gọi ToList() hoặc AsEnumerable() quá sớm rồi mới lọc, phân trang, khiến tải cả bảng về.

    Ôn thêm câu hỏi C# & .NET →
  10. 10Kể về một thất bại hoặc sai lầm của bạn và bài học rút ra.Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Chọn sai lầm thật, có hậu quả vừa phải, nhận trách nhiệm rõ ràng, và nhấn mạnh việc bạn đã thay đổi sau đó.

    Cấu trúc: chuyện gì xảy ra, phần lỗi của bạn, bạn khắc phục ngay thế nào, bài học và thay đổi lâu dài.

    Câu mẫu: "Có lần em deploy một thay đổi cấu hình lên production vào chiều thứ Sáu mà không kiểm tra kỹ trên staging, làm một tính năng lỗi khoảng một giờ. Em báo ngay cho lead, rollback và viết báo cáo sự cố. Sau đó em đề xuất checklist trước deploy và quy ước hạn chế deploy cuối tuần; team áp dụng tới giờ."

    Hay sai: kể một "thất bại" thực ra là khoe, đổ lỗi cho người khác, hoặc nói mình chưa từng thất bại.

    Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →

Bạn đã phỏng vấn ở Scandinavian Software Park?

Kể lại các vòng và câu hỏi đã gặp (ẩn danh) để người sau ôn đúng trọng tâm.

Chia sẻ kinh nghiệm phỏng vấn