167

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?

4

8 回答 8

126

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

// 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;
    }
});
于 2012-07-23T18:35:00.627 回答
115

编辑 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 中被删除。

于 2012-07-25T21:10:18.307 回答
97

有一个库: BreakOn()

如果您将它作为片段添加到 Chrome 开发工具中(来源 -->片段--> 右键单击​​ --> 新建 --> 粘贴--> 运行),您可以随时使用它

在此处输入图像描述


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

breakOn(myObject, 'myProperty');

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

于 2016-07-28T20:25:58.477 回答
6

这也可以通过使用新的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 并检查中断时的调用堆栈。

于 2017-11-25T14:21:28.850 回答
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;
    }
  });
}
于 2018-01-18T06:54:46.817 回答
3

决定编写我自己的解决方案版本,将其保存在 Chrome 的 DevTools 中的一个片段中,并将其包装在一个应该支持 Node 和浏览器的 IIFE 中。还更改了观察者以使用范围变量而不是对象上的属性,这样就不会有名称冲突的可能性,并且任何枚举键的代码都不会“看到”新创建的“私钥”:

(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)
于 2019-05-08T18:15:43.373 回答
1

在 Alexandos Katechis 的出色解决方案的基础上,这里是一个不影响财产原始价值的片段版本。我重命名它以更好地匹配我使用它时的想法。

用法:

  1. 通过 Sources -> Snippets 添加片段
  2. 需要时,按 Command-O 并选择运行 breakOnChange 片段
  3. breakOnChange(anyObject, 'propertyName')在控制台中调用
  4. 采取导致改变的行动
  5. 在调试器中停止

这对于发现诸如 jQuery 之类的全局库被第三方脚本踩踏之类的事情非常有帮助。

(function (global) {
  global.breakOnChange = (obj, prop) => {
    let value = obj[prop]

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

      set: function (newValue) {
        debugger
        value = newValue
      },
    })
  }
})(typeof process !== 'undefined' ? process : window)
于 2021-03-01T17:19:47.490 回答
-3

Chrome 在最新版本中内置了此功能https://developers.google.com/web/updates/2015/05/view-and-change-your-dom-breakpoints

因此不再需要自定义库和解决方案,只需右键单击检查器中的 DOM 元素并选择“中断”->“属性修改”即可。

于 2018-06-02T09:20:29.177 回答