Getter/Setter - Theo dõi thay đổi property
Sử dụng get và set trong Object.defineProperty hoặc class để intercept việc đọc/ghi property, từ đó thực hiện logic phụ (validation, sync, logging...).
Ví dụ từ bài gốc (Class với getter)
class Student {
constructor(studentMarks1, studentMarks2) {
this._studentMarks1 = studentMarks1;
this._studentMarks2 = studentMarks2;
// Getter object - cách cũ trong bài
this.getValues = {
get studentMarks1() {
return this._studentMarks1; // LỖI: this ở đây là getValues, không phải Student instance
},
get studentMarks2() {
return this._studentMarks2;
}
};
}
}
// Sửa lỗi: dùng closure hoặc bind
class StudentFixed {
constructor(m1, m2) {
this._marks1 = m1;
this._marks2 = m2;
const self = this; // Closure
this.getValues = {
get studentMarks1() { return self._marks1; },
get studentMarks2() { return self._marks2; }
};
}
}
Cách chuẩn: Getter/Setter trên Class (ES6)
class Student {
constructor(marks1, marks2) {
this._marks1 = marks1;
this._marks2 = marks2;
}
// Getter - đọc property
get marks1() {
console.log('Đang đọc marks1');
return this._marks1;
}
set marks1(value) {
console.log('Đang ghi marks1:', value);
if (value < 0 || value > 100) {
throw new Error('Điểm phải 0-100');
}
this._marks1 = value;
}
get marks2() { return this._marks2; }
set marks2(value) {
if (value < 0 || value > 100) throw new Error('Điểm phải 0-100');
this._marks2 = value;
}
// Computed property
get average() {
return (this._marks1 + this._marks2) / 2;
}
}
const student = new Student(78, 79);
console.log(student.marks1); // 78 (gọi getter)
student.marks2 = 89; // Gọi setter
console.log(student.average); // 83.5 (getter computed)
Object.defineProperty() - Cấp thấp hơn
const obj = { _value: 0 };
Object.defineProperty(obj, 'value', {
get() {
console.log('GET');
return this._value;
},
set(v) {
console.log('SET:', v);
this._value = v;
},
enumerable: true,
configurable: true
});
obj.value = 10; // SET: 10
console.log(obj.value); // GET → 10
Proxy (ES6) - Theo dõi toàn bộ object
const target = { name: 'John', age: 30 };
const handler = {
get(target, prop, receiver) {
console.log(`Đọc property: ${prop}`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`Ghi property: ${prop} = ${value}`);
return Reflect.set(target, prop, value, receiver);
},
deleteProperty(target, prop) {
console.log(`Xóa property: ${prop}`);
return Reflect.deleteProperty(target, prop);
}
};
const proxy = new Proxy(target, handler);
proxy.name = 'Jane'; // Ghi property: name = Jane
console.log(proxy.name); // Đọc property: name → Jane
Ứng dụng thực tế: Reactive System (Vue.js style)
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key); // Dependency tracking
return target[key];
},
set(target, key, value) {
const oldValue = target[key];
target[key] = value;
if (oldValue !== value) {
trigger(target, key); // Notify subscribers
}
return true;
}
});
}
const state = reactive({ count: 0 });
state.count++; // Trigger update UI
So sánh
| Cách | Phạm vi | Phức tạp | Dùng cho |
|---|---|---|---|
| Class getter/setter | 1 property | Thấp | Validation, computed props |
| Object.defineProperty | 1 property | Trung bình | Library, framework internals |
| Proxy | Toàn bộ object | Cao | Reactive systems, validation toàn diện |