web-dev-qa-db-ja.com

プロパティを列挙できないようにすることの利点は何ですか?

列挙可能性は、プロパティの3つの属性(書き込み可能性、列挙可能性、および構成可能性)の1つです。私の質問は次のとおりです。

  • JavaScriptでプロパティを列挙できないようにすることの利点は何ですか?列挙できないようにすることでプロパティを非表示にしていることは知っていますが、プロパティを非表示にすることの利点は何ですか?
  • 列挙できないプロパティにアクセスできますか?はいの場合、それらを列挙できないようにすることの利点は何ですか?
  • オブジェクトの事前定義されたすべてのプロパティが列挙不可として設定されていますか?配列のpopおよびPushプロパティが列挙できない場合など?
46
Anshul

主な利点は、_for in_やObject.keys()などのオブジェクトのプロパティを列挙するときに表示される内容を制御できることだと思います。

MDNはそれを_Object.defineProperty_でうまく説明しています: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty

したがって、通常、古いブラウザでサポートされていないメソッドのポリフィルなど、メソッドをObjectに追加する場合は、_.prototype_を変更します。しかし、それはプロパティを列挙可能にし、ループ/キーコレクションで返されるものを台無しにします(_.hasOwnProperty_を使用せずに...誰もが使用するわけではありません)。

したがって、次のようなものの代わりに:

_Object.prototype.myMethod = function () {
    alert("Ahh");
};
_

_Object.defineProperty_を使用して、列挙できないように明示的に指定できます。

_Object.defineProperty(Object.prototype, 'myMethod', {
    value: function () {
        alert("Ahh");
    },
    enumerable: false
});
_

そうすれば、たとえばfor (var key in obj)を使用する場合、「myMethod」は列挙される項目ではなく、_.hasOwnProperty_の使用について心配する必要はありません。これに関する主な問題は、一部のブラウザがもちろんそれをサポートしていないことです: http://kangax.github.com/es5-compat-table/ そして、すべてのライブラリ/コードがそれを使用しているわけではありません、そのため、常に外部ライブラリ/コードを使用して正しく使用できるとは限りません。

列挙できないプロパティにはいつでもアクセスできます。オブジェクトのプロパティを列挙するときに表示されないだけです。これが重要なポイントです。

そして、オブジェクトのすべての「事前定義された」プロパティは列挙できないと私は信じています。つまり、私は実際にはネイティブプロパティのみを意味し、必ずしも継承または作成されるとは限りません。したがって、あなたの例では、popPushnotで列挙されますが、_Array.prototype.indexOf_は、そのメソッドをサポートしていない古いブラウザでのポリフィル...もちろん、上記の例のように_Object.defineProperty_を使用することで回避できます。もう1つの例は、列挙されていないlengthプロパティです。

一般的な例を次に示します。 http://jsfiddle.net/aHJ3g/

_Object.keys_の使用と定義は重要です: "_for-in_ループによって提供されるのと同じ順序で、指定されたオブジェクト自体の列挙可能なプロパティの配列を返します(違いは_for-in_ループはプロトタイプチェーンのプロパティも列挙します)。」 --MDNから- https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys

41
Ian

私が見ているもう1つの大きな利点は、オブジェクトのプライベートプロパティがパブリック名前空間を汚染するのを防ぐことです。

Cosmosという強力なライブラリを作成して公開したとします。ユーザーはNodeインタープリターを起動し、コンストラクターを呼び出してその新しいインスタンスを作成します。

var Cosmos = require('Cosmos');
var cosmos = new Cosmos('my empire');

これで、ユーザーはcosmosと入力し、Enterキーを押すだけで、サポートされているパブリックAPIを確認できます。 2つのうちどちらをユーザーに見せたいですか?

{ name: 'my empire',
  grow: [Function: grow],
  addStar: [Function: addStar],
  beautify: [Function: beautify],
  implode: [Function: implode],
  destroy: [Function: destroy] }

OR

