使用 jQuery(或纯JS)绑定更改事件到数组中对象的属性

3
我有一个对象数组,这些对象都有一个'isvalid'属性。
是否可以使用JQuery或纯JavaScript将代码绑定到该属性值更改的事件?
因此,当我有一个包含10个对象的数组时,我希望在其中一个对象的'isvalid'属性更改时执行函数。
这是可能的吗?
米歇尔

3
请访问 https://dev59.com/1XNA5IYBdhLWcg3wKam3,该网页讨论了如何监听JavaScript对象属性值的变化。 - Manuel van Rijn
啊,没找到那个。我现在会去看一下。 - Michel
3个回答

3

通过使用一个属性设置器函数,可以使用纯JavaScript实现。使用ES5语法,代码如下(live example--在Chrome和其他合理支持ES5的浏览器中运行):

// Our constructor function
function Thing() {
}

// Define a "foo" property with a setter and getter
Object.defineProperty(Thing.prototype, "foo", {
  set: function(value) {
    this.fooStorage = value;
    display("Foo was set to '" + value + "'");
  },
  get: function() {
    return this.fooStorage;
  }
});

// Create a `Thing`  
var t = new Thing();

// Set its property
t.foo = "bar";

当执行t.foo = "bar";赋值语句时,会调用setter函数。如果需要,你可以让setter函数调用回调函数来通知你Thing对象已被更改。
请注意以上只是一个示例。它使用fooStorage属性存储foo的值,这不是最理想的方式,但对于示例而言简单易懂。
为了兼容非ES5 JavaScript引擎,你必须要么退回到Mozilla的某些专有且现在已弃用的语法(该语法在其他引擎上不起作用),要么使用显式的setter函数(实时示例):
// Our constructor function
function Thing() {
}

// Define a "foo" property with a setter and getter
Thing.prototype.setFoo = function(value) {
  this.fooStorage = value;
  display("Foo was set to '" + value + "'");
};
Thing.prototype.getFoo = function() {
  return this.fooStorage;
};

// Create a `Thing`
var t = new Thing();

// Set the property
t.setFoo("bar");

(再次强调,这只是一个使用简单的存储方式来存储foo值的示例。)
这种方法的优点是它可以与几乎任何JavaScript引擎一起使用,而不仅仅是符合ES5标准的引擎,并且明确设置foo是一个函数调用,而不仅仅是属性赋值(而使用ES5 setter/getter语法时,设置foo属性的人并不知道它是一个函数调用——这有优点和缺点)。
因此,这就是如何捕获属性更改的事实。然后,只需允许注册和删除回调以接收更改通知即可。这些可以在一个简单的数组中轻松管理。这里是一个基于ES5的示例,按对象进行处理;显然,您可以将其分组处理,以便为要让人们观察的整个对象数组执行此操作。(live copy
window.onload = function() {

  // Our constructor function
  function Thing() {
    this.fooHandlers = [];
  }

  // Add a listener for "foo" changes
  Thing.prototype.addFooChangeHandler = function(callback) {
    this.fooHandlers.push(callback);
  };

  // Remove a listener for "foo" changes
  Thing.prototype.removeFooChangeHandler = function(callback) {
    var index;

    index = this.fooHandlers.indexOf(callback);
    if (index >= 0) {
      this.fooHandlers.splice(index, 1);
    }
  };

  // Define a "foo" property with a setter and getter
  Object.defineProperty(Thing.prototype, "foo", {
    set: function(value) {
      var index;

      for (index = 0; index < this.fooHandlers.length; ++index) {
        try {
          // Handler receives a reference to this Thing,
          // foo's old value, and foo's new value.
          this.fooHandlers[index](this, value, this.fooStorage);
        }
        catch (e) {
        }
      }

      this.fooStorage = value;
    },
    get: function() {
      return this.fooStorage;
    }
  });

  // Create a `Thing`
  var t = new Thing();

  // Add a foo change handler
  t.addFooChangeHandler(function(t, newValue, oldValue) {
    display("Handler 1: Foo changed from '" + oldValue + "' to '" + newValue + "'");
  });

  // Add another
  t.addFooChangeHandler(function(t, newValue, oldValue) {
    display("Handler 2: Foo changed from '" + oldValue + "' to '" + newValue + "'");
  });

  // Set the property
  t.foo = "bar";
  t.foo = "boo";

  // === Basic utility functions

  function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = msg;
    document.body.appendChild(p);
  }
};

如果没有ES5 JavaScript引擎,只需设置先前描述的“setFoo” / “getFoo”模型,并确保引擎正确支持“Array#indexOf”(有些引擎根本没有它,有些使用“==”而不是“===”等价物),或者将“removeFooChangeHandler”中“Array#indexOf”的使用替换为简单地通过数组查找回调的循环。
// Remove a listener for "foo" changes
Thing.prototype.removeFooChangeHandler = function(callback) {
  var index;

  for (index = 0; index < this.fooHandlers.length; ++index) {
    if (this.fooHandlers[index] === callback) {
      this.fooHandlers.splice(index, 1);
      break;
    }
  }
};

顺便提一下:这些示例中有许多匿名函数。我这样做是为了避免让事情变得复杂,但我不喜欢匿名函数,我更喜欢函数有名称。详情请参见链接。


0
你可以将对象的属性设置为私有,然后只通过setter方法来修改它们。这样每次使用setter方法设置变量时,都可以触发一个事件。这种方式适用于任何环境。
如果你只能在浏览器中使用,可以使用watch方法(请参考Object.watch() for all browsers?以了解浏览器兼容性)。

0

1
http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers - T.J. Crowder
1
@T.J.Crowder 谢谢,我会记住这个,在我的下一个回答中应用。 - Abdul Munim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接