Javascript 属性更改上的断点

Javascript 属性更改上的断点,javascript,debugging,firefox,google-chrome,firebug,Javascript,Debugging,Firefox,Google Chrome,Firebug,Firefox的Firebug有一个很好的特性,叫做“属性更改时中断”,在这里我可以标记任何对象的任何属性,它将在更改之前停止JavaScript执行 我试图在Google Chrome中实现同样的功能,但在Chrome调试器中找不到该功能。如何在Google Chrome中做到这一点?如果您不介意混淆源代码,可以使用访问器重新定义属性 // original object var obj = { someProp: 10 }; // save in another property

Firefox的Firebug有一个很好的特性,叫做“属性更改时中断”,在这里我可以标记任何对象的任何属性,它将在更改之前停止JavaScript执行


我试图在Google Chrome中实现同样的功能,但在Chrome调试器中找不到该功能。如何在Google Chrome中做到这一点?

如果您不介意混淆源代码,可以使用访问器重新定义属性

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

编辑2016.03:
对象。观察
在Chrome 50中被弃用和删除

**编辑2014.05:“Object.observe”添加到Chrome 36中** Chrome 36附带本机
对象。请注意此处可以利用的
实现:

myObj={a:1,b:2};
观察对象(myObj,功能(变化){
日志(“更改:”);
控制台日志(更改);
调试器;
})
myObj.a=42;
如果只是暂时需要,则应将回调存储在变量中,并在完成后调用
对象。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
,则不会收到通知

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


原始答案(2012.07):

控制台。观看@katspaugh建议的草图:

var console=console | |{};//以防万一
console.watch=函数(oObj、sProp){
var sPrivateProp=“$\u”+sProp+“\u$”;//将名称冲突风险降至最低
oObj[sPrivateProp]=oObj[sProp];
//用存取器覆盖
对象定义属性(oObj、sProp、{
get:function(){
返回oObj[sPrivateProp];
},
设置:函数(值){
//console.log(“将“+sProp+”设置为“+value”);
调试器;//设置断点
oObj[sPrivateProp]=值;
}
});
}
调用:

console.watch(obj, "someProp");
兼容性:

  • 在Chrome20中,您可以在运行时将其直接粘贴到开发工具中
  • 完整性:在Firebug 1.10(Firefox 14)中,您必须将其注入您的网站(例如,如果无法手动编辑源代码,则通过Fiddler);遗憾的是,Firebug中定义的函数在
    调试器上似乎没有中断(或者是配置问题?请更正),但是
    控制台.log
    工作正常
注意,由于Firefox的非标准[`Object.watch`],在Firefox中,`console.watch`已经存在(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch). 因此,在Firefox中,您可以通过本机监视更改:
>>> var obj = { foo: 42 }
>>> obj.watch('foo', function() { console.log('changed') })
>>> obj.foo = 69
changed
69

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

有一个用于此的库:

如果将其作为代码段添加到Chrome开发工具中(源-->代码段-->右键单击-->新建-->粘贴),则可以随时使用它


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

breakOn(myObject, 'myProperty');

您还可以将库添加到项目的调试版本中,这样您就不必在每次刷新页面时再次调用
breakn

这也可以通过使用新对象来完成,该对象的目的正是:截取对代理所包装对象的读写。您只需将要观察的对象包装到代理中,并使用新包装的对象而不是原始对象

例如:

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,并在中断时检查调用堆栈。

Chrome在最新版本中内置了此功能

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

因此,不再需要自定义库和解决方案,只需在inspector中右键单击DOM元素并选择“断开”->“属性修改”,就可以了。

决定编写此解决方案的我自己的版本,将其保存在Chrome的DevTools中的一个片段中,并将其包装在一个应同时支持节点和浏览器的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)

在Alexandos Katechis的优秀解决方案的基础上,这里是代码片段的一个版本,它不会影响属性的原始值。我重新命名了它,以便更好地匹配我使用它时的想法

用法:

  • 通过Sources->Snippets添加代码段
  • 需要时,按Command-O并选择运行BreaknChange代码段
  • 在控制台中调用
    breaknChange(anyObject'propertyName')
  • 采取导致改变的行动
  • 在调试器中停止
  • 这对于发现全局库(如jQuery)被第三方脚本践踏的情况非常有用

    (功能(全局){
    global.breaknChange=(对象,属性)=>{
    let value=obj[prop]
    对象定义属性(对象、属性、{
    get:function(){
    返回值
    },
    set:函数(newValue){
    调试器
    值=新值
    },
    })
    }
    })(进程类型!=“未定义”?进程:窗口)
    
    有没有一个插件可以帮我这么做?@ArsenZahray,dunno。但是,您可以利用它制作一个方便的函数,并使用诸如
    console.watch(obj,'someProp')
    。出于安全原因,这不适用于内置属性,如
    window.location
    。要调试DOM元素的setter,应稍微修改此模式。查看更多信息details@katspaugh我能问你为什么需要这个
    obj.\u someProp=obj.someProp,这似乎与您试图归档的内容无关(可能是因为我遗漏了一些内容)。顺便说一句,在自定义代码中无法命中调试器似乎是Firebug 1.8和1.9之间的回归:->重复@colered我们必须存储val