属性更改的断点

IT技术 javascript debugging firefox google-chrome firebug
2021-01-14 18:19:59

Firebug for Firefox 有一个很好的功能,称为“中断属性更改”,我可以在其中标记任何对象的任何属性,并且它会在更改之前立即停止 JavaScript 执行。

我正在尝试在 Google Chrome 中实现相同的功能,但在 Chrome 调试器中找不到该功能。如何在 Google Chrome 中执行此操作?

6个回答

如果您不介意弄乱源代码,则可以使用访问器重新定义该属性。

// 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;
    }
});
这不适用于内置属性,例如window.location出于安全原因。
2021-03-12 18:19:59
有没有插件可以为我做到这一点?
2021-03-27 18:19:59
要调试 DOM 元素的 setter,应该稍微修改此模式。有关更多详细信息,请参阅mnaoumov.wordpress.com/2015/11/29/...
2021-03-27 18:19:59
@katspaugh 我可以问你为什么需要这个吗obj._someProp = obj.someProp;,这似乎与你想要归档的内容无关(可能是因为我错过了一些东西)
2021-03-27 18:19:59
@ArsenZahray,不知道。但是,您可以利用它制作一个方便的功能并使用 like console.watch(obj, 'someProp')
2021-04-07 18:19:59

编辑 2016.03:Object.observe在 Chrome 50 中已弃用并删除

**编辑 2014.05:在 Chrome 36 中添加了 `Object.observe` **

Chrome 36 附带了Object.observe可在此处利用的本机实现:

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

如果你只是暂时想要它,你应该将回调存储在一个变量中并Object.unobserve在完成后调用

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

请注意,在使用 时Object.observe,当分配没有更改任何内容,您将不会收到通知,例如,如果您已编写myObj.a = 1.

要查看调用堆栈,您需要在开发工具中启用“异步调用堆栈”选项:

chrome 异步调用堆栈


原答案(2012.07):

一个console.watch由@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;
       }
   });
}

调用:

console.watch(obj, "someProp");

兼容性:

  • 在 Chrome 20 中,可以在运行时直接粘贴到 Dev Tools 中!
  • 为完整起见:在 Firebug 1.10 (Firefox 14) 中,您必须将其注入您的网站(例如,如果您无法手动编辑源代码,则通过 Fiddler);遗憾的是,从 Firebug 定义的函数似乎没有中断debugger(或者是配置问题?然后请纠正我),但console.log有效。
请注意,在 Firefox 中,`console.watch` 已经存在,因为 Firefox 的非标准 [`Object.watch`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects /对象/手表)。因此,在 Firefox 中,您可以在本地观察更改:
>>> var obj = { foo: 42 }
>>> obj.watch('foo', function() { console.log('changed') })
>>> obj.foo = 69
changed
69

编辑:Object.watch已在 Firefox 57 中删除。

@ColeReed 我们必须将值存储在某个地方以在 getter 中检索它;它不能存储在 中oObj[sProp],因为 getter 会进入无限递归。在 Chrome 中试试,你会得到RangeError: Maximum call stack size exceeded.
2021-03-27 18:19:59
应该更新这个答案:Object.observe已弃用,很快将被删除:参见:chromestatus.com/features/6147094632988672
2021-04-01 18:19:59
@PhiLho 可以看到堆栈,使用async@cnp 写复选框,请参阅我的更新
2021-04-04 18:19:59
顺便说一句,似乎无法在自定义代码中点击调试器是 Firebug 1.8 和 1.9 之间的回归:问题 5757 ->问题 5221 的重复
2021-04-06 18:19:59
我想添加这个,因为async这种方法复选框是如此黄金: html5rocks.com/en/tutorials/developertools/async-call-stack
2021-04-11 18:19:59

有一个库: BreakOn()

如果您将它作为片段添加到 Chrome 开发工具中(sources --> snippets --> right-click --> new --> paste this --> run),您可以随时使用它。

在此处输入图片说明


要使用它,请打开开发工具并运行代码段。然后在myObject.myProperty更改时中断,从开发控制台调用它:

breakOn(myObject, 'myProperty');

您还可以将库添加到项目的调试构建中,这样您就无需在breakOn每次刷新页面时再次调用

当这个没有突破scrollLeftscrollTop正在发生变化。这帮助我意识到当用户的鼠标滚轮滚动修改这些值时不涉及 JavaScript。(无论他们变化是由影响overflow-xoverflow-y在SCSS风格。)
2021-03-14 18:19:59
任何试图从开发控制台调试的人的最佳解决方案。无需额外努力即可在任何网站上重复使用,真棒!
2021-03-18 18:19:59
很棒的工具发现!为调试复杂代码节省了大量时间。
2021-04-03 18:19:59

这也可以通过使用新的Proxy对象来完成,其目的正是:拦截对由 Proxy 包装的对象的读取和写入。您只需将要观察的对象包装到代理中,然后使用新包装的对象而不是原始对象。

例子:

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

现在使用wrappedObject,您将在其中提供originalObject,并在中断时检查调用堆栈。

代理set必须返回,true以便它不会因跟踪案例以外的情况而失败。
2021-03-15 18:19:59
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;
    }
  });
}