Breakpoint sulla modifica della proprietà


147

Firebug per Firefox ha una bella funzione, chiamata "Break on change change", in cui posso contrassegnare qualsiasi proprietà di qualsiasi oggetto e interromperà l'esecuzione di JavaScript prima della modifica.

Sto cercando di ottenere lo stesso in Google Chrome e non riesco a trovare la funzione nel debugger di Chrome. Come faccio a farlo in Google Chrome?


1
Se si vuole fare questo con gli elementi HTML vedere stackoverflow.com/a/32686203/308851
chx

Risposte:


106

Se non ti dispiace scherzare con la fonte, potresti ridefinire la proprietà con un accessor.

// 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;
    }
});

2
c'è una spina che lo farebbe per me?
Arsen Zahray,

3
@ArsenZahray, non lo so. Tuttavia, puoi farne una pratica funzione e usare like console.watch(obj, 'someProp').
Katspaugh,

5
Questo non funziona per le proprietà integrate, ad esempio window.locationper motivi di sicurezza.
qJake

1
Per eseguire il debug dei setter per gli elementi DOM questo schema dovrebbe essere leggermente modificato. Vedi mnaoumov.wordpress.com/2015/2015/2/29/… per maggiori dettagli
mnaoumov

@katspaugh posso chiederti il ​​motivo per cui hai bisogno di questo obj._someProp = obj.someProp;, non sembra correlato a ciò che stai cercando di archiviare (probabilmente perché mi manca qualcosa)
Victor

109

Modifica 2016.03: Object.observeè obsoleto e rimosso in Chrome 50

Modifica 2014.05: è Object.observestato aggiunto in Chrome 36

Chrome 36 viene fornito con Object.observeun'implementazione nativa che può essere sfruttata qui:

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

Se lo desideri solo temporaneamente, dovresti archiviare il callback in una variabile e chiamare Object.unobserveal termine:

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

Tieni presente che durante l'utilizzo Object.observenon riceverai una notifica quando il compito non ha cambiato nulla, ad esempio se hai scritto myObj.a = 1.

Per vedere lo stack di chiamate, devi abilitare l'opzione "stack di chiamate asincrono" in Dev Tools:

stack di chiamate asincrono cromato


Risposta originale (2012.07):

Uno console.watchschizzo come suggerito da @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;
       }
   });
}

Invocazione:

console.watch(obj, "someProp");

Compatibilità:

  • In Chrome 20, puoi incollarlo direttamente in Dev Tools in fase di esecuzione!
  • Per completezza: in Firebug 1.10 (Firefox 14), è necessario iniettarlo nel proprio sito Web (ad es. Tramite Fiddler se non è possibile modificare manualmente la fonte); purtroppo, le funzioni definite da Firebug non sembrano rompersi debugger(o è una questione di configurazione? per favore correggetemi allora), ma console.logfunziona.

Modificare:

Nota che in Firefox console.watchesiste già, a causa del non standard di Firefox Object.watch. Quindi in Firefox, puoi guardare le modifiche in modo nativo:

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

Tuttavia, questo sarà presto (fine 2017) rimosso .


1
A proposito, sembra che non riuscire a colpire il debugger nel codice personalizzato sia una regressione tra Firebug 1.8 e 1.9: numero 5757 -> duplicato del problema 5221
jakub.g

1
@ColeReed dobbiamo memorizzare il valore da qualche parte per recuperarlo nel getter; non può essere archiviato oObj[sProp], perché il getter entrerebbe in una ricorsione infinita. Provalo in Chrome, otterrai RangeError: Maximum call stack size exceeded.
jakub.g,

1
Vorrei aggiungere questo, poiché la asynccasella di controllo è così dorata con questo approccio: html5rocks.com/en/tutorials/developertools/async-call-stack
cnp

1
@PhiLho è possibile vedere lo stack, con la asynccasella di controllo come ha scritto @cnp, vedere il mio aggiornamento
jakub.g

1
Dovrebbe aggiornare questa risposta: Object.observeè obsoleta e presto verrà rimossa: vedi chromestatus.com/features/6147094632988672
Amir Gonnen,

79

C'è una libreria per questo: BreakOn ()

Se lo aggiungi agli strumenti di sviluppo di Chrome come snippet (fonti -> snippet -> fai clic con il pulsante destro del mouse -> nuovo -> incolla questo ) , puoi utilizzarlo in qualsiasi momento.


Per usarlo, apri dev-tools ed esegui lo snippet. Quindi per interrompere quando myObject.myPropertyviene modificato, chiamalo dalla console di sviluppo:

breakOn(myObject, 'myProperty');

È inoltre possibile aggiungere la libreria alla build di debug del progetto in modo da non dover chiamare breakOnnuovamente ogni volta che si aggiorna la pagina.


5

Questo può essere fatto anche usando il nuovo proxy oggetto cui scopo è esattamente quello: intercettare le letture e le scritture sull'oggetto che è avvolto dal Proxy. Devi semplicemente avvolgere l'oggetto che desideri osservare in un proxy e utilizzare il nuovo oggetto avvolto anziché quello originale.

Esempio:

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);

Ora usa wrapperObject dove forniresti invece OriginalObject ed esamina lo stack di chiamate in pausa.


I proxy setdevono essere restituiti trueper non fallire se non per i casi tracciati.
keaukraine,

4
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;
    }
  });
}

1

Ho deciso di scrivere la mia versione di questa soluzione, salvarla in uno snippet in DevTools di Chrome e inserirla in un IIFE che dovrebbe supportare sia Node che Browser. Inoltre, l'osservatore ha cambiato in modo da utilizzare una variabile scope piuttosto che una proprietà sull'oggetto, in modo tale che non vi sia alcuna possibilità di scontro tra nomi e qualsiasi codice che enumera le chiavi non "vedrà" la nuova "chiave privata" creata:

(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)

-2

Chrome ha questa funzione integrata nelle ultime versioni https://developers.google.com/web/updates/2015/05/view-and-change-your-dom-breakpoints .

Quindi non sono più necessarie librerie e soluzioni personalizzate, basta fare clic con il pulsante destro del mouse sull'elemento DOM nella finestra di ispezione e scegliere "Interrompi" -> "Modifica attributi" e il gioco è fatto.


10
Ha chiesto la modifica della proprietà (oggetto js), non la modifica del valore dell'attributo DOM
Z. Khullah,

1
@Ivica Questa è una buona tecnica, ma questo è il posto sbagliato per dirla. Andrebbe bene come commento, ma non come risposta.
bnieland,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.