メソッドをすべてのオブジェクトに追加する必要はありません。使用するオブジェクトの種類だけを追加してください。文字列メソッドの場合は、String.prototype
すべての文字列に追加して定義することができます。
var obj = { "text" : "Hi" };
// We only want to add this method to strings.
String.prototype.addText = function(){
return this+' there!';
};
alert("OBJECT TEXT+method: " + obj.text.addText());
これにより、メソッドが列挙可能for..in
になることに注意してください。つまり、ループ内に表示されます。
Object.defineProperty
2010 年以降 (IE8 なし) のブラウザーのサポートのみを気にする場合はObject.defineProperty
、列挙できないようにプロパティを定義するために使用することを強くお勧めします。
var obj = { foo: 'bar' };
// Extending all objects this way is likely to break other scripts...
Object.prototype.methodA = function() { return 'A'; };
// Instead you can do extensions this way...
Object.defineProperty(Object.prototype, 'methodB', {
value: function() { return 'B'; },
// Prevent the method from showing up in for..in
enumerable: false,
// Allow overwriting this method.
writable: true,
// Allow reconfiguring this method.
configurable: true
});
for (var propertyName in obj) {
console.log(propertyName);
// Logs: "foo" and "methodA" but not "methodB"
}
上記のコードは、「foo」プロパティと「methodA」プロパティをログに記録しますが、「methodB」プロパティは列挙不可として定義したため、ログに記録しません。また、「toString」、「valueOf」、「hasOwnProperty」などの組み込みメソッドも表示されないことに気付くでしょう。これは、それらが列挙不能としても定義されているためです。
このようにして、他のスクリプトがfor..in
自由に使用できるようになり、すべてが期待どおりに機能するはずです。
特定のビルトインに戻る
特定のタイプのオブジェクトに対して列挙不可能なメソッドを定義することもできますObject.defineProperty
。たとえば、次の例では、配列に値が含まれている場合と含まれていない場合にcontains
返されるメソッドをすべての配列に追加します。true
false
Object.defineProperty(Array.prototype, 'contains', {
value: (function() {
// We want to store the `indexOf` method so that we can call
// it as a function. This is called uncurrying `this`.
// It's useful for ensuring integrity, but I'm mainly using
// it here so that we can also call it on objects which aren't
// true Arrays.
var indexOf = Function.prototype.call.bind(Array.prototype.indexOf);
return function(value) {
if (this == null)
throw new TypeError('Cannot be called on null or undefined.');
return !!~indexOf(this, value);
}
})(),
enumerable: false,
writable: true,
configurable: true
});
var colors = [ 'red', 'green', 'blue', 'orange' ];
console.log(colors.contains('green')); // => true
console.log(colors.contains('purple')); // => false
このメソッドは で定義したためArray.prototype
、配列でのみ使用できることに注意してください。他のオブジェクトでは使用できません。ただし、他の配列メソッドの精神では、配列のようなオブジェクトで呼び出すことができる十分な一般性で記述されています。
function foo() {
Array.prototype.contains.call(arguments, 5);
}
console.log(foo(1, 2, 3, 4, 5)); // => true
console.log(foo(6, 7, 8, 9, 10)); // => false
上記の呼び出しcontains
はarguments
機能しますが、イベントarguments
は真の配列ではありません。
ボイラープレートの単純化
を使用Object.defineProperty
すると、多くの機能が提供されますが、ほとんどの人が常に入力したくない追加のコードも大量に必要になります。ECMAScript 委員会が関数を定義したとき、それは理解されていましたが、彼らは、コードをよりきれいにするためにヘルパー関数を書くことができると想定していました。これを覚えておいてください。たとえば、いつでも次のようなことができます。
var define = (function() {
// Let's inherit from null so that we can protect against weird situations
// like Object.prototype.get = function() { };
// See: https://mail.mozilla.org/pipermail/es-discuss/2012-November/026705.html
var desc = Object.create(null);
desc.enumerable = false;
desc.writable = true;
desc.configurable = true;
return function define(constructor, name, value) {
if (typeof constructor != 'function'
|| !('prototype' in constructor))
throw new TypeError('Constructor expected.');
desc.value = value;
Object.defineProperty(constructor.prototype, name, desc);
}
})();
次に、次のことができます。
define(String, 'addText', function() {
return this + ' there!';
});
console.log('Hi'.addText()); // => "Hi there!"
このようなことを支援するために開発されたいくつかの小さなライブラリさえあります。例として、Andrea Giammarchi の redefine.js を確認してください。
注意
ここでの唯一の注意点は、独自のメソッドをビルトインに追加すると、(a) JavaScript の将来のバージョンまたは (b) 他のスクリプトと名前が衝突する可能性があるということです。(名前衝突の問題は、シンボルを使用した JavaScript の次のバージョンで解決されます。) 多くの人は、これは十分に大きな問題であり、ビルトインを変更するべきではなく、自分が所有するものだけを変更することに固執すべきだと主張するでしょう。 " -- 独自のコンストラクターで作成したもの。いくつかの (または多くの) 状況では同意する傾向がありますが、個人的な使用と学習のために、組み込みのプロトタイプをいじることは非常に役立ち、楽しいことだと思います。
可能な欠点のより詳細な説明については、ビルトインを変更するコストの一部を比較検討するこの記事をチェックしてください : http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/この記事は少し時代遅れ (1 年半) であり、彼の主な不満の 1 つは列挙可能性の問題であり、これはObject.defineProperty
最新のすべてのブラウザーで克服することができます。私が言ったように、もう 1 つの主要な問題 (名前の衝突) は、JavaScript の次のバージョンで解決される予定です。状況は良くなっています!