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


147

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

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


1
HTML要素でこれを行う場合は、stackoverflow.com
a / 32686203/308851

回答:


106

ソースをいじることを気にしない場合は、アクセサーを使用してプロパティを再定義できます。

// 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
それを行うプラグインはありますか?
Arsen Zahray

3
@ArsenZahray、くそー。ただし、便利な関数を作成してのように使用できますconsole.watch(obj, 'someProp')
katspaugh

5
これはwindow.location、セキュリティ上の理由など、組み込みのプロパティでは機能しません。
qJake 2014年

1
DOM要素のセッターをデバッグするには、このパターンを少し変更する必要があります。詳細については、mnaoumov.wordpress.com / 2015/11/29 /…をご覧ください
mnaoumov 2015年

@katspaugh私はなぜこれが必要なのか尋ねることができますobj._someProp = obj.someProp;、それはあなたがアーカイブしようとしているものとは無関係であるようです(おそらく私は何かが足りないためです)
Victor

109

2016.03を編集:Object.observeChrome 50で廃止され、削除されました

2014.05を編集:Object.observeChrome 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

コールスタックを表示するには、開発ツールで「非同期コールスタック」オプションを有効にする必要があります。

クロム非同期呼び出しスタック


元の回答(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)では、それをWebサイトに挿入する必要があります(たとえば、ソースを手動で編集できない場合はFiddlerを介して)。悲しいことに、Firebugから定義された関数debuggerは中断しないようです(または構成の問題ですか?その場合は修正してください)がconsole.log機能します。

編集:

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

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

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


1
ちなみに、カスタムコードでデバッガを打つことができないということはFirebugは1.8と1.9の間の回帰であるようだ。問題は5757 - >重複の問題5221
jakub.g

1
@ColeReedゲッターで取得するには、値をどこかに保存する必要があります。oObj[sProp]ゲッターが無限再帰に入るので、それをに格納することはできません。Chromeでお試しくださいRangeError: Maximum call stack size exceeded
jakub.g 2013

1
私のような「Dとして、これを追加するasyncチェックボックスは、このアプローチにとても黄金です: html5rocks.com/en/tutorials/developertools/async-call-stack
CNP

1
@PhiLho async@cnpが書いたチェックボックスを使用してスタックを確認することができます。私の更新を参照してください
jakub.g

1
この回答を更新する必要があります:Object.observe廃止予定で、間もなく削除されます:chromestatus.com/features/6147094632988672
Amir Gonnen

79

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

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


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

breakOn(myObject, 'myProperty');

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


5

これは、目的がまさに次のとおりである新しい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);

ここで、代わりにoriginalObjectを提供するwrappedObjectを使用し、ブレーク時にコールスタックを調べます。


追跡された場合以外に失敗しないように、プロキシsetは戻る必要がありtrueます。
keaukraine

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

1

このソリューションの独自のバージョンを作成し、それを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)

-2

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

したがって、カスタムライブラリやソリューションはもう必要ありません。インスペクタでDOM要素を右クリックし、[ブレークオン]-> [属性の変更]を選択するだけです。


10
彼は、DOM属性値の変更ではなく、(jsオブジェクト)プロパティの変更を求めました
Z. Khullah

1
@Ivicaこれは良いテクニックですが、ここに置くのは間違っています。コメントとしては問題ありませんが、回答としては問題ありません。
bnieland
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.