使用getter / setter获取动态对象属性

时间:2015-07-26 10:03:21

标签: javascript oop getter-setter

我有一个名为status的对象,我想跟踪一个班级的任何状态 除了设置各种状态,我还想跟踪这些状态的活动时间。现在,不是为每个状态定义第二个属性来跟踪时间,而是为getter / setter的工作。

那就是我被困住的地方。如何使它们动态化,以便触发status的每个属性?

var Person = function(options) {
  this.name = options.name;

  var _statusChanged = {};
  var _status = {};

  // How to make this dynamic?
  var expr = "isOnfire";
  this.status = {
    get [expr]() {
      console.log(_statusChanged);
      return _status[expr];
    },
    set [expr](val) {
      _status[expr] = val;
      _statusChanged[expr] = new Date();
      return _status[expr];
    }
  };
};

var John = new Person({
  name: "John"
});

John.status.isOnfire = true;
John.status.hasPinkShirt = true;

console.log(John, John.status.isOnfire, John.status.hasPinkShirt);

3 个答案:

答案 0 :(得分:1)

如果您有这些列表,只需在循环中创建getters / setter,例如:

this.status = {};
["isOnFire", "hasPinkShirt"].forEach((name) => {
  Object.defineProperty(status, name {
    get() {
      console.log(_statusChanged);
      return _status[name];
    },
    set(val) {
      _status[name] = val;
      _statusChanged[name] = new Date();
      return _status[name];
    }
  });
});

如果他们可以任何,那么您将需要使用Proxy object。使用代理,您可以在不事先知道属性名称的情况下捕获所有获取/设置:

this.status = new Proxy(_status, {
    get(target, propKey, receiver) {
        // handle get
        return _status[propKey];
    },
    set(target, propKey, value, receiver) {
        // handle set
        _status[propKey] = value;
        _statusChanged[propKey] = new Date();
        return true; // Tells the proxy the assignment worked
    }
});

(或者您可能会使用Reflect.getReflect.set,但即使Firefox还没有它们。)

Here's an article更详细地进入代理。

这是一个示例,但您需要在最新版本的Firefox中运行它,因为support or Proxy in the wild在地面上仍然非常薄,而且就其性质而言,您无法填充/填充代理。< / p>

(function() {
  "use strict";

  var _status = {};
  var _statusChanged = {};
  var status = new Proxy(_status, {
    get(target, propKey, receiver) {
      snippet.log(propKey + " requested");
      return _status[propKey];
    },
    set(target, propKey, value, receiver) {
      snippet.log(propKey + " set to " + value);
      _status[propKey] = value;
      _statusChanged[propKey] = new Date();
      return true; // Tells the proxy the assignment worked
    }
  });
  
  status.foo = "bar";
  snippet.log("foo = " + status.foo);

})();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

在您可以使用它们之前,您需要将状态设置为方法调用,而不是分配。

答案 1 :(得分:0)

您需要一个名为ECMAScript 6 Proxy的对象。在Firefox中,它们默认处于启用状态。有一次,他们是在“experimental JavaScript”下的Chrome中实现的,但它们似乎暂时被删除了;见this ES6 compatibility table

此代码适用于Firefox:

var output = function(text) {
      var line = document.createElement('div');
      line.innerHTML = text;
      document.getElementById('output').appendChild(line);
  }

var Person = function(options) {
  this.name = options.name;

  var _status = {};
  var _statusChanged = {};
  
  this.status = new Proxy(_status,{
    get: function(target,property) {
      return target[property];
    },
    set: function(target,property,value) {
      _statusChanged[property] = new Date();
      output("set " + property + " to " + value + " at " + _statusChanged[property]);
      _status[property] = value;
    }
  });
  
  this.show = function(property) {
    output("Property " + property + " is " + _status[property] + " since " + _statusChanged[property]);
  }
};

var John = new Person({
  name: "John"
});

John.status.isOnfire = true;
John.status.hasPinkShirt = true;

John.show("isOnfire");
John.show("hasPinkShirt");
<div id="output"></div>

答案 2 :(得分:0)

也许这对你有用

http://jsfiddle.net/oksbLyqf/16/

var Person = function (options) {
    this.name = options.name;

    var _statusChanged = {};
    var _status = {};

    var expr = '';

    var addStatusProperty = function (prop) {
        expr = prop;

        Object.defineProperty(otherStatus, expr, {
            get: function () {
                console.log(_statusChanged);
                return _status[expr];
            },
            set: function (val) {
                _status[expr] = val;
                _statusChanged[expr] = new Date();
                return _status[expr];
            }
        });
    };

    var setStatusProperty = function (prop, val) {
        expr = prop;

        if (_status[expr]) {
            otherStatus[expr] = val;
            return _status[expr];
        } else {
            addStatusProperty(expr);
            otherStatus[expr] = val;
            return _status[expr];
        }
    };

    var getStatusProperty = function (prop) {
        expr = prop;

        return _status[expr]
    };

    this.status = {
        addProperty: addStatusProperty,
        setProperty: setStatusProperty,
        getProperty: getStatusProperty
    };

    var otherStatus = this.status;
};

var John = new Person({
    name: "John"
});

John.status.setProperty('isOnfire', true);
John.status.setProperty('hasPinkShirt', true);

console.log(John, John.status.getProperty('isOnfire'), John.status.getProperty('hasPinkShirt'));