财产变化的断点

时间:2012-07-23 18:26:41

标签: javascript debugging firefox google-chrome firebug

Firebug for Firefox有一个很好的功能,名为“Break on property change”,我可以在其中标记任何对象的任何属性,它将在更改之前停止JavaScript执行。

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

8 个答案:

答案 0 :(得分:103)

修改2016.03:我已弃用并在Chrome 50中删除Object.observe

<击> 修改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 async call stack


原始答案(2012.07):

@katspaugh建议的console.watch草图:

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中,由于Firefox的非标准Object.watchconsole.watch已经存在。因此,在Firefox中,您可以本地监视更改:

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

然而,this will be soon (late 2017) removed

答案 1 :(得分:88)

如果您不介意搞乱来源,可以使用访问者重新定义该属性。

// 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 :(得分:66)

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), 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.

答案 3 :(得分:2)

这也可以通过使用新的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,并在break上检查调用堆栈。

答案 4 :(得分: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)

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

因此不再需要自定义库和解决方案,只需右键单击检查器中的DOM元素,然后选择“中断”即可。 - &GT; &#39;属性修改&#39;那就是它。

答案 7 :(得分:0)

决定编写此解决方案的我自己的版本,将其保存在Chrome的DevTools中的一段代码中,然后将其包装在同时支持Node和Browsers的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)