Câu hỏi phỏng vấn lập trình JavaScript


🔰 PHẦN 1: CƠ BẢN

  • Lời giải:
    JavaScript là một ngôn ngữ lập trình phổ biến dùng để xây dựng các chức năng tương tác trên website. Ban đầu, JavaScript chỉ chạy trên trình duyệt (frontend), nhưng hiện nay có thể chạy trên server (backend) thông qua Node.js. Nó giúp xử lý sự kiện, thao tác DOM và gọi API.
  • Code demo:
document.querySelector("button").onclick = () => {
alert("Hello JS");
};

  • Lời giải:
    Ba cách khai báo biến này khác nhau ở phạm vi hoạt động (scope) và khả năng thay đổi giá trị:
  • var: có phạm vi trong function, có thể bị truy cập ngoài block {} và dễ gây lỗi
  • let: có phạm vi trong block {}, an toàn hơn
  • const: giống let nhưng không thể gán lại giá trị sau khi đã khai báo
    👉 Nên dùng const mặc định, chỉ dùng let khi cần thay đổi giá trị
  • Code demo:
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1
console.log(b); // lỗi

  • Lời giải:
    Hoisting là cơ chế mà JavaScript tự động đưa phần khai báo biến và function lên đầu phạm vi (scope) trước khi thực thi code. Tuy nhiên, chỉ phần khai báo được đưa lên, còn giá trị thì không.
  • Code demo:
console.log(a); // undefined
var a = 5;

  • Lời giải:
    Scope là phạm vi mà một biến có thể được truy cập. Có 3 loại chính:
  • Global scope: dùng được mọi nơi
  • Function scope: chỉ dùng trong function
  • Block scope: chỉ dùng trong {} (áp dụng cho let, const)
  • Code demo:
let a = 1;

function test() {
let b = 2;
}

  • Lời giải:
    Closure là khi một function có thể truy cập và ghi nhớ các biến ở scope bên ngoài của nó, ngay cả khi function bên ngoài đã kết thúc. Đây là cơ chế giúp tạo biến “private” trong JavaScript.
  • Code demo:
function counter() {
let count = 0;
return function () {
count++;
return count;
};
}

const c = counter();
console.log(c()); // 1
console.log(c()); // 2

  • Lời giải:
  • ==: so sánh giá trị nhưng có ép kiểu dữ liệu (có thể gây lỗi logic)
  • ===: so sánh cả giá trị và kiểu dữ liệu (an toàn hơn)
    👉 Trong thực tế nên luôn dùng ===
  • Code demo:
console.log(1 == "1"); // true
console.log(1 === "1"); // false

  • Lời giải:
  • undefined: biến đã khai báo nhưng chưa gán giá trị
  • null: giá trị rỗng do lập trình viên chủ động gán
    👉 Hiểu đơn giản: undefined là “chưa có”, null là “có nhưng rỗng”
  • Code demo:
let a;
let b = null;

  • Lời giải:
    JavaScript có 2 nhóm kiểu dữ liệu:
  • Primitive: string, number, boolean, null, undefined, symbol, bigint
  • Reference: object, array, function
    👉 Primitive lưu trực tiếp giá trị, object lưu theo tham chiếu
  • Code demo:
typeof "hello"; // string
typeof 123; // number
typeof {}; // object

  • Lời giải:
  • Primitive: khi gán sẽ copy giá trị
  • Reference: khi gán sẽ copy địa chỉ trong bộ nhớ
    👉 Vì vậy thay đổi object sẽ ảnh hưởng biến gốc
  • Code demo:
let a = 1;
let b = a;
b = 2;
console.log(a); // 1

let obj1 = { x: 1 };
let obj2 = obj1;
obj2.x = 2;
console.log(obj1.x); // 2

  • Lời giải:
  • Function declaration: được hoisting (có thể gọi trước khi khai báo)
  • Function expression: không được hoisting
    👉 Function expression thường dùng trong thực tế nhiều hơn
  • Code demo:
// declaration
function a() {}

// expression
const b = function () {};

  • Lời giải:
    Arrow function là cách viết ngắn gọn của function trong ES6. Nó giúp code gọn hơn và không có this riêng, mà dùng this từ bên ngoài.
  • Code demo:
const add = (a, b) => a + b;

  • Lời giải:
    this là từ khóa đại diện cho đối tượng đang gọi function. Giá trị của this phụ thuộc vào cách function được gọi, không phải nơi nó được khai báo.
  • Code demo:
