如何检测对象变量是否已更改?

时间:2014-07-14 20:30:18

标签: javascript

我有一个代表栅栏的类,它内部由矩形和圆形标记对象(也是我的类)组成。围栏有4个变量 - x1,x2,y1和y2。如果有任何这些更改,我必须修改或重建内部标记对象。

存储和检查4个值并不是什么大问题,但这只是我的第一个世界对象类,并且会有更长的变量列表。 有没有什么好方法可以检查是否有任何更改或触发更改的内容而不显式存储双值并在每次重绘画布时进行检查?有点像vb.net中的属性吗?

4 个答案:

答案 0 :(得分:4)

var fence= {
   set x1(){
      alert('change');
      this.rebuild();
   },
   rebuild: function(){}
}

另外

function Fence(val){
    var value = val;

    this.__defineGetter__("x1", function(){
        return value;
    });

    this.__defineSetter__("x1", function(val){
        alert('change');
        this.rebuild();
    });
    this.rebuild = function(){};
}
var fence = new Fence();

答案 1 :(得分:1)

使用下面代码中发布的对象,您可以非常轻松地实现它:

function Fence() {
    // constructor
}

Fence.prototype.refresh = function() {
    // change the refresh code here
    console.log(this.x1 + "," + this.y1 + "," + this.x2 + "," + this.y2);
};

// must be called after the prototype.refresh function is defined
RefreshExtender.addRefreshProperties(Fence, [
        new RefreshExtender.Property("x1", 0), // propertyName, defaultValue[, refreshFunction]
        new RefreshExtender.Property("y1", 0, function() { console.log('Refresh only y1 property.'); }),
        new RefreshExtender.Property("x2", 0),
        new RefreshExtender.Property("y2", 0)
    ]);

然后使用它时:

var fence = new Fence();
fence.x1 = 20;
// Outputs: "20,0,0,0"

现在,如果您一次更改多个属性,它将仅在设置了所有属性后调用刷新函数。例如:

fence.x1 = 10; 
fence.x2 = 20;
// Outputs: "10,0,20,0 (Outputs only ONCE)"

如果我们更新y1属性,它将执行创建属性时传入的函数:

fence.y1 = 30;
// Outputs: "Refresh only y1 property."

刷新扩展器:

var RefreshExtender = {
    addRefreshProperties: function(baseType, properties) {
        function defineProperty(property) {
            Object.defineProperty(baseType.prototype, property.name, {
                get: function() {
                    var val = this["_" + property.name];
                    if (typeof val === "undefined") {
                        return property.defaultValue;
                    }
                    return val;
                },
                set: function(val) {
                    var shouldRefresh = this["_" + property.name] !== val;
                    this["_" + property.name] = val;
                    if (shouldRefresh) {
                        if (typeof property.refreshFunction === "function") {
                            property.refreshFunction();
                        }
                        else {
                            this.refresh();
                        }
                    }
                },
                enumerable: true,
                configurable: true
            });
        }

        for (var i = 0, l = properties.length; i < l; i++) {
            defineProperty(properties[i]);
        }

        var oldRefreshFunction = baseType.prototype.refresh;

        baseType.prototype.refresh = RefreshExtender._executeOnce(oldRefreshFunction);
    },
    Property : function(name, defaultValue, refreshFunction) {
        this.name            = name;
        this.defaultValue    = defaultValue;
        if (typeof refreshFunction === "function") {
            this.refreshFunction = RefreshExtender._executeOnce(refreshFunction);
        }
    },
    _executeOnce : function(originalFunc) {
        var isRefreshing = false,
            func = function() {
                var _this = this;
                if (!isRefreshing) {
                    isRefreshing = true;
                    setTimeout(function() {
                        isRefreshing = false;
                        originalFunc.call(_this);
                    }, 0);
                }
            };

        return func;
    }
};

答案 2 :(得分:0)

您可以创建一个可以访问setter和getter方法的闭包,但不能直接访问这些属性。类似的东西:

var fence = function() {
    var x1, x2, y1, y2; 
    var setX1 = function(x) {
            if (typeof x == 'undefined') return x1;
            if (x != x1) alert('It Changed');
            x1 = x; 
    };
    var setX2 = function(x) {
            if (typeof x == 'undefined') return x2;
            if (x != x2) alert('It Changed');
            x2 = x; 
    };
    var setY1 = function(y) {
            if (typeof x == 'undefined') return y1;
            if (y != y1) alert('It Changed');
            y1 = y; 
    };
    var setY2 = function(y) { 
            if (typeof y == 'undefined') return y1;
            if (y != y2) alert('It Changed');
            y2 = y; 
    };
    return { x1: setX1, 
             x2: setX2, 
             y1: setY1, 
             y2: setY2 
           }
}()

fence.x1(1); //alerts "It changed"
fence.x1(1); //no alert

答案 3 :(得分:0)

一种好的方法可能是为围栏定义原型而不是使用常规对象。对于原型,您可以创建setter方法而不是直接设置属性,并让setter方法处理对变量的跟踪更改。

原型看起来像这样:

function fence(x1, x2, x3, x4){
  this.x1 = x1;
  ....

  this.changedVars = {};
}

fence.Prototype.setX1 = function(newVal){
 this.x1 = newVal;
 this.changedVars.x1 = true;
};

这将在内部收集所有已更改的变量。当您运行方法(例如,'rebuildFence')时,您将删除从this.changedVariables更新的密钥。在原型上保留所有setter方法(以及getter方法,如果你是如此倾向),也会减少内存开销,因为每次构建fence时你都不会重新定义函数。