Breakpoint on property change
Solution 1
If you don't mind messing around with the source, you could redefine the property with an 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;
}
});
Solution 2
Edit 2016.03: Object.observe
is deprecated and removed in Chrome 50
Chrome 36 ships with native Object.observe
implementation that can be leveraged here:
myObj = {a: 1, b: 2};
Object.observe(myObj, function (changes){
console.log("Changes:");
console.log(changes);
debugger;
})
myObj.a = 42;
If you want it only temporarily, you should store callback in a variable and call Object.unobserve
when done:
myObj = {a: 1, b: 2};
func = function() {debugger;}
Object.observe(myObj, func);
myObj.a = 42;
Object.unobserve(myObj, func);
myObj.a = 84;
Note that when using Object.observe
, you'll not be notified when the assignment didn't change anything, e.g. if you've written myObj.a = 1
.
To see the call stack, you need to enable "async call stack" option in Dev Tools:
Original answer (2012.07):
A console.watch
sketch as suggested by @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");
Compatibility:
- In Chrome 20, you can paste it directly in Dev Tools at runtime!
- For completeness: in Firebug 1.10 (Firefox 14), you have to inject it in your website (e.g. via Fiddler if you can't edit the source manually); sadly, functions defined from Firebug don't seem to break on
debugger
(or is it a matter of configuration? please correct me then), butconsole.log
works.
>>> var obj = { foo: 42 }
>>> obj.watch('foo', function() { console.log('changed') })
>>> obj.foo = 69
changed
69
Edit: Object.watch
was removed in Firefox 57.
Solution 3
There is a library for this: BreakOn()
If you add it to Chrome dev tools as a snippet (sources --> snippets --> right-click --> new --> paste this --> run), you can use it anytime.
To use it, open the dev-tools and run the snippet. Then to break when myObject.myProperty
is changed, call this from the dev-console:
breakOn(myObject, 'myProperty');
You could also add the library to your project's debug-build so you don't need to call breakOn
again every time you refresh the page.
Solution 4
This can also be done by using the new Proxy object whose purpose is exactly that: intercepting the reads and writes to the object that is wrapped by the Proxy. You simply wrap the object you would like to observe into a Proxy and use the new wrapped object instead of your original one.
Example:
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);
Now use wrappedObject where you would supply originalObject instead and examine the call stack on break.
Solution 5
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;
}
});
}
Related videos on Youtube
Arsen Zahray
Updated on July 05, 2021Comments
-
Arsen Zahray almost 3 years
Firebug for Firefox has a nice feature, called "Break on property change", where I can mark any property of any object, and it will stop JavaScript execution right before the change.
I'm trying to achieve the same in Google Chrome, and I can't find the function in Chrome debugger. How do I do this in Google Chrome?
-
chx over 8 yearsIf you want to do this with HTML elements see stackoverflow.com/a/32686203/308851
-
-
Arsen Zahray almost 12 yearsis there a plug in which would do that for me?
-
katspaugh almost 12 years@ArsenZahray, dunno. However, you can make a handy function out of it and use like
console.watch(obj, 'someProp')
. -
jakub.g almost 12 yearsBy the way, it seems being unable to hit debugger in custom code is a regression between Firebug 1.8 and 1.9: issue 5757 -> duplicate of issue 5221
-
Cole Reed over 10 yearsWhat is the purpose / benefit of saving the object value into the sPrivateProp variable, and then retrieving through that variable?
-
jakub.g over 10 years@ColeReed we must store the value somewhere to retrieve it in the getter; it can not be stored in
oObj[sProp]
, because the getter would enter an infinite recursion. Try it in Chrome, you'll getRangeError: Maximum call stack size exceeded
. -
qJake over 9 yearsThis does not work for built-in properties such as
window.location
for security reasons. -
Piranna over 9 yearsIsn't there a Chrome extension to add this console method? It's awesome! :-D
-
jakub.g over 9 years
Object.observe
/ and the"console.watch"
I wrote only works with JS objects. For DOM objects, you can useMutationObserver
. See them in action here. Note though that in Chrome Dev Tools debugger, you can put "DOM breakpoints" instead. -
cnp about 9 yearsI"d like to add this, as the
async
checkbox is so golden with this approach: html5rocks.com/en/tutorials/developertools/async-call-stack -
mnaoumov over 8 yearsTo debug setters for DOM elements this pattern should be slightly modified. See mnaoumov.wordpress.com/2015/11/29/… for more details
-
PhiLho about 8 yearsThis is useful in itself, but alas, unless I miss something, in current Chrome (48), we can see only the changes, not the call stack, so we don't know where it has been changed. And it seems to accumulate / group changes.
-
jakub.g about 8 years@PhiLho it's possible to see the stack, with the
async
checkbox as @cnp wrote, see my update -
PhiLho about 8 yearsThanks, I will try. The linked article is about async APIs, so I thought it was off-topic... Meanwhile, I tried Firefox' object.watch which gives the call stack. That gives us some useful tools in our quiver (or arrows in our toolbox?).
-
Amir Gonnen about 8 yearsShould update this answer:
Object.observe
is deprecated and soon will be removed: see: chromestatus.com/features/6147094632988672 -
jakub.g about 8 yearsRight, I knew it was deprecated but didn't know they finally decided to remove it in Chrome 50. Updated the answer.
-
Bernardo Dal Corno almost 6 yearsHe asked for (js object) property change, not DOM attribute value change
-
keaukraine almost 5 yearsProxy's
set
must returntrue
for it not to fail for other than tracked cases. -
bnieland over 4 years@Ivica This is a good technique, but this is the wrong place to put it. It would be fine as a comment, but not as an answer.
-
Victor over 4 years@katspaugh can i ask why you need to this
obj._someProp = obj.someProp;
, it seems unrelated regarding what you are trying to archieve (probably because i'm missing somethign) -
Victor over 4 yearsFound this link: stackoverflow.com/questions/38256087/… that explains why it is needed
-
Rena about 4 yearsThank you for updating your answer to indicate that the function was removed! Too many answers are stale...
-
Chris Hayes almost 4 yearsBest solution for anyone trying to debug from dev console. No extra effort to reuse on any website, awesome!
-
Timothy C. Quinn almost 3 yearsAwesome tool find! Such a massive time saver for debugging complex code.
-
root almost 3 yearsThis didn't break when
scrollLeft
andscrollTop
were changing. This helped me realize that there is no JavaScript involved when the user's mousewheel scrolling modifies these values. (Whether they change is influenced byoverflow-x
andoverflow-y
in the SCSS style.)