Một hàm nhận options dùng cú pháp {limit = 20} = {}. Bạn có thể gọi hàm không truyền argument, nhưng truyền null lại gây lỗi. Nếu truyền {limit: null}, hàm không lỗi lúc destructure nhưng limit vẫn là null. Hai dấu bằng trong chữ ký đang xử lý hai vị trí khác nhau.
Bài đối chiếu MDN ngày 05/11/2026 và chạy các đoạn JavaScript trên Node.js 24.18.1. Ví dụ dùng object dữ liệu đơn giản, không có getter, Proxy hoặc code React. Mục tiêu là giải thích lúc nào default được chọn, không xây một validator đầy đủ cho options từ bên ngoài.
Bắt đầu bằng default của một thuộc tính
Trong object destructuring, initializer chỉ được dùng khi giá trị đọc được là undefined, bao gồm trường hợp không có thuộc tính. null là một giá trị riêng nên không kích hoạt default. Các giá trị 0, false và chuỗi rỗng cũng được giữ nguyên.
Đọc từng trường hợp dưới đây trước khi chạy file .cjs. Assertions giúp bạn kiểm tra quy tắc mà không phải đoán từ cách console trình bày object:
const assert = require('node:assert/strict');
function readLimit(options) {
const {limit = 20} = options;
return limit;
}
assert.equal(readLimit({}), 20);
assert.equal(readLimit({limit: undefined}), 20);
assert.equal(readLimit({limit: null}), null);
assert.equal(readLimit({limit: 0}), 0);
assert.equal(readLimit({limit: false}), false);
assert.equal(readLimit({limit: ''}), '');
let defaultsUsed = 0;
function fallback() {
defaultsUsed += 1;
return 20;
}
const {limit: first = fallback()} = {limit: 0};
const {limit: second = fallback()} = {};
assert.equal(first, 0);
assert.equal(second, 20);
assert.equal(defaultsUsed, 1);
console.log('property defaults verified');
Biểu thức fallback được đánh giá khi cần, không phải ở mọi lần destructure. Trong cú pháp limit: first, limit là tên thuộc tính được đọc còn first là tên biến được khai báo. Việc đổi tên biến không đổi nội dung của object nguồn.
Một kết quả false hoặc chuỗi rỗng ở readLimit không có nghĩa là giới hạn phân trang hợp lệ. Đó chỉ là bằng chứng initializer không phải phép kiểm tra kiểu dữ liệu. Validation phải được đặt rõ ràng nếu limit cần là số nguyên trong một khoảng.
Default của cả tham số là một lớp khác
Chạy ví dụ độc lập tiếp theo. Dấu = {} ngoài cùng cung cấp object khi argument là undefined hoặc bị bỏ qua; default bên trong mới cung cấp giá trị limit:
const assert = require('node:assert/strict');
function listOptions({limit = 20} = {}) {
return limit;
}
assert.equal(listOptions(), 20);
assert.equal(listOptions(undefined), 20);
assert.equal(listOptions({}), 20);
assert.equal(listOptions({limit: null}), null);
assert.throws(() => listOptions(null), TypeError);
function readTheme({ui: {theme = 'light'} = {}} = {}) {
return theme;
}
assert.equal(readTheme(), 'light');
assert.equal(readTheme({ui: undefined}), 'light');
assert.equal(readTheme({ui: {theme: null}}), null);
assert.throws(() => readTheme({ui: null}), TypeError);
console.log('parameter and nested defaults verified');
Khi argument là null, default của cả tham số không được chọn. Hàm cố destructure null nên ném TypeError. Trong readTheme, ui có default riêng nhưng ui bằng null vẫn không được thay bằng object rỗng; thao tác lấy theme từ null gây lỗi tương tự.
Trả lời câu hỏi phỏng vấn theo từng bước
Trước hết xác định giá trị argument thực tế: bị bỏ qua, undefined, null hay object. Tiếp theo áp dụng default của cả tham số nếu có. Sau đó mới đọc từng thuộc tính và xét initializer tại cấp đó. Với object lồng nhau, lặp lại quá trình cho từng cấp, không coi dấu bằng ngoài cùng là bảo vệ toàn bộ cây dữ liệu.
Nếu nghiệp vụ muốn null cũng mang nghĩa “không có cấu hình”, hãy chuẩn hóa null ở biên hoặc dùng toán tử phù hợp tại đúng chỗ. Đồng thời quyết định có chấp nhận số, mảng hoặc object lạ làm options hay không. Tự chuyển mọi đầu vào lỗi thành object rỗng có thể che dữ liệu không đúng hợp đồng.
Các ca kiểm tra nên giữ lại
Với options, kiểm tra ít nhất lời gọi không argument, undefined, null, object rỗng và object có thuộc tính null. Với thuộc tính số, thêm 0 cùng một giá trị sai kiểu để chứng minh default và validation là hai bước riêng. Với fallback có side effect, kiểm tra số lần gọi nếu điều đó ảnh hưởng chương trình.
Không dùng default destructuring để khẳng định payload đã có schema hợp lệ. Cú pháp này giúp viết cách lấy giá trị ngắn hơn; tính đúng của dữ liệu vẫn đến từ hợp đồng và bước kiểm tra tương ứng. Khi giải thích được cả argument lẫn từng thuộc tính, bạn sẽ đọc các chữ ký options lồng nhau rõ ràng hơn.

