web-dev-qa-db-fra.com

Point d'arrêt sur un changement de propriété

Firebug pour Firefox a une fonctionnalité Nice, appelée "Break on property change", dans laquelle je peux marquer n'importe quelle propriété d'un objet, et qui arrête l'exécution de JavaScript juste avant la modification.

J'essaie d'obtenir le même résultat dans Google Chrome et je ne trouve pas la fonction dans le débogueur Chrome). Comment puis-je procéder dans Google Chrome?

135
Arsen Zahray

Si cela ne vous dérange pas de jouer avec la source, vous pouvez redéfinir la propriété avec un accesseur.

// original object
var obj = {
    someProp: 10
};

// save in another property
obj._someProp = obj.someProp;

// overwrite with accessor
Object.defineProperty(obj, 'someProp', {
    get: function () {
        return obj._someProp;
    },

    set: function (value) {
        debugger; // sets breakpoint
        obj._someProp = value;
    }
});
92
katspaugh

Éditer 2016.03: Object.observe est obsolète et supprimé dans Chrome 50

Édition 2014.05: Object.observe a été ajouté dans Chrome 36

Chrome 36 est livré avec Object.observe mise en œuvre qui peut être exploitée ici:

myObj = {a: 1, b: 2};
Object.observe(myObj, function (changes){
    console.log("Changes:");
    console.log(changes);
    debugger;
})
myObj.a = 42;

Si vous ne le souhaitez que temporairement, vous devez stocker le rappel dans une variable et appeler Object.unobserve lorsque vous avez terminé:

myObj = {a: 1, b: 2};
func = function() {debugger;}
Object.observe(myObj, func);
myObj.a = 42;
Object.unobserve(myObj, func);
myObj.a = 84;

Notez que lorsque vous utilisez Object.observe, vous ne serez pas averti lorsque l’affectation n’a rien changé, par exemple. si vous avez écrit myObj.a = 1.

Pour voir la pile d'appels, vous devez activer l'option "Pile d'appels async" dans les outils de développement:

chrome async call stack


Réponse originale (2012.07):

UNE console.watch _ esquisse suggérée par @katspaugh:

var console = console || {}; // just in case
console.watch = function(oObj, sProp) {
   var sPrivateProp = "$_"+sProp+"_$"; // to minimize the name clash risk
   oObj[sPrivateProp] = oObj[sProp];

   // overwrite with accessor
   Object.defineProperty(oObj, sProp, {
       get: function () {
           return oObj[sPrivateProp];
       },

       set: function (value) {
           //console.log("setting " + sProp + " to " + value); 
           debugger; // sets breakpoint
           oObj[sPrivateProp] = value;
       }
   });
}

Invocation:

console.watch(obj, "someProp");

Compatibilité:

  • Dans Chrome 20, vous pouvez le coller directement dans les outils de développement au moment de l’exécution!).
  • Pour être complet: dans Firebug 1.10 (Firefox 14), vous devez l’injecter dans votre site Web (par exemple, via Fiddler si vous ne pouvez pas modifier le code source manuellement); Malheureusement, les fonctions définies par Firebug ne semblent pas s’être cassées sur debugger (ou est-ce une question de configuration? corrigez-moi alors), mais console.log travaux.

Modifier:

Notez que dans Firefox, console.watch existe déjà, en raison de la non-standard de Firefox Object.watch . Par conséquent, dans Firefox, vous pouvez surveiller les modifications de manière native:

>>> var obj = { foo: 42 }
>>> obj.watch('foo', function() { console.log('changed') })
>>> obj.foo = 69
changed
69

Cependant, cela sera bientôt (fin 2017) supprimé .

103
jakub.g

Il existe une bibliothèque pour cela: BreakOn ()

Si vous l'ajoutez à Chrome dev tools sous forme d'extrait de code (sources -> extraits de code -> clic-droit -> nouveau -> coller - this ) , vous pouvez l'utiliser à tout moment.


Pour l'utiliser, ouvrez les dev-tools et exécutez l'extrait de code. Puis casser quand myObject.myProperty est modifié, appelez-le depuis la console de développement:

breakOn(myObject, 'myProperty');

Vous pouvez également ajouter la bibliothèque à la version de débogage de votre projet afin de ne pas avoir à appeler breakOn à chaque fois que vous actualisez la page.

Cela peut également être fait en utilisant le nouvel objet Proxy dont le but est exactement le suivant: intercepter les lectures et les écritures sur l'objet encapsulé par le proxy. Vous intégrez simplement l'objet que vous souhaitez observer dans un proxy et utilisez le nouvel objet enveloppé au lieu de celui d'origine.

Exemple:

const originalObject = {property: 'XXX', propertyToWatch: 'YYY'};
const watchedProp = 'propertyToWatch';
const handler = {
  set(target, key, value) {
    if (key === watchedProp) {
      debugger;
    }
    target[key] = value;
  }
};
const wrappedObject = new Proxy(originalObject, handler);

Maintenant, utilisez wrappedObject où vous fourniriez à la place originalObject et examinerez la pile d'appels à la rupture.

3
Dmitry S.

Cette fonctionnalité est intégrée à Google Chrome dans les dernières versions. https://developers.google.com/web/updates/2015/05/view-and-change-your-dom-breakpoints .

Vous n'avez donc plus besoin de bibliothèques et de solutions personnalisées, cliquez simplement avec le bouton droit de la souris sur l'élément DOM dans l'inspecteur et choisissez "Interrompre" -> "attribuer les modifications", et c'est tout.

1
Ivica Puljic
function debugProperty(obj, propertyName) {
  // save in another property
  obj['_' + propertyName] = obj[propertyName];

  // overwrite with accessor
  Object.defineProperty(obj, propertyName, {
    get: function() {
      return obj['_' + propertyName];
    },

    set: function(value) {
      debugger; // sets breakpoint
      obj['_' + propertyName] = value;
    }
  });
}
0
Roland Soós

Décidé d'écrire ma propre version de cette solution, de l'enregistrer dans un extrait de l'outil de développement de Chrome et de l'envelopper dans un IIFE prenant en charge à la fois Node et les navigateurs. Changé également l'observateur pour utiliser une portée variable plutôt qu'une propriété sur l'objet, de sorte qu'il n'y a aucune possibilité de conflit de nom, et tout code qui énumère des clés ne "verra" pas la nouvelle "clé privée" créée:

(function (global) {
  global.observeObject = (obj, prop) => {
    let value

    Object.defineProperty(obj, prop, {
      get: function () {
        return value
      },

      set: function (newValue) {
        debugger
        value = newValue
      },
    })
  }
})(typeof process !== 'undefined' ? process : window)
0