JavaScriptでオブジェクトを適切に記録する方法?


私はコンソールAPIについて話しましたmy previous articles . しかし、私はそれをカバーしていない1つの特に重要な詳細があった-オブジェクトのログ記録の問題.だから、問題とどのように適切に解決するのですか?

何が問題ですか。


以前にコンソールにオブジェクトを記録したのでしょう?
const obj = { key: "value" };

console.log(obj);
今、私はJSのすべてがオブジェクトであることをあなたに思い出させたくありません.ここは重要ではない.我々はオブジェクトを適切に記録することに興味があります.
上記のオブジェクトを使用することによって最も基本的な方法を見ることができますconsole.log() . 私は間違って取得しないでください-それは完全にそれを行うには罰金ですが、それは1つの基本的な欠陥-動的評価しています.

ダイナミック評価


コンソールウィンドウに入ると、あなたのオブジェクトは拡張可能なツリーの形できれいにログオンします.あなたが中で見つけることができるものの少しのプレビューも、あります.

しかし、プレビュー自体は、呼び出しの瞬間から値(またはそれらの小さな部分)を示していますconsole.log() , あなたが手動で展開しなければならない木は、同じ規則に従いません.
const obj = { key: "value" };

console.log(obj);
setTimeout(() => {
  obj.key = "changed";
}, 2000);
上のスニペットを使えば、ログインしているオブジェクトを2秒以内に拡大することができなければ、key コンソールのプロパティは"changed" . これはツリーを拡張した時点で動的に評価される値のためです.ただし、その時点から、コード内の値を変更しても、ログは同じままです.

このことはあなたにとってコンサートではないかもしれません.しかし、オブジェクトのプロパティの現在の状態が重要なコードで動作する場合は、ログがそれらが呼び出された瞬間のより代表的なものとなります.

複写


そのような問題の最も明白な解決策は、単にログオブジェクトをコピーすることです.確かに、追加のメモリを少し取ることができますが、デバッグ段階では、それは重要ではない.
を実装するブラウザECMAScript 6 (ES6) 標準的には、Object.assign() これはまさに必要なものです.
// ...
console.log(Object.assign({}, obj));
Object.assign() 渡されたオブジェクトのすべてのプロパティを最初のものに割り当て、それを返します.これは有効な1つのライナーを作ります.そして、我々はすべての特性(複数のオブジェクトからさえ)を一つの標的オブジェクトにコピーします.このように、我々はログが将来変更されないことを確認します.
もう一つの、より良い解決策は、広げられた構文です... ) 少し悪いcross-browser support , しかし、以下のコードを書くのは基本的に同じです.
// ...
console.log({...obj});
ここでは、オブジェクトからの展開/スプレッド/コピーのプロパティobj 新しいオブジェクトリテラルに演算子が使用されます.

ディープコピー


今、単一の次元の“フラット”オブジェクトだけで動作する場合は、さらにそれ以上を見て必要があります-上記のソリューションは、すべてのニーズを満たす必要があります.
ただし、オブジェクトは値の代わりに参照によってコピーされるため、拡張構文もObject.assign() 入れ子になったオブジェクトで動作します.確かに、一番上の値はすばらしいです、しかし、入れ子にされたオブジェクトのすべての特性はまだダイナミックに決定されます(すなわち、あなたがそれらを広げたあと).
この問題を解決するために、私たちが以前行ったことと似たテクニックを使って、深いコピーを使う必要があります.基本的に、必要に応じてすべてのプロパティをコピーし、オブジェクトを明示的にコピーする必要があります.
また、循環参照のようなケースや、配列のような参照値によってコピーされたものを考慮しなければならないことに留意してください.したがって、単にユーティリティライブラリを使用するように簡単ですLodash , 代わりに、独自の機能全体を実装する.
// ...
console.log(_.cloneDeep(obj));
ここでは、我々は cloneDeep() LodDashから目的のオブジェクトを深くコピー/クローン化する方法.
あなたがしたくない場合はimport あるいはnpm install ライブラリ全体を使用して、常にメソッドを使用してNPM package .

JSON


オブジェクトをコピーするときに素晴らしいツリーの書式設定とすべてのその空想のものを維持したいという大きなオプションです.しかし、すべての必要ないくつかの基本的な情報です.JSON.stringify() 良い選択肢かもしれない.
// ...
console.log(JSON.stringify(obj, null, 1));
あなたはそれを知らないかもしれないJSON.stringify() オプションの引数を受け取ります.私は、すでに私の1つでこれについて話しました"Tricks" articles . 第1のものは処理された値を変えることができる代わるものです、一方、第2のものはつくられたストリングの中で挿入するスペースの数として使われます.以下のようにして終わります.

循環参照


現在、一方JSON.stringify() 通常の入れ子になったオブジェクトに対しても、うまく配列を扱うことができます.
const obj = {key: "value"};
obj.reference = obj;
そこを得るために簡単な方法があります-代用機能.ご覧ください.
// ...
const log = value => {
  const cache = [];

  console.log(JSON.stringify(value, (key, value) => {
      if (typeof value === "object" && value !== null) {
        if (cache.indexOf(value) !== -1) {
          return "[[circular]]";
        }
        cache.push(value);
      }
      return value;
  }, 1));
};

log(obj);
我々がここに持っているものは本質的にcloneDeep() -エッジケース処理のようにJSON.stringify() . 実際の値を表示する代わりに"[[circular]]" 文字列を返します.

必要に応じて、次に追加のコードのビットを使用すると、また、循環参照を表示するための完全なサポートを実装することができます.
再び、オブジェクトをコピーすることはより良いオプションであるかもしれませんcloneDeep() メソッド.しかし、最終的には、それは単なる好みの問題だと思います.

ボトムライン


コンソールロギングのような単純なものさえ時々複雑になることができるようです.まあ、それはプログラミングの仕事の非常に性質にあると思います.とにかく、私はこの記事が役に立つことを願って、それはあなたがさらに優れたデバッグの芸術を得るのを助ける!
あなたがポストを好きであるならば、それを共有することを考えて、私についてFacebook . 興味があれば、私もチェックアウトをお勧めします.再び、この作品を読んでくれてありがとうございます.