2016-08-06 1 views
-1

ここでは、javascriptのプロトタイプ継承を使用してDOM要素からCSSプロパティを収集しています。 elem配列はDOMノードに対応するオブジェクトを含み、各オブジェクトはstyleフィールドを持ち、各elem[x].styleもオブジェクトです。 elem[x].styleオブジェクトはDOMツリー階層を繰り返し、__proto__で接続されています。 rootStyle変数は、すべてのelem[x].styleプロトタイプチェーンのルートとして機能します:ブラウザでjavascript __proto__を使用すると、実装されたアルゴリズムの一部として自然になります

var rootStyle = {}, 
    elem = [{}, {}, {}]; 

rootStyle.__proto__ = null; 
rootStyle.fontSize = '14px'; 

elem[0].style = {}; 
elem[0].style.__proto__ = rootStyle; 
elem[0].style.fontWeight = 'bold'; 
elem[0].className = 'my-elem-123'; 

elem[1].style = {}; 
elem[1].style.__proto__ = rootStyle; 
elem[1].style.fontStyle = 'italic'; 
elem[1].className = 'my-elem-456'; 

elem[2].style = {}; 
elem[2].style.__proto__ = elem[1].style; 
elem[2].style.textDecoration = 'underline'; 
elem[2].className = 'my-elem-789'; 
... 
// later in the code 
var cssCode = [], 
    i, len = 3; 
