Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Kiểm tra giá trị object bị thay đổi và cập nhật giá trị khác dựa trên đó trong JavaScript

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/setter1 propertyThấpValidation, computed props
Object.defineProperty1 propertyTrung bìnhLibrary, framework internals
ProxyToàn bộ objectCaoReactive systems, validation toàn diện