列挙可能性は、プロパティの3つの属性(書き込み可能性、列挙可能性、および構成可能性)の1つです。私の質問は次のとおりです。
pop
およびPush
プロパティが列挙できない場合など?主な利点は、_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/ そして、すべてのライブラリ/コードがそれを使用しているわけではありません、そのため、常に外部ライブラリ/コードを使用して正しく使用できるとは限りません。
列挙できないプロパティにはいつでもアクセスできます。オブジェクトのプロパティを列挙するときに表示されないだけです。これが重要なポイントです。
そして、オブジェクトのすべての「事前定義された」プロパティは列挙できないと私は信じています。つまり、私は実際にはネイティブプロパティのみを意味し、必ずしも継承または作成されるとは限りません。したがって、あなたの例では、pop
とPush
はnotで列挙されますが、_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
私が見ているもう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] }
これは私が自分自身に尋ねようとしていた非常に素晴らしい質問です。少し調査した結果、私の結論は次のとおりです。この機能は間違いなく必要ありません。
列挙できないプロパティが何であるかを知らない人のために、以下のリンクを見てください:
これは奇妙ですが、「列挙できない」プロパティを列挙することは実際には非常に簡単です。
_// 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つの非常に具体的なケースについて話します。
コードがhasOwnProperty()
またはObject.keys()
。その場合は、非常に古いコード(つまり、今日のベストプラクティスに準拠していないレガシーコード)をサポートする必要があります。申し訳ありませんが(今日でも多くのシステムが維持されていることはわかっていますが)残念ながら、その場合に該当します);
これは、パブリックライブラリを開発していて、パブリックに面したオブジェクトをクリーンに保ちたい場合に役立ちます。それは非常に具体的ですよね?また、そのためだけに、ライブラリのコードをいくつかのdefineProperty
で汚染したくないと思います。さらに、 プライベートフィールド があるため、その答えはすぐに古くなっています。最後に、答えは、パブリック名前空間もクリーンに保つと述べていますが、それは真実ではありません。名前空間は、プロパティではなく、オブジェクト自体によって汚染されています。
したがって、古いコードを維持しなければならないという不幸な立場にない限り、これを使用することを忘れてください。あなたはそれを必要としない、私を信じてください。オブジェクトを列挙するときにいくつかのプロパティを非表示にする必要がある状況に陥った場合は、確かにそれを間違ってモデル化しています。これらのプロパティを別のオブジェクトに配置するだけです。彼らはあなたが持っている他のプロパティと一緒に暮らすことを意図していません。これにより、コードがよりクリーンで理解しやすくなります。これは、コードを作成するときに達成するために努力する必要がある最も重要なことの1つです。
より詳細な記事があります 列挙できないプロパティが今日重要な役割を果たしていないという考えを裏付けています。
継承されたプロパティは列挙可能です(列挙可能とマークされている限り)
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