Gán thường obj.x = 1 tạo thuộc tính với cả ba cờ bật: writable, enumerable, configurable. Object.defineProperty cho phép đặt từng cờ, và mặc định của nó là tắt hết.
const o = {};
Object.defineProperty(o, 'id', { value: 7 });
o.id = 9; // im lặng bỏ qua (strict mode thì ném TypeError)
Object.keys(o); // [] → không enumerable
delete o.id; // false → không configurableNó cũng là cách định nghĩa accessor (getter/setter) một cách chương trình:
Object.defineProperty(o, 'full', {
get() { return this.first + ' ' + this.last; },
enumerable: true,
});Giới hạn: defineProperty chỉ chặn được thuộc tính đã biết trước. Thêm khoá mới, xoá khoá, hay thay đổi độ dài mảng đều không bắt được — đó chính là lý do Vue 2 phải có Vue.set và không theo dõi được arr[0] = x.
Proxy chặn ở tầng thao tác (get, set, has, deleteProperty, ownKeys...) nên bắt được cả khoá chưa tồn tại và thao tác xoá, không cần duyệt trước từng thuộc tính. Đây là lý do Vue 3 chuyển sang Proxy. Đánh đổi: Proxy không polyfill được cho môi trường cũ và mỗi thao tác qua trap có chi phí.