Est-il possible d'avoir un événement en JS qui se déclenche lorsque la valeur d'une certaine variable change ? JQuery est accepté.
Non.
Mais, si c’est vraiment si important, vous avez deux options (la première est testée, la seconde ne l’est pas):
Premièrement, utiliser des setters et getters, comme ceci:
var myobj = {a : 1};
function create_gets_sets(obj) { // make this a framework/global function
var proxy = {}
for ( var i in obj ) {
if (obj.hasOwnProperty(i)) {
var k = i;
proxy["set_"+i] = function (val) { this[k] = val; };
proxy["get_"+i] = function () { return this[k]; };
}
}
for (var i in proxy) {
if (proxy.hasOwnProperty(i)) {
obj[i] = proxy[i];
}
}
}
create_gets_sets(myobj);
puis vous pouvez faire quelque chose comme:
function listen_to(obj, prop, handler) {
var current_setter = obj["set_" + prop];
var old_val = obj["get_" + prop]();
obj["set_" + prop] = function(val) { current_setter.apply(obj, [old_val, val]); handler(val));
}
puis définir l'écouteur comme:
listen_to(myobj, "a", function(oldval, newval) {
alert("old : " + oldval + " new : " + newval);
}
Deuxièmement, j'ai en fait oublié, je vais soumettre pendant que j'y pense :)
EDIT : Oh, je me souviens :) Vous pourriez mettre une montre sur la valeur:
Given myobj ci-dessus, avec 'a' ; dessus:
function watch(obj, prop, handler) { // make this a framework/global function
var currval = obj[prop];
function callback() {
if (obj[prop] != currval) {
var temp = currval;
currval = obj[prop];
handler(temp, currval);
}
}
return callback;
}
var myhandler = function (oldval, newval) {
//do something
};
var intervalH = setInterval(watch(myobj, "a", myhandler), 100);
myobj.set_a(2);
Comme la réponse de [Luke Schafer][1] (note : ceci fait référence à son message original ; mais l'ensemble du point reste valable après la modification), je suggérerais également une paire de méthodes Get/Set pour accéder à votre valeur.
Cependant, je suggérerais quelques modifications (et c'est pour cela que je poste...).
Un problème avec ce code est que le champ a
de l'objet myobj
est directement accessible, donc il est possible d'y accéder / de changer sa valeur sans déclencher les listeners:
var myobj = { a : 5, get_a : function() { return this.a;}, set_a : function(val) { this.a = val; }}
/* add listeners ... */
myobj.a = 10; // no listeners called!
Donc, pour garantir que les listeners sont effectivement appelés, nous devrions interdire cet accès direct au champ a
. Comment le faire ? Utilisez une fermeture !
var myobj = (function() { // Anonymous function to create scope.
var a = 5; // 'a' is local to this function
// and cannot be directly accessed from outside
// this anonymous function's scope
return {
get_a : function() { return a; }, // These functions are closures:
set_a : function(val) { a = val; } // they keep reference to
// something ('a') that was on scope
// where they were defined
};
})();
Maintenant, vous pouvez utiliser la même méthode pour créer et ajouter les listeners que celle proposée par Luke, mais vous pouvez être sûr qu’il n’y a aucun moyen possible de lire ou d’écrire sur a
sans que cela soit remarqué !
Toujours sur la piste de Luke, je propose maintenant une manière simple d'ajouter des champs encapsulés et les getters/setters respectifs aux objets au moyen d'un simple appel de fonction.
Notez que cela ne fonctionnera correctement qu'avec les types valeur. Pour que cela fonctionne avec des types de référence, une sorte de copie profonde devrait être implémentée (voir [celui-ci][2], par exemple).
function addProperty(obj, name, initial) {
var field = initial;
obj["get_" + name] = function() { return field; }
obj["set_" + name] = function(val) { field = val; }
}
Cela fonctionne de la même manière que précédemment : nous créons une variable locale sur une fonction, puis nous créons une fermeture.
Comment l'utiliser ? C'est simple:
var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);
[1] : https://stackoverflow.com/questions/1759987/detect-variable-change-in-javascript/1760040#1760040 [2] : http://blog.imaginea.com/deep-copy-in-javascript/