监听器在javascript对象中更改属性值

Nag*_*ran 20 javascript browser dom-events

通过javascript文档,我发现javascript对象上的以下两个函数看起来很有趣:

.watch - 为属性分配值并在发生时运行函数.
.unwatch - 使用watch方法删除观察点集.

样品用法:

o = { p: 1 };
o.watch("p", function (id,oldval,newval) {
    console.log("o." + id + " changed from " + oldval + " to " + newval)
    return newval;
});
Run Code Online (Sandbox Code Playgroud)

每当我们更改"p"的属性值时,此函数都会被触发.

o.p = 2;   //logs: "o.p changed from 1 to 2"
Run Code Online (Sandbox Code Playgroud)

我在过去的几年里一直在使用javascript,从未使用过这些函数.
有人可以抛出一些好的用例,这些功能会派上用场吗?

Ell*_* B. 13

现在是2018年,这个问题的答案有点过时了:

今天,您现在可以使用代理对象来监视(和拦截)对对象所做的更改。它是为OP要做的目的而专门设计的。这是一个基本示例:

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
      return true;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'
Run Code Online (Sandbox Code Playgroud)

Proxy对象的唯一缺点是:

  1. Proxy对象在较旧的浏览器(例如IE11)中不可用,并且polyfill无法完全复制Proxy功能。
  2. 代理对象在特殊对象(例如Date)上的行为并不总是如预期的那样- Proxy最好与普通对象或数组配对。

如果需要观察对嵌套对象所做的更改,则需要使用专门的库,例如Observable Slim(由我编写)。它是这样的:

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]
Run Code Online (Sandbox Code Playgroud)

  • 不确定我理解你的代理示例。您写道它可以拦截对目标对象的更改,但在您的示例中,您通过代理而不是目标对象修改属性值。目前尚不清楚如何用此方法拦截目标对象的更改。 (9认同)
  • @Johncl这就是代理对象的工作原理:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy 行为是否最好用“拦截”、“虚拟化”一词来描述”、“陷阱”或其他什么东西在某种程度上取决于解释。 (2认同)
  • 但这与聆听原始发布者要求的属性更改完全不同。如果您有一个具有某些属性的对象,并且将该对象传递到另一个黑匣子中 - 但黑匣子想要侦听该对象中属性的更改并对其进行操作,则上面的 Proxy 对象根本没有帮助。 (2认同)
  • @Johncl这并不是完全不同——使用“代理”,你可以实现完全相同的最终结果。但是,是的,你是对的,你没有观察到“直接”对目标对象所做的更改——这是名称“Proxy”所暗示的。 (2认同)

Pre*_*aul 8

真正设计的手表是属性值的验证.例如,您可以验证某些内容是否为整数:

obj.watch('count', function(id, oldval, newval) {
    var val = parseInt(newval, 10);
    if(isNaN(val)) return oldval;
    return val;
});
Run Code Online (Sandbox Code Playgroud)

您可以使用它来验证字符串长度:

obj.watch('name', function(id, oldval, newval) {
    return newval.substr(0, 20);
});
Run Code Online (Sandbox Code Playgroud)

但是,这些仅在最新版本的SpiderMonkey javascript引擎中可用. 如果您使用的是Jaxer或嵌入SpiderMonkey引擎,但在您的浏览器中尚未实际可用(除非您使用的是FF3),这很棒.

  • 这些方法“watch”和“unwatch”已被弃用。请不要使用它。 (2认同)

Sea*_*gan 8

签出Object.definePropertyObject.prototype.\__defineGetter__(或\__defineSetter__)查看此功能的标题.

Object.defineProperty 应该很快就可以在所有现代浏览器中使用.