2011-07-26 3 views
1

Dans Firefox, j'ai plusieurs objets dont j'ai besoin pour déclencher un événement lorsqu'une propriété particulière de chacun est modifiée. J'utilise object.watch(), mais quand je renvoie la valeur de la propriété qui a été modifiée en utilisant "this", elle renvoie l'ancienne valeur la première fois et "indéfinie" la seconde et les suivantes:object.watch(), obtention d'une nouvelle valeur

var myObject = { 
     "aProperty": 1 
    }; 

function propChanged(prop) { 
    alert(prop); 
} 

myObject.watch("aProperty", function() { 
    propChanged(this.aProperty); 
}); 

myObject.aProperty = 2;//alerts "1" 
myObject.aProperty = 3;//alerts "undefined" 

La raison pour laquelle je ne peux pas simplement dire alert (myObject.aProperty) est parce que cela est censé être un code dynamique qui va appliquer le gestionnaire d'événements à plusieurs objets, éventuellement inconnus.

Je ne suis pas sûr exactement comment obtenir dynamiquement la nouvelle valeur de la propriété en utilisant la méthode de surveillance. Je suis en train de mettre en place un prototype d'IE pour cela, donc je ne m'inquiète pas de ne pas y travailler. J'ai juste besoin de comprendre "ceci" et comment cela s'applique au propriétaire de la méthode de surveillance.

Modifier >>

Voici le nouveau code J'utilise pour le navigateur croix, y compris l'IE et al prototype:

var myObject = {}; 

if (!Object.prototype.watch) { 
    Object.prototype.watch = function (prop, handler) { 
     var oldval = this[prop], newval = oldval, 
     getter = function() { 
      return newval; 
     }, 
     setter = function (val) { 
      oldval = newval; 
      return newval = handler.call(this, prop, oldval, val); 
     }; 
     if (delete this[prop]) { // can't watch constants 
      if (Object.defineProperty) // ECMAScript 5 
       Object.defineProperty(this, prop, { 
        get: getter, 
        set: setter 
       }); 
      else if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { // legacy 
       Object.prototype.__defineGetter__.call(this, prop, getter); 
       Object.prototype.__defineSetter__.call(this, prop, setter); 
      } 
     } 
    }; 
} 

if (!Object.prototype.unwatch) { 
    Object.prototype.unwatch = function (prop) { 
     var val = this[prop]; 
     delete this[prop]; // remove accessors 
     this[prop] = val; 
    }; 
} 


function propChanged(t, p, o, n) { 
    alert(o); 
} 

Object.defineProperty(myObject, "aProperty", {value: 2, 
    writable: true, 
    enumerable: true, 
    configurable: true}); 

myObject.watch("aProperty", propChanged); 

myObject.aProperty = 3; //alerts 3 
myObject.aProperty = 4; //alerts 4 (n is undefined in propChanged? 

Répondre

4

Vous devez retourner la valeur que vous voulez que la propriété a de la fonction que vous passez à regarder.

myObject.watch("aProperty", function (prop, oldval, newval) { 
    propChanged(newVal); 
    return newVal; 
}); 

devrait le faire.

Voir la MDN docs pour un détail complet de la fonction, mais le bit correspondant est

Montres pour l'attribution d'une propriété prop nommée dans cet objet, appelant handler(prop, oldval, newval) chaque fois prop est réglé et mémoriser la valeur de retour cette propriété. Un point de contrôle peut filtrer (ou annuler) l'affectation de valeur en renvoyant un newval modifié (ou en renvoyant oldval).

EDIT

Votre code modifié pourrait mieux fonctionner de cette façon

Object.prototype.watch = function (prop, handler) { 
    var fromPrototype = !Object.hasOwnProperty.call(this, prop), 
    val = this[prop], 
    getter = function() { 
     return fromPrototype ? Object.getPrototypeOf(this)[prop] : val; 
    }, 
    setter = function (newval) { 
     fromPrototype = false; 
     return val = handler.call(this, prop, val, newval); 
    }; 
    if (delete this[prop]) { // can't watch constants 
     if (Object.defineProperty) { // ECMAScript 5 
      Object.defineProperty(this, prop, { 
       get: getter, 
       set: setter, 
       configurable: true, 
       enumerable: true 
      }); 
     } else if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { // legacy 
      Object.prototype.__defineGetter__.call(this, prop, getter); 
      Object.prototype.__defineSetter__.call(this, prop, setter); 
     } 
    } 
}; 
+0

Je ne pense pas que je vous suis. Je pensais que c'était ce que je faisais. – Dexter

+0

Ah .. merci. Je creusais juste à travers le getter et le setter de la méthode et j'ai vu que je pourrais être capable d'ajouter des arguments au gestionnaire. Vous venez de me montrer ce que je cherchais! Merci! – Dexter

+0

@Dexter, de rien. Btw, si vous pouvez vous connecter au moment de la création de la propriété, la plupart des choses que vous pouvez faire avec 'watch' peuvent être faites avec plusieurs navigateurs (pour les navigateurs récents y compris FF4) via [defineProperty] (https: //developer.mozilla. org/fr/JavaScript/Référence/Global_Objects/Object/defineProperty) et même si vous ne le pouvez pas, vous pourrez intercepter les appels de méthode via http://wiki.ecmascript.org/doku.php?id=harmony:proxies ce que je crois est disponible dans certains des nightlies de Firefox. –

Questions connexes