const obj = {
name: "JS",
show() {
console.log(this.name);
}
};
obj.show(); // JS

  • Lời giải:
    Event là các hành động xảy ra trên trang web như click, scroll, nhập dữ liệu… JavaScript dùng event để xử lý tương tác của người dùng.
  • Code demo:
button.addEventListener("click", () => {
console.log("Clicked");
});

  • Lời giải:
    Callback là một function được truyền vào function khác như một tham số, và sẽ được gọi lại sau khi một công việc hoàn thành (thường dùng trong async).
  • Code demo:
function run(callback) {
callback();
}

run(() => console.log("Hello"));

  • Lời giải:
    NaN (Not a Number) là giá trị đại diện cho kết quả không hợp lệ trong các phép toán số học.
  • Code demo:
console.log("abc" * 2); // NaN

⚙️ PHẦN 2: TRUNG CẤP

  • Lời giải:
    Promise là một đối tượng dùng để xử lý các tác vụ bất đồng bộ (async) trong JavaScript. Nó giúp bạn xử lý kết quả của một công việc trong tương lai (ví dụ: gọi API).
    Promise có 3 trạng thái:
  • pending: đang chờ xử lý
  • fulfilled: xử lý thành công
  • rejected: xử lý thất bại

👉 Promise giúp code dễ đọc hơn so với callback (tránh callback hell)

  • Code demo:
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Success"), 1000);
});

promise.then(res => console.log(res));

  • Lời giải:
    Async/Await là cú pháp giúp viết code bất đồng bộ theo kiểu đồng bộ, dễ đọc và dễ hiểu hơn Promise.
  • async: khai báo function bất đồng bộ
  • await: chờ Promise hoàn thành trước khi chạy tiếp

👉 Giúp code nhìn “thẳng” hơn, dễ debug hơn

  • Code demo:
async function run() {
const result = await Promise.resolve(10);
console.log(result);
}
run();

  • Lời giải:
    Event Loop là cơ chế giúp JavaScript xử lý các tác vụ bất đồng bộ dù chỉ chạy trên một luồng (single-thread).

Cách hoạt động:

  1. Code chạy trong Call Stack
  2. Task async (setTimeout, Promise...) được đưa ra ngoài
  3. Khi xong → đưa vào Queue
  4. Event Loop sẽ đưa task từ Queue vào lại Stack khi rảnh

👉 Giúp JS không bị block khi xử lý async

  • Code demo:
console.log("1");

setTimeout(() => console.log("2"), 0);

Promise.resolve().then(() => console.log("3"));

console.log("4");

// Kết quả: 1 4 3 2

  • Lời giải:
    Call Stack là nơi JavaScript lưu trữ các function đang được thực thi. Nó hoạt động theo nguyên tắc LIFO (Last In First Out).
    👉 Function nào gọi sau sẽ chạy trước
  • Code demo:
function a() {
b();
}

function b() {
console.log("Run");
}

a();

  • Lời giải:
    JavaScript có 2 loại hàng đợi:
  • Microtask: Promise, queueMicrotask → ưu tiên cao
  • Macrotask: setTimeout, setInterval → ưu tiên thấp hơn

👉 Event Loop luôn chạy Microtask trước

  • Code demo:
setTimeout(() => console.log("macro"), 0);

Promise.resolve().then(() => console.log("micro"));

// Output: micro → macro

  • Lời giải:
    setTimeout không chạy ngay lập tức sau thời gian delay, mà nó đưa callback vào hàng đợi. Callback chỉ được chạy khi Call Stack rảnh.
    👉 Vì vậy delay = 0 không có nghĩa là chạy ngay
  • Code demo:
setTimeout(() => console.log("run"), 0);
console.log("end");

// Output: end → run

  • Lời giải:
  • Shallow copy: chỉ copy cấp 1, object bên trong vẫn dùng chung reference
  • Deep copy: copy toàn bộ, không bị ảnh hưởng lẫn nhau

👉 Dùng deep copy khi làm việc với object lồng nhau

  • Code demo:
const obj = { a: { b: 1 } };

const shallow = { ...obj };
const deep = JSON.parse(JSON.stringify(obj));

  • Lời giải:
    Cả hai đều dùng để copy hoặc merge object:
  • Object.assign(): method truyền thống
  • ...spread: cú pháp mới, dễ đọc hơn

👉 Trong thực tế, nên dùng spread

  • Code demo:
