V8デベロッパーはこちら。
はい、最初のバージョンは一般的には価値あるベストプラクティスです。
その理由は、ではなく、というオブジェクトの作成自体が高速になるためです。逆に、作業をしないコンストラクタは、何らかの作業を行うコンストラクタよりも少なくとも少し速くなることは明らかです。
アプリケーションのすべてのFoo
オブジェクトが同じ「シェイプ」を持つことを保証するため、最初のバージョンが推奨される理由は、2番目のバージョンでは、.bar
プロパティとその他のもの't。プロパティは時々存在し、時にはJavaScriptエンジンを使用可能な最速の状態/コードパスから離れる傾向がありません。そのような特性が複数ある場合、効果はより大きくなる。例として
:
class Foo() {
constructor() {}
addBar(x) { this.bar = x; }
addBaz(x) { this.baz = x; }
addQux(x) { this.qux = x; }
}
var foo1 = new Foo(); foo1.addBar(1);
var foo2 = new Foo(); foo2.addBaz(10); foo2.addBar(2);
var foo3 = new Foo(); foo3.addQux(100); foo3.addBaz(20); foo3.addBar(3);
function hot_function(foo) {
return foo.bar; // [1]
}
hot_function(foo1);
hot_function(foo2);
hot_function(foo3);
ラインでは、コンストラクタのこのバージョンでは、[1]
とマークは、少なくとも3つの異なる形状のオブジェクトが見られます。したがって、JavaScriptエンジンはオブジェクト内の少なくとも3つの異なる場所にプロパティbar
を見つけます。内部実装の詳細によっては、毎回すべてのオブジェクトのプロパティを検索する必要があるかもしれません。あるいは、以前に見たオブジェクトシェイプをキャッシュできるかもしれませんが、いくつかのキャッシュはキャッシュするよりも高価です。 。 コンストラクタがundefined
にすべてのプロパティを初期化していた場合、ここに入ってくるfoo
オブジェクトはすべて同じ形状になり、bar
プロパティは常に最初のプロパティになり、エンジンはこの非常に単純なケースを処理するために。
ちょうどそのようなロードではなく、addBar()
は既存のプロパティを上書きするか(非常に高速)、新しいプロパティを追加する必要がありますか(割り当てが必要な場合があります)オブジェクトをコピーする)、または両方のケース間で動的に決定する必要があります(もちろん、最も遅い)。
もう1つの効果は、一意のオブジェクトのそれぞれの形状がある量の内部メタデータを必要とすることです。不必要に異なるオブジェクト形状を避けることで、メモリを節約できます。
もちろん、このような小さな例では、効果は小さくなります。しかし、それぞれ数十のプロパティを持つ何千ものオブジェクトを持つ大きなアプリがあれば、それは本当に大きな違いを生むことができます。誤ったマイクロベンチマークに注意してください!
一方で、それを測定してみることはできますが、最初のバージョンがどうにかして2番目のバージョンよりも優れていると思う理由は明確ではありません。 – pvg
なぜあなたは最初のバージョンが候補者だと思いますか? –
はい、一般的な最適化ですが、実際に違いを生むかどうかは、インスタンスで行う操作の種類によって大きく異なります。 – Bergi