10

オブジェクトが作成されるたびにプロパティを初期化する必要がなくなるため、オブジェクトのプロトタイプに常に値の型を持つプロパティを設定しています。

それ以来、私はいくつかのデバッグを行っており、そのプロトタイプ プロパティの値が変更される場合、新しいプロパティがオブジェクトに割り当てられ、プロトタイプのプロパティはそのままであることがわかりました。

var o = function () {

};

o.prototype.x = 0;

o.prototype.setX = function(x) {
    this.x = x;
};

var obj = new o();
obj.setX(1);
console.log(obj);

// o {x: 1, x: 0, setX: function}

私の質問は、prototype プロパティの値が変更される可能性が高いことがわかっている場合、プロトタイプでそれを設定し、オブジェクトの作成時に初期化する必要がないという利点があるということです。

私が言いたいのは、それが別の値に変更されたとき、新しい値を既存のオブジェクトに割り当てなければならないということです。最初にプロトタイプに設定するという最初の利点が失われます! さらに、同じものに対して 2 つのプロパティがあり、1 つはオブジェクトに、もう 1 つはプロトタイプにあることを意味します。

これがそれを行う方法であるとグーグル開発者に書かれていますが、私にはよくわかりません。

プロトタイプで値型プロパティを設定する必要があるのはいつですか? また、値が変更されることがわかっている場合、実際のパフォーマンスは向上しますか?

4

2 に答える 2

8

私は実際にこの種のベンチマークを行いました.メモリが機能する場合、プロトタイプモデルは通常、値をオブジェクトに直接割り当てるよりも遅くなります. 例外は、インスタンスの大部分が同一であり、インスタンス化がプロパティ アクセスよりもはるかに頻繁に発生する場合です。

したがって、次のようにオブジェクトを定義すると:

var Class = function() {};
Class.prototype.p1 = 1;
Class.prototype.p2 = 1;
Class.prototype.p3 = 1;

プロパティを各オブジェクトにコピーすることで、インスタンス化時のパフォーマンス ヒットを回避できます。しかし、そのパフォーマンスは、それらのプロパティがアクセスまたは変更されると頭角を現します。また、これらのプロパティを変更せずにアクセスすると、アクセスするたびにプロトタイプ チェーンをたどるというパフォーマンス ヒットが発生します (ローカル インスタンスにコピーされないため)。しかし、多くのプロパティがあり、インスタンスごとに少数のプロパティにしかアクセスできない場合は、おそらくこれが理想的です。

for (var i = 0; i < 100000; i++) {
  var x = new Class();
  console.log(x.p1);
  // ignore p2-p99. we don't need them right now.
}

スペクトルの反対側では、少数のインスタンスでプロパティを何度も反復する必要がある場合は、プロトタイプ チェーンをたどるヒットを回避した方がよいでしょう。

var Class = function() {
  this.p1 = 1;
  this.p2 = 1;
  this.p3 = 1;
}

各インスタンスは、作成時に p1、p2、および p3 の独自のコピーを取得します。また、プロトタイプ チェーンは、それらのいずれかにアクセスするときに参照する必要はありません。

var instances = [
  new Class(), new Class(), new Class()
];

for (var i = 0; i < 1000000; i++) {
  console.log(instances[i % instances.length].p1);
  console.log(instances[i % instances.length].p2);
  console.log(instances[i % instances.length].p3);
}

後で時間があれば、後でこれをベンチマークして検証します。それまでは、私があなたに提供できるのは理論だけです!

補遺

プロトタイプを使用すると、必ずしもパフォーマンスに関連するわけではありませんが、2 つのメリットがあります。

1 つは、比較的静的なプロパティ (関数など) の場合、メモリを節約します。ほとんどのアプリケーションは、制限にぶつかることはありません。ただし、オフチェンジではこれが問題になるため、プロトタイプを使用してください。

2 つ目は、プロトタイプを使用すると、クラスの既存のすべてのインスタンスに関数とプロパティを割り当てることができることです。インスタンス レベルのプロパティで同じ偉業を達成するには、検索して反復する必要があります。

ベンチマーク

最新バージョンの FF と Chrome for OS X でのみ実行した最新のベンチマークに従って、単一層 (継承されていない) クラス定義に次の構文を使用しました。

プロトタイプ。*

function Class() {}
Class.prototype.a = 1;
Class.prototype.b = 2;
Class.prototype.c = 3;

これ。*

function Class() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

上記の 2 つの構文の間で、this.*構文は全体的に約 10.5% 高速に動作します。

継承のレベルを追加して、次を使用しました。

プロトタイプ。*

function Base() {}
Base.prototype.a = 1;
Base.prototype.b = 2;
Base.prototype.c = 3;

function Class() {}
Class.prototype = new Base();

これ。*

function Base() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

function Class() {
  Base.apply(this);
}

この場合、このprototype.*構文は全体で約 38.5% 高速であることがわかりました。this.*構文は、メンバ アクセスのブラウザ間で合計すると、まだわずかに高速でした。しかし、この利点は、インスタンス化の利点ほど顕著ではありませんでした。

また、継承へのハイブリッド アプローチのベンチマークも行いました。

function Base() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

function Class() {
}
Class.prototype = new Base();

全体として、構文よりも約 0.5% 高速に実行されましたprototype.*(おそらく重要ではありません)。ただし、興味深いことに、インスタンス化中はprototype.*構文よりも約 1% 遅くなりましたが、メンバー アクセス中は約 2% 高速でした。繰り返しますが、それほど重要ではありませんが、継承の深さが増すにつれて、これらの利点が拡大するかどうか疑問に思わずにはいられません。

もちろん、これらのベンチマークは十分に管理された環境で行われたものではないことに注意してください。私は、パフォーマンスの著しく広いギャップが重要であると見なす傾向があります. ただし、パーセンテージが低いのは、マシンの CPU 負荷が変動していることが原因である可能性が非常に高くなります。

とはthis.*いえ、継承が行われていない場合、クラスのインスタンス化よりもメンバー アクセスがはるかに一般的な場合には、 を使用することをお勧めします。もちろん、Web アプリのパフォーマンスを最大限に引き出す必要がない場合は、自分とチームにとってより直感的な構文を使用してください。ほとんどの Web アプリでは、オブジェクト構築スタイルの違いよりもはるかに大きなパフォーマンス ヒットが発生します。

たとえば、背景色の変更、

document.body.style.backgroundColor = 'blue';

...ベンチマークした最悪のコンストラクターをインスタンス化するよりも約70% 遅くなります。

于 2013-04-16T22:06:00.400 に答える
0

prototypeプロパティの値がオブジェクトのインスタンス化時に常に (またはほとんどの場合) 変更される場合、プロパティ値を に格納する利点はありません。値が複数のインスタンス間で共有されている場合にのみ利点があります。その場合、メモリ使用量は少なくなりますが、必ずしもパフォーマンスが向上するわけではありません。プロトタイプ チェーン をたどると、 で直接プロパティ ルックアップを実行するよりもコストがかかりobjectます。

于 2013-04-16T22:18:26.363 に答える