如何在对象中创建新对象时自动调用函数

时间:2013-08-05 20:42:23

标签: javascript oop prototype getter-setter

好吧,让我解释一下我正在尝试做什么,这感觉就像一个基本问题,但似乎非常困难来解决: 假设我有一个常规的javascript对象:

var x = {};

现在,当我添加任何新属性(现在让我们使用newProp)到对象x时,我想自动传递新属性及其值存储它时父对象initializer的函数x

x.initializer = function(propKey, propValue){
  console.log(propKey, 'IS', propValue);
}

x.newProp = 13;

所以在这种情况下,当我定义x.initializer(x.newProp);时,我想自动触发x.newProp(任何时候分配/更改其值时,作为奖励。 )但最终,我希望自动完成添加到x的所有新属性。

我试图通过setter / getters和原型来做到这一点,但这些方法的复杂性并不明显,似乎有限。

例如,即使我这样做了:

function setterFunc(value){
  x.initializer("newProp", value); //the name of the property isn't even dynamic.
}
function getterFunc(value){
  return someValue; //SOMEHOW!
}
Object.defineProperty(x, 'newProp', { get: getterFunc,
                                      set: setterFunc,
                                      configurable: true,
                                      enumerable: true });

这种方法存在许多问题/并发症:

  1. newProp的值本质上需要存储在另一个键中 使用get / set。
  2. 新属性的名称被遮盖,只有 value可以传递给初始化函数(据我所知)。
  3. 甚至使用getter函数,检索原始存储值 很复杂,需要某种索引或其他东西。
  4. 通过以某种方式为所有新属性实现这一点 x的原型似乎很疯狂......是吗?我甚至都不知道那是不是 可能的。
  5. 任何帮助超级赞赏......我不知所措!如果需要,我会澄清。


    更新

    有许多建议,但似乎从未完全给出完整的答案。经过几个月和一些启示,这里有一些候选人(虽然没有一个完全最佳):

    代理

    http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies

    Rob W建议,似乎与所需的功能非常匹配。如上所述,它并未在任何地方实施,仍然是和谐草案的一部分。


    Object.observe();

    http://wiki.ecmascript.org/doku.php?id=harmony:observe

    此外,作为和声规范的一部分,Observe以最小的性能影响(理论上)监听对象的变化。还有一段路要走。


    Watch.js

    https://github.com/melanke/Watch.JS

    此跨浏览器库监视对象的属性,但它似乎不监视对象本身。因此,您似乎必须将对象分配给另一个对象的属性。

1 个答案:

答案 0 :(得分:3)

问题2可以通过为每个属性生成不同的getter和setter函数来解决。

function setterFunc(prop) {
  return function(value) {
    x._private[prop] = value;
    x.initializer(prop, value);
  }
}

function getterFunc(prop) {
  return function() {
    return x._private[prop];
  }
}

Object.defineProperty(x, 'newProp', { get: getterFunc('newProp'),
                                      set: setterFunc('newProp'),
                                      configurable: true,
                                      enumerable: true });