属性更改的断点

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

我正在尝试在谷歌浏览器中实现同样的功能,但是我在 Chrome 调试器中找不到这个功能。我如何在谷歌浏览器中做到这一点?

76634 次浏览

如果您不介意对源代码进行修改,可以使用访问器重新定义属性。

// 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: 在 Chrome50中取消和删除 Object.observe

* * 编辑2014.05: 在 Chrome36中添加“ Object.Observer”* *

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

兼容性:

  • 在 Chrome20中,你可以在运行时直接粘贴到开发工具中!
  • 为了完整起见: 在 Firebug 1.10(Firefox 14)中,你必须将它注入到你的网站中(例如,如果你不能手动编辑源代码,可以通过 Fiddler) ; 遗憾的是,从 Firebug 定义的函数似乎不会在 debugger上中断(或者这是一个配置问题?请纠正我) ,但 console.log工程。
请注意,在 Firefox 中,由于 Firefox 的非标准[‘ Object.watch’]( https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/object/watch ) ,“ console. watch”已经存在。因此,在 Firefox 中,你可以看到原生的变化:
>>> var obj = { foo: 42 }
>>> obj.watch('foo', function() { console.log('changed') })
>>> obj.foo = 69
changed
69

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

有一个这样的库: 破碎()

如果你把它作为一个片段 (图片来源: http://developer.chrome.com/docs/devtools/javascript/resources/# Snippets”rel = “ noReferrer”> Snippets > 右键单击—— > new —— > 粘贴 < a href = “ https://raw.githubusercontent.com/paulirish/break-on-access/master/break-on-acc.js”rel = “ noReferrer”> this —— > run)添加到 Chrome 开发工具中,你可以在任何时候使用它。

enter image description here


要使用它,请打开 dev-tools 并运行代码段。然后,要在 myObject.myProperty更改时中断,请从 dev-sole 调用:

breakOn(myObject, 'myProperty');

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

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

例如:

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,您可以在其中提供 OrigalObject,并在中断时检查调用堆栈。

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

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

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

决定编写自己版本的解决方案,将其保存在 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)

基于 Alexandos Katechis 的优秀解决方案,下面是这个代码片段的一个版本,它不会干扰属性的原始值。我重新命名它,以便更好地匹配我使用它时的想法。

用法:

  1. 通过 Source-> 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)