const a = { x: 1 };
const b = { y: 2 };

const c = Object.assign({}, a, b);
const d = { ...a, ...b };

  • Lời giải:
  • map(): biến đổi từng phần tử
  • filter(): lọc phần tử theo điều kiện
  • reduce(): gom dữ liệu thành 1 giá trị

👉 Đây là 3 method rất quan trọng trong xử lý mảng

  • Code demo:
const arr = [1, 2, 3];

arr.map(x => x * 2); // [2,4,6]
arr.filter(x => x > 1); // [2,3]
arr.reduce((s, x) => s+x, 0); // 6

  • Lời giải:
    Prototype là cơ chế giúp các object trong JavaScript kế thừa thuộc tính và phương thức từ object khác.
    👉 Đây là nền tảng của OOP trong JS
  • Code demo:
function Person(name) {
this.name = name;
}

Person.prototype.say = function() {
console.log(this.name);
};

  • Lời giải:
    Prototype chain là chuỗi liên kết các object với nhau thông qua prototype. Khi truy cập thuộc tính, JS sẽ tìm từ object hiện tại → lên prototype → cho đến Object gốc.
    👉 Đây là cơ chế tìm kiếm thuộc tính trong JS
  • Code demo:
const obj = {};
console.log(obj.toString()); // từ Object.prototype

  • Lời giải:
    Cả 3 đều dùng để thay đổi this:
  • call: gọi function ngay, truyền tham số từng cái
  • apply: giống call nhưng truyền mảng
  • bind: trả về function mới, chưa gọi

👉 bind thường dùng trong React hoặc event

  • Code demo:
function greet(name) {
console.log(this.title + name);
}

greet.call({ title: "Mr " }, "A");
greet.apply({ title: "Mr " }, ["B"]);

const fn = greet.bind({ title: "Mr " });
fn("C");

  • Lời giải:
  • Function thường: this phụ thuộc cách gọi
  • Arrow function: không có this riêng, nó dùng this từ scope bên ngoài

👉 Đây là điểm dễ gây bug

  • Code demo:
const obj = {
name: "JS",
show: () => console.log(this.name)
};

obj.show(); // undefined

  • Lời giải:
    Module giúp chia code thành nhiều file nhỏ, dễ quản lý và tái sử dụng.
    👉 Dùng exportimport
  • Code demo:
// a.js
export const a = 1;

// b.js
import { a } from "./a.js";

  • Lời giải:
    ES6 (ECMAScript 2015) mang lại nhiều cải tiến:
  • let, const
  • arrow function
  • destructuring
  • spread operator
  • class, module

👉 Giúp code hiện đại và dễ đọc hơn

  • Code demo:
const { a } = { a: 1 };
const arr = [...[1,2,3]];

🚀 PHẦN 3

  • Lời giải:
    Debounce là kỹ thuật chỉ thực thi function sau khi người dùng ngừng thao tác trong một khoảng thời gian.
    👉 Dùng cho search input, resize
  • Code demo:
function debounce(fn, delay) {
let timer;
return () => {
clearTimeout(timer);
timer = setTimeout(fn, delay);
};
}

  • Lời giải:
    Currying là kỹ thuật biến một function nhiều tham số thành chuỗi function mỗi function nhận một tham số.
  • Code demo:
const add = a => b => a + b;
add(2)(3);

  • Lời giải:
    Memoization là kỹ thuật lưu cache kết quả của function để tránh tính toán lại.
  • Code demo:
const cache = {};
function memo(n) {
if (cache[n]) return cache[n];
return cache[n] = n * 2;
}

  • Lời giải:
    Generator là function có thể tạm dừng và tiếp tục thực thi bằng từ khóa yield.
  • Code demo:
function* gen() {
yield 1;
yield 2;
}
  • Lời giải:
  • Map: key có thể là bất kỳ kiểu dữ liệu nào
  • WeakMap: key phải là object và sẽ tự động bị xóa khi object không còn tham chiếu

👉 WeakMap giúp tránh memory leak

  • Code demo:
let wm = new WeakMap();
let obj = {};

wm.set(obj, "data");
obj = null; // GC có thể dọn

  • Lời giải:
  • Set: lưu các giá trị duy nhất
  • WeakSet: chỉ lưu object và không ngăn GC

👉 WeakSet thường dùng để tracking object

  • Code demo:
