【问题标题】:How to automatically call a function when a new object is created within an object在对象中创建新对象时如何自动调用函数
【发布时间】:2013-08-05 20:42:22
【问题描述】:

好吧,让我解释一下我要做什么,感觉像是一个基本问题,但似乎很难解决: 假设我有一个常规的 javascript 对象:

var x = {};

现在,当我向对象 x 添加任何新属性(现在让我们使用 newProp)时,我想自动通过函数 @987654329 传递该新属性及其值父对象的@x 存储时:

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

x.newProp = 13;

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

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

例如,即使我这样做:

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. 新属性的名称被隐藏了,只有 值可以传递给初始化函数(据我所知)。
  3. 即使使用 getter 函数,也可以检索原始存储值 很复杂,需要某种索引或其他东西。
  4. 以某种方式通过 x的原型似乎很疯狂……是吗?我什至不知道这是不是 可能。

非常感谢任何帮助...我不知所措!如果需要,我会澄清。


更新

有很多建议,但似乎从未完全给出完整的答案。经过几个月和一些启示后,这里有一些候选者(尽管没有一个是完全最佳的):

代理

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

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

【问题讨论】:

  • 查看Proxys(不要在生产中使用它,因为目前支持有限)。
  • 要么创建一个函数,它应该是向对象添加新属性的唯一入口点,因此能够在那里运行你的逻辑,要么你放弃这个相当不常见的要求。
  • 您正在寻找Object.watch,但它只适用于FF,而且速度非常慢。如果您控制对象实例化,Matthias 方法可能会起作用。
  • 谢谢@RobW,这实际上非常接近可能性,但不幸的是,这在生产中确实需要相当可靠。但有趣的线索!
  • @Renan 不幸的是,我需要使用标准属性创建语法的东西。使用 getter/setter 函数(或者可能是代理)似乎是最好的方法。

标签: javascript oop prototype getter-setter


【解决方案1】:

问题 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 });

【讨论】:

  • 哇,这让我向前迈出了一大步!现在我只需要将其设为“通用”,以便为每个新属性自动添加 getter 和 setter,而不必通过 Object.defineProperty 调用为每个新属性手动添加它们。也许我可以通过某种方式调整 x 的原型来做到这一点。另外,我很困惑“值”在 setterFunc 中的位置。好像是突然冒出来的!
  • 每次调用setterFunc,它都会创建并返回一个全新的函数。当这个新函数被调用时,它会将第一个参数赋值给变量value。这是否有助于您了解value 的来源?
  • 是的!这就像魔术一样。谢谢!但是这个问题还没有解决,因为我需要将它普遍地自动应用于添加到 x.xml 的所有新属性。我正在摆弄它:)
  • @ArjunMehta 人们已经多次告诉你,你想要的东西实际上并不可行。代理可以满足您的需求,但其他浏览器并不能很好地支持它们。这可能是适用于不同浏览器的最佳解决方法
  • 谢谢胡安,如果有人用代理写了一个答案,我会考虑这个答案! :)
猜你喜欢
  • 2015-03-31
  • 2020-10-10
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2012-05-16
相关资源
最近更新 更多