3

プロトタイプの継承に関するちょっとした質問
最近、JS.toUpperCase()やその他のメソッドなどthis、接頭辞付きオブジェクトからの参照を使用するカスタム メソッド ジャットを作成しようとしていました。

そして、それはうまく機能します(愚かで役に立たない例)

Object.prototype.customMethod = function(){
    return this.toLowerCase() ; 
};

次のように使用できます。

// access some object and get a key value
member.name; // JOHN
// use custom Method
member.name.customMethod(); // john

.customMethod()問題は、 Method がグローバルに every を継承しているように見えることですObject
邪魔にならないようにして、プレフィックス付きのオブジェクトのみを参照する方法は? それともまったく?

以下に例を示します: http://jsbin.com/evaneg/2/edit

// CREATE OBJECT
var obj = { "text" : "Hi" };

// TEST OBJECT KEY VALUE
alert( "OBJECT TEXT: "+ obj.text );     // Hi


// CREATE CUSTOM METHOD ( just like e.g. JS's .toUpperCase() method )
Object.prototype.addText = function(){ 
  return this+' there!';  
};

// USE CUSTOM .addText() METHOD
alert( "OBJECT TEXT+method: "+obj.text.addText() ); // Hi there! // wow, the method works!


for(var key in obj){
  alert( 'obj KEYS: '+ key ); // text // addText
}

// hmm... addText method as obj Key ???
// ok let's try with a new one...

var foobee = { "foo" : "bee" };

for(var key in foobee){
  alert( 'foobee KEYS: '+ key ); // foo // addText
}

// addText  ...again... but why?

私はこのhttp://javascript.crockford.com/prototypal.htmlと SOverflow に関する他の多くの同様のものも読みましたが、それらのほとんどはnew F( arguments )特定の引数を使用する を作成することに焦点を当てていますが、これは私の場合ではありません。説明をありがとう

4

2 に答える 2

4

メソッドをすべてのオブジェクトに追加する必要はありません。使用するオブジェクトの種類だけを追加してください。文字列メソッドの場合は、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返されるメソッドをすべての配列に追加します。truefalse

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

上記の呼び出しcontainsarguments機能しますが、イベント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 の次のバージョンで解決される予定です。状況は良くなっています!

于 2013-01-27T23:12:58.477 に答える
0

new F() も使用する必要があります。F を定義するだけで済みます。識別しやすいように、F を 'Name' と呼びましょう。

var Name = function(){
    var newName = {
        text: 'Hello',
        customMethod: function(){
            this.text = this.text.toUpperCase();
        }
    }
    return newName;
}

var Member = function(){
    var newMember = {
        name = new Name(),
        customMethod: function(){
        this.name.customMethod(); // make a member invoke upperCase on name (or any number of vars)
        }
    }
    return newMember;
}

var member = new Member();  //now when you run new Member, it runs the function above. and automatically makes your object with it's properties and methods.

console.log(member.name.text); //Hello!
member.customMethod();
// or
member.name.customMethod();
console.log(member.name.text); //HELLO!
于 2013-01-27T22:38:45.227 に答える