let set = new Set([1, 2, 2]);
console.log(set); // {1,2}

  • Lời giải:
    Symbol là kiểu dữ liệu dùng để tạo ra các giá trị duy nhất, thường dùng làm key trong object để tránh trùng lặp.
  • Code demo:
const id1 = Symbol("id");
const id2 = Symbol("id");

console.log(id1 === id2); // false

  • Lời giải:
    Proxy cho phép bạn “chặn” và kiểm soát các thao tác trên object như get, set, delete...

👉 Dùng để validate, log hoặc bảo mật

  • Code demo:
const obj = new Proxy({}, {
get(target, prop) {
return prop in target ? target[prop] : 0;
}
});

console.log(obj.a); // 0

  • Lời giải:
    Reflect là một API cung cấp các phương thức để thao tác với object một cách rõ ràng và chuẩn hơn so với cách truyền thống.

👉 Thường dùng cùng Proxy

  • Code demo:
const obj = { a: 1 };
console.log(Reflect.get(obj, "a")); // 1

  • Lời giải:
    Tree shaking là kỹ thuật loại bỏ những đoạn code không được sử dụng khi build project, giúp giảm dung lượng file và tăng hiệu năng.

👉 Thường dùng trong Webpack, Vite

  • Code demo:
// import nhưng không dùng → sẽ bị loại bỏ khi build
import { unused } from "./lib";

  • Lời giải:
    Lazy loading là kỹ thuật chỉ tải tài nguyên khi cần thiết, thay vì tải toàn bộ ngay từ đầu.

👉 Giúp giảm thời gian load ban đầu

  • Code demo:
import("./module.js").then(module => {
module.run();
});

  • Lời giải:
    Garbage Collection là cơ chế tự động dọn dẹp bộ nhớ của JavaScript. Nó sẽ giải phóng những object không còn được tham chiếu đến.

👉 Tránh memory leak

  • Code demo:
let obj = { a: 1 };
obj = null; // GC sẽ dọn

  • Lời giải:
    JavaScript chỉ có một luồng thực thi, nghĩa là tại một thời điểm chỉ xử lý một tác vụ.

👉 Async (Event Loop) giúp JS không bị block

  • Code demo:
while (true) {
// block toàn bộ chương trình
}

  • Lời giải:
    Web Worker cho phép chạy JavaScript trên một luồng riêng biệt, không ảnh hưởng đến UI chính.

👉 Dùng cho task nặng (xử lý dữ liệu lớn)

  • Code demo:
const worker = new Worker("worker.js");
worker.postMessage("start");

💼 PHẦN 4: THỰC CHIẾN


  • Lời giải:
    Một số cách phổ biến:
  • Sử dụng debounce/throttle
  • Lazy loading
  • Giảm thao tác DOM
  • Sử dụng caching

👉 Tùy bài toán để chọn cách phù hợp

  • Code demo:
window.addEventListener("scroll", debounce(() => {
console.log("scroll");
}, 200));

  • Lời giải:
  • Sử dụng console.log
  • Dùng debugger
  • Dùng Chrome DevTools để đặt breakpoint

👉 Debug là kỹ năng quan trọng khi đi làm

  • Code demo:
function test() {
debugger;
let a = 1;
}

  • Lời giải:
    Memory leak xảy ra khi bộ nhớ không được giải phóng dù không còn sử dụng.

👉 Nguyên nhân:

  • Không clear event listener
  • Không clear timer

👉 Cách xử lý:

  • cleanup khi component unmount
  • Code demo:
const id = setInterval(() => {}, 1000);
clearInterval(id);

  • Lời giải:
  • Chia module (MVC hoặc Clean Architecture)
  • Tách logic và UI
  • Dùng folder rõ ràng

👉 Giúp maintain dễ hơn

  • Code demo:
// service.js
export const getUser = () => {};

// controller.js
import { getUser } from "./service";

  • Lời giải:
    Race condition xảy ra khi nhiều tác vụ async chạy cùng lúc và kết quả trả về không đúng thứ tự.

👉 Cách xử lý:

  • Hủy request cũ
  • Dùng flag hoặc AbortController
  • Code demo:
let current = 0;

async function fetchData() {
const id = ++current;
const res = await fetch("api");
if (id !== current) return; // bỏ kết quả cũ
}
Phản hồi từ học viên

5

Tổng 0 đánh giá
Developer Toolbox

TEXT CASE

FORMAT & CLEAN

ENCODE & DECODE

JSON & CRYPTO

Đã sao chép!!!
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.
Hotline: 0967025996
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.