web-dev-qa-db-ja.com

プロパティ変更のブレークポイント

Firebug for Firefoxには、「プロパティ変更時のブレーク」と呼ばれる素敵な機能があり、任意のオブジェクトのプロパティをマークでき、変更の直前にJavaScriptの実行を停止します。

Google Chromeでも同じことをしようとしていますが、Chromeデバッガーで関数が見つかりません。 Google Chromeでこれを行うにはどうすればよいですか?

135
Arsen Zahray

ソースをいじくり回しても構わない場合は、アクセサでプロパティを再定義できます。

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

2016.03の編集:Object.observeは廃止され、Chrome 50 で削除されました

2014.05の編集:Object.observeがChrome 36 に追加されました

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では、実行時に開発ツールに直接貼り付けることができます!
  • 完全を期すため:Firebug 1.10(Firefox 14)では、Webサイトに挿入する必要があります(たとえば、ソースを手動で編集できない場合はFiddlerを使用)。悲しいことに、Firebugで定義された関数はdebuggerで壊れないようです(または、構成の問題ですか?修正してください)が、console.logは機能します。

編集:

Firefoxには、Firefoxの非標準 console.watch のため、Object.watchがすでに存在していることに注意してください。したがって、Firefoxでは、変更をネイティブで監視できます。

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

ただし、 これはまもなく(2017年後半)削除されます

103
jakub.g

このためのライブラリがあります: BreakOn()

Chrome devツールにスニペットとして追加する場合(ソース->スニペット->右クリック->新規->貼り付け this、いつでも使用できます。


使用するには、dev-toolsを開いてスニペットを実行します。 myObject.myPropertyが変更されたときに中断するには、dev-consoleからこれを呼び出します。

breakOn(myObject, 'myProperty');

ライブラリをプロジェクトのデバッグビルドに追加して、ページを更新するたびにbreakOnを再度呼び出す必要がないようにすることもできます。

これは、新しい 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);

次に、代わりにoriginalObjectを指定する場所でwrappedObjectを使用し、ブレーク時の呼び出しスタックを調べます。

3
Dmitry S.

Chromeには、この機能が最新バージョンに組み込まれています https://developers.google.com/web/updates/2015/05/view-and-change-your-dom-breakpoints

したがって、カスタムライブラリとソリューションの必要はありません。インスペクタでDOM要素を右クリックし、[Break on]-> [attribute modification]を選択するだけです。

1
Ivica Puljic
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;
    }
  });
}
0
Roland Soós

このソリューションの独自バージョンを作成し、ChromeのDevToolsのスニペットに保存し、NodeとBrowserの両方をサポートする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)
0