Nicholas Zakasによるオブジェクト指向JavaScriptの原則を読んだ後、 Object.create()を使用してnullから継承されたオブジェクトを作成することについてのアドバイスに出会いました。 そのようなオブジェクトはObject.prototypeを継承しないため、 Object.prototypeメソッドを持ちません。 Zakazは、これを使用して安全なキャッシュオブジェクトを作成できると提案しました。 私はこのアイデアが本当に好きでしたが、 MDN ( Mozilla Developer Network )によると、 Object.create()は IE9までサポートされていません。 ただし、サーバー上のNode.jsでは、このメソッドは完全にサポートされています。
JavaScriptでオブジェクトを作成すると、このオブジェクトはObject.prototypeメソッドを自動的に継承します。 このため、オブジェクトは、「 in 」演算子を使用してキーの存在を確認するために「危険」になります。この場合、「 valueOf 」や「 toString 」などのオブジェクトメソッドがあるためです(プロトタイプの階層を登った結果)。 したがって、人々 は「 in 」演算子の代わりにObject.prototype.hasOwnProperty()を使用することを好みます。
ただし、 Object.create()を使用してnullから継承されたオブジェクトを作成する場合、継承階層はありません。 そのため、このオブジェクトは、システムによって事前定義されたメソッドを含まないオブジェクトに非常に近くなります。
仕組みを確認するには、次のNode.jsスクリプトをご覧ください。
// . // . , // , . var safeCache = Object.create(null); // , - . ["hasOwnProperty", "toString", "valueOf", "constructor", "__proto__"] .forEach( function iterator(key, index) { console.log("[ %s ] exists: %s", key, ( key in safeCache )); } );
このスクリプトを実行すると、次の結果が得られます。
[ hasOwnProperty ] exists: false [ toString ] exists: false [ valueOf ] exists: false [ constructor ] exists: false [ __proto__ ] exists: true
ご覧のとおり、 Object.prototypeのすべての「標準」プロパティが欠落しています。 存在する唯一の魔法のプロパティは__proto__です。 これにより、与えられたオブジェクトのキーを盲目的に追加、削除、およびチェックする最も近い機会が得られます。 これは、可能な限り単純なコードの可能性に対するリスクの許容レベルだと思います。
もちろん、「単純なコード」と言っても、違いはそれほど重要ではありません。 特定の何かを見るために、キーと値のペアのストレージをカプセル化する最も単純なキャッシュクラスを作成しようとしました。 最初のクラスは、 nullから継承したオブジェクトに実装されたストレージです。 2番目のクラスは、通常のJavaScriptオブジェクトに実装されたリポジトリです。
// // null, , , // . function SafeCache() { var cache = Object.create(null); // Reveal the public API. return ({ get: get, has: has, remove: remove, set: set }); // --- // PUBLIC METHODS. // --- function get(key) { return ( cache[key] ); } function has(key) { return ( key in cache ); } function remove(key) { return ( delete( cache[key] ), this ); } function set(key, value) { return ( cache[key] = value, this ); } } var safeCache = new SafeCache() .set("foo", "Bar") .set("hello", "world") .set("beep", "boop"); console.log("## Safe Cache ##"); console.log(safeCache.has("foo")); console.log(safeCache.has("meep")); console.log(safeCache.has("valueOf")); console.log(safeCache.has("__proto__")); // , // // , , . function SaferCache() { var cache = {}; // Reveal the public API. return ({ get: get, has: has, remove: remove, set: set }); // --- // PUBLIC METHODS. // --- function get(key) { if (has(key)) { return ( cache[key] ); } } function has(key) { return ( cache.hasOwnProperty(key) ); } function remove(key) { return ( delete( cache[key] ), this ); } function set(key, value) { return ( cache[key] = value, this ); } } var saferCache = new SaferCache() .set("foo", "Bar") .set("hello", "world") .set("beep", "boop"); console.log("## Safer Cache ##"); console.log(saferCache.has("foo")); console.log(saferCache.has("meep")); console.log(saferCache.has("valueOf")); console.log(saferCache.has("__proto__"));
このコードを一目見ただけでも、違いに気付かないかもしれません。 しかし、それはget ()メソッドとhas()メソッドにあります。
正直に言うと、キャッシュの実装をカプセル化する場合、最も信頼性の高い.hasOwnProperty()または、たとえば、混合キーを使用できます。 ただし、不完全なキャッシュで作業していない場合、 nullから継承されたオブジェクトを使用することは、コードの単純さとリスクのバランスをとる合理的な方法です。 上記のいずれにも当てはまらない場合、 nullから継承したオブジェクトをJavaScript / Node.jsで作成できることを知っておくと便利です。