for(i = 0; i < len; i++) { 
    cssCode.push('.' + elem[i].className + '{' + getCssRules(elem[i]) + '}'; 
} 

function getCssRules(elem) { 
    var result = [], 
     cssProperty, cssValue; 
    for(cssProperty in elem.style) { 
     // No hasOwnProperty check! 
     // Here (and in for..in loop) happens the lookup magic that I need 
     cssValue = elem.style[cssProperty]; 
     result.push(cssValue + ':' + cssProperty + ';'; 
    } 
    return result; 
} 

そして、ここで述べたように:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto、私はので、パフォーマンスへの影響のオブジェクトのプロトタイプを変更しないでください。

内部的には、オブジェクトのキー値ルックアップは多くの操作に変わりますが、これは管理言語ですが、ここでの操作にはオーバーヘッドがあります。クレイジー深さのプロトタイプチェーンを作っていないなら、プロトタイプチェーンルックアップのスピードは、 "シングルステップ"オペレーションのスピードに匹敵するはずです。つまり、O(1)の複雑さに近くなります。私の忠誠心が、そのような振る舞いを持つデータ構造を必然的に必要とするならば、 "__proto__の設定が悪い"という理由だけで、私自身のチェーンルックアップや完全に異なる解決策を実装するのは難しいです。

だから、__proto__の場合、または良い/悪い使い方は何ですか?

私はこのような elem配列内の実際のDOMノードへの参照を格納した場合どうなりますか

elem[0].domNode = document.body.childNodes[0]; 
elem[1].domNode = document.body.childNodes[1]; 
elem[2].domNode = elem[1].domNode.childNodes[0]; 

それは悪い、良いですか、重要ではありませんカスタムプロトタイプチェーンを持つオブジェクトをリンクするために、そして持つオブジェクトジェネリックプロトタイプチェーン、エンジンの最適化はここで失敗しますか?

を追加しました。これですべてが手に入りました。 __proto__を設定すると混乱するものはすべて、正確に__proto__のリファレンスを変更することです。それは悪いことを引き起こします(最初のコメントのリンクを参照)。私たちは本当に受け入れられた答えの構文に固執すべきです。まず、空のプロトタイプそのものが原因で悪いことが起こり、最適化のためにjavascriptエンジンに必要なメンバーが不足していると私は考えました。

+1

[なぜ性能の悪いオブジェクトのプロトタイプに変異があるのですか?](http://stackoverflow.com/questions/23807805/why-is-mutating-the-prototype-of-an -object-bad-for-performance)には、興味のある情報と引用があります。 – noppa

答えて

4

だから、__proto__の場合、または良い/悪い使用法は何ですか?

__proto__、あなたのコードではそうする必要がない設定ため良いユースケースがあるかどうかはともかく。代わりに:なしプロトタイプを持つルートの作成

rootStyle = Object.create(null); 

はそのプロトタイプとしてrootStyleを使用してオブジェクトを作成:

その他の変更を加えることなく、あなたのコードの先頭にそれを適用する
elem[0].style = Object.create(rootStyle); 

を:

var rootStyle = Object.create(null),   // ** 
    elem = [{}, {}, {}]; 

rootStyle.fontSize = '14px'; 

elem[0].style = Object.create(rootStyle);  // ** 
elem[0].style.fontWeight = 'bold'; 
elem[0].className = 'my-elem-123'; 

elem[1].style = Object.create(rootStyle);  // ** 
elem[1].style.fontStyle = 'italic'; 
elem[1].className = 'my-elem-456'; 

elem[2].style = Object.create(elem[1].style); // ** 
elem[2].style.textDecoration = 'underline'; 
elem[2].className = 'my-elem-789'; 
elem[0].domNode = document.body.childNodes[0]; 
elem[1].domNode = document.body.childNodes[1]; 
elem[2].domNode = elem[1].domNode.childNodes[0]; 

elemインスタンスのプロトタイプチェーンの性質は、あなたがしなければ何が起こるかの質問に完全に無関係です:私はこのようなelemは、アレイ内の実際のDOMノードへの参照を格納した場合どうなりますか上記。

上記の場合、「何が起こりますか」に対する答えは次のとおりです。珍しいことはありません(IEの古いバージョンを扱っている場合を除きます)。これは要素の別の参照です。その場合、document.bodyの最初の子を削除した場合は、それを参照するのを中止するまでスッキリされませんが、それはあなたと同じです他のオブジェクトへの参照を維持してください(IEの古いバージョンについて話していない場合)。その上


三ノート:

  1. あなたは、既存オブジェクトのプロトタイプを変更バックステップし、あなたの全体的なデザインを見てする必要があると思う場合。これを行う必要は非常に珍しいことです。通常は、正しいタイプの新しいオブジェクトを作成し、関連する情報をコピーするという設計の観点から優れています。 (私は10年以上のJavaScriptプログラミングでこれをやっていたことはありませんでした。もしそれを古典的なOOP用語[C++、Java]に入れていたのであれば、オブジェクトを作成した後にオブジェクトのタイプを変更するオブジェクトのプロトタイプを変更するCatが、今はDogにそれを変更したい。ちょうどそれを行うには、実際の必要性を持って無視できるほど稀である。)

  2. あなたはMDNに見てきたように、JavaScriptエンジンが最適化されているものではないため、異常値の場合はオブジェクトの最適化を吹き飛ばし、プロパティへのアクセスが遅くなる傾向があります。その減速が何らかの方法で行われているかどうかは、もちろんはユースケースからユースケースに変わります。それが問題になる前に心配するのは早すぎる最適化であろう。現代のJavaScriptエンジンで

  3. 、あなたはを行う場合、プロトタイプを変更するための本物のユースケースを持ってObject.setPrototypeOf経由ではなく、__proto__に割り当てるそれを行います。

+0

しかしこれは次のように見えます:C++はOOP言語ですが、カスタムクラスを作成することはお勧めしません。それとも、プロトタイプを変更するだけで動作が遅いのですか? (それは常にそれを念頭に置いておくと問題ではありません)そして、オブジェクトの最適化を吹き飛ばす場合は、それは間違いありません。それとも、非常に深いプロトタイプ鎖だけを意味するのでしょうか? – user3198882

+0

私はそれを得るように見えますが、私はカスタムプロトタイプを使うことができますが、答えからObject.create(null)と他の構文を使用することをお勧めします。どのような最適化について - 私は一般的なプログラミングミス(念頭に置いて、プロトタイプのチェーンのルックアップが動作している)をしない場合、悪いことは起こりません。 – user3198882

+1

@ user3198882:*存在する*オブジェクトのプロトタイプを変更する必要がある非常に、非常に、非常に少数の状況があります。最初の場所に、 'Object.create'またはコンストラクタ関数を使用して、正しいプロトタイプを持つオブジェクトを作成してください。 –

関連する問題