{ _age: 25000,
  _size: 35000,
  _destroyed: false,
  name: 'my empire',
  _numStars: 200,
  _init: [Function: _init],
  grow: [Function: grow],
  _grow: [Function: _grow],
  addStar: [Function: addStar],
  _checkStatus: [Function: _checkStatus],
  beautify: [Function: beautify],
  implode: [Function: implode],
  destroy: [Function: destroy] }
12
Gary Chang

列挙できないプロパティの実際の実用的な使用法はありません

これは私が自分自身に尋ねようとしていた非常に素晴らしい質問です。少し調査した結果、私の結論は次のとおりです。この機能は間違いなく必要ありません。

バックグラウンド

列挙できないプロパティが何であるかを知らない人のために、以下のリンクを見てください:

あなたは実際にそれらを列挙することができます

これは奇妙ですが、「列挙できない」プロパティを列挙することは実際には非常に簡単です。

_// start with some enumerable properties
const foo = {
  a: 1,
  b: "yes",
  c: function () {}
}

// then add a couple of non-enumerable ones
Object.defineProperty(foo, "d", { value: "hiding here", isEnumerable: false });
Object.defineProperty(foo, "e", { value: 42, isEnumerable: false });

const enumerableProperties = Object.keys(foo).join(", ");
console.info("Enumerables: " + enumerableProperties);
// Enumerables: a, b, c

const ownPropertyNames = Object.getOwnPropertyNames(foo).join(", ");
console.info("Enumerating also the non-enumerables: " + ownPropertyNames);
// Enumerating also the non-enumerables: a, b, c, d, e_

それらを列挙できないと彼らが言うとき、彼らは特にObject.keys()と_for..in_ループ、そしてそれらが列挙可能なプロパティのみを返すという事実を参照しています。 getOwnPropertyNames() の場合はそうではありません。

使用しないでください

さて、同じページにいるので、私にはあいまいな言語機能のように見えます。これは、コードを読みにくく、理解しにくくするだけです。本当に合法的な使い方は考えられません。

既存の両方の回答は、2つの非常に具体的なケースについて話します。

  1. コードがhasOwnProperty()またはObject.keys()。その場合は、非常に古いコード(つまり、今日のベストプラクティスに準拠していないレガシーコード)をサポートする必要があります。申し訳ありませんが(今日でも多くのシステムが維持されていることはわかっていますが)残念ながら、その場合に該当します);

  2. これは、パブリックライブラリを開発していて、パブリックに面したオブジェクトをクリーンに保ちたい場合に役立ちます。それは非常に具体的ですよね?また、そのためだけに、ライブラリのコードをいくつかのdefinePropertyで汚染したくないと思います。さらに、 プライベートフィールド があるため、その答えはすぐに古くなっています。最後に、答えは、パブリック名前空間もクリーンに保つと述べていますが、それは真実ではありません。名前空間は、プロパティではなく、オブジェクト自体によって汚染されています。

したがって、古いコードを維持しなければならないという不幸な立場にない限り、これを使用することを忘れてください。あなたはそれを必要としない、私を信じてください。オブジェクトを列挙するときにいくつかのプロパティを非表示にする必要がある状況に陥った場合は、確かにそれを間違ってモデル化しています。これらのプロパティを別のオブジェクトに配置するだけです。彼らはあなたが持っている他のプロパティと一緒に暮らすことを意図していません。これにより、コードがよりクリーンで理解しやすくなります。これは、コードを作成するときに達成するために努力する必要がある最も重要なことの1つです。

より詳細な記事があります 列挙できないプロパティが今日重要な役割を果たしていないという考えを裏付けています。

1
Lucio Paiva
  • プロパティを列挙できないようにすることで、引き続きアクセスできます。ただし、オブジェクトにfor inループを適用すると、列挙不可能なプロパティは繰り返されません。
  • 最初のポイントを参照してください
  • 継承されたプロパティは列挙可能です(列挙可能とマークされている限り)

    var x = {a:1, b:2} // a and b are enumerable properties by default
    x.propertyIsEnumerable("toString") // returns false, because it is not marked as enumerable
    var y = Object.create(x);
    y.c = 3;
    for(p in y) console.log(p); // this loop will print c, a and b but not toString
    
0
daniatic