28

バウンティ 編集:

純粋なプロトタイプ OO パラダイム (Self を考えてください)で記述されたコードを探しています。プロトタイプの OO と従来の OO の混合物ではありません。一般的な OO ラッパーは見たくありませんが、単にプロトタイプの OO 手法を使用し、プロトタイプの OO 手法のみを使用するだけです。

参照関連の質問:

JavaScript の典型的なオブジェクト指向

上記の質問では、主に焦点を当てました

このようなプロトタイプの OO を記述できますか?

コンストラクターと初期化ロジックが必要ですか、代替手段は何ですか?

新しい質問:

基本的に、大規模なオープン ソース プロジェクトで javascript プロトタイプOO の良い例はありますか?

説明:

プロトタイプ OOの意味を明確にする必要があります。

  • クラスはありません。オブジェクトしかありません。
  • クラスの概念のエミュレーションはまったくありませ。ここでも、新しいオブジェクトを作成するためのオブジェクトとオブジェクトのクローンしかありません。

プロトタイプ OO のさらなる説明:

JavaScript のプロトタイプの OO と従来の OO エミュレーションの違いは、非常にグレーな領域です。古典的なオブジェクト指向を避けることを重視しているわけではありません。私は、古典的な OO エミュレーションとプロトタイプ OO の (おそらくより最適な) 組み合わせを学ぶことなく、それ自体でアカデミックな方法でプロトタイプ OO を学びたいと考えています。

これが、私がクラスを「禁止」する理由です。これらの手法を純粋な方法で確認し、独自の OO ツール キットを拡張できるようにするためです。

例:

jQuery などの一般的な例は、2 番目の基準を満たしていません。オブジェクトは、1 つのjQuery大きなクラス エミュレーションです。既存のオブジェクトを複製するのではなく、クラスから新しいオブジェクトを作成することに重点を置いています。

「純粋な」プロトタイプ OOの使用例を実際に知っていれば、お見せしたでしょう。JavaScript OO の 99% は、古典的なエミュレーションの影響を大きく受けていると思います。

ボーナスポイント

もしも

  • 十分にコメント/文書化されています
  • 単体テストあり
  • github にあります。

また、単純な Hello World アプリケーションを超えるプロトタイプの OO コードの作成方法に関する記事/チュートリアルと例も受け付けます。

4

8 に答える 8

9

あなたはそれを見つけることができません。

しばらく前にこの種のものを探しに行ったところ、これが見つかりました: Self Paper Organizing Programs Without Classes ( PDF バージョンについては Citeseer を参照してください。) この論文では、元のプロトタイプ言語であるSelfのベスト プラクティスについて説明します。ベストプラクティスは、メソッドのみを含み、オブジェクト固有のデータを含まない「特性オブジェクト」からオブジェクトを継承させる「特性オブジェクトイディオム」を使用することです。つまり、クラスのように疑わしいオブジェクトです。

元のプロトタイプ言語でさえ、クラスをエミュレートします。

于 2011-07-08T20:57:54.343 に答える
4

OMeta/JS をご覧になりましたか? OMeta は、Smalltalk と Self に基づく実験的な研究パターン マッチング言語です。OMeta/JS は、プロトタイプの OO を使用した JavaScript での実装です。

多くの例で十分にコメントされ、文書化されています。Githubにもあります。

http://tinlizzie.org/ometa-js/

https://github.com/alexwarth/ometa-js

編集: OMeta は Alexander Warth の博士論文の成果です。

于 2011-07-12T13:38:57.403 に答える
1

あなたが何を探しているのか正確にはわかりませんが、私の現在のフレームワークでは、次のようにOO形式でプログラミングできます。

Cin.define({
    name: 'MyApp.Logger',
    extends: 'Cin.Component',
    implements: ['MyApp.ILogger'],
    mixes: {
        SomeMixin: 'MyApp.SomeMixin'
    },

    init: function() {
    },

    method: function() {
    },

    statics: {
        staticMethod: function() {}
    }
});

そして、次のようなコードを書くことができます。

var instance = new MyApp.Logger();
instance.method();

MyApp.Logger.staticMethod();

ここでは、古典的なOOをエミュレートしようとはしていません。開発者がそのようなオブジェクト指向コードを簡単に記述できるように、継承、ミックスイン、インターフェイス、および一般的なオブジェクト指向の概念を宣言するための便利で便利な方法を作成しようとしています。これにより、自動読み込みコンポーネントを終了する機会も得られるため、依存関係を処理する必要がなくなり、ページの読み込みごとに100個のスクリプトを読み込む必要がないため、カスタムビルドを作成し、開発を迅速化できます。

OOの典型的な概念を学びたいのであれば、ある種の継承システムを書くべきだと思います。DojoToolkitまたはExtJSを見てください。覚えておくとよいのは、プロトタイプベースのシステムはねじれて壊れてしまうことです。クラスベースのオブジェクト指向言語よりも強力です。私の意見では、プロトタイプコードを書く正しい方法は1つではありません。

ただし、すべてではないにしてもほとんどの継承システムが、従来のOOをエミュレートしているように見える可能性があります。私の意見では、私のフレームワークはそうではありませんが、それでも完成していません。

于 2011-06-30T13:43:38.207 に答える
1

おそらくJSLintです(Crockfordはプロトタイプの継承の支持者ですが、私はそれを隅々まで調べたわけではありません)。また、オブジェクト指向よりも機能的に見えますが、プロトタイプの継承を真に取り入れたコードの場合は、一般的にそうなると思います。

于 2011-07-07T18:58:27.423 に答える
1

私のフレームワークでは、すべてがオブジェクトまたは「インターフェース」です。

インターフェイスは、オブジェクトが持つ可能性のある共通の機能 (methods / property_gets / property_sets) を定義します。

次のようなインターフェイスを作成します。var some_interface = GetInterface(constructor, interface_setup, parent_interface..)

parent_interfaces はいくつでも指定できます。したがって、 が と の両方をinterface_A継承する場合、interface_A を次のように作成できます。interface_Binterface_CGetInterface(constructor, interface_setup, interface_B, interface_C);

interface_Ainheritsinterface_Xinterface_Xinheritsの場合interface_Y、と の両方をinterface_A持つすべての関数が含まれます。interface_Xinterface_Y

コンストラクターを必要としないインターフェイスは、コンストラクター引数を null のままにします。interface_setup は、次のような関数です。

function(proto){
}

proto引数が指すオブジェクトにはSetMShadowM、 、SetP、 の 4 つのメソッドがありShadowPます。

これらの 4 つの方法を使用して、インターフェイスをセットアップします。

このフレームワークは、インターフェイスの遅延インスタンス化も提供します。(つまり、セットアップ コードは実際に最初に必要になるまで実行されません)。

このフレームワークの制限には、少なくともObject.keysObject.getOwnPropertyDescriptorおよびのサポートが必要Object.definePropertyです。(つまり、FireFox、IE、Chrome、Safari の最新バージョンでは動作しますが、Opera では動作しません)

TestPage2.html:

<!doctype html>
<script src="js.js"></script>
<script>
var human = GetInterface(function(){
},function(proto){
    //alert("trace: initing human");
    proto.$SetM("Sleep",function(){
        alert(this.Name+" is sleeping");
    });
    proto.$SetP("Name",function(){
        return this._name;
    },function(value){
        this._name=value;
    });
});

var female = GetInterface(function(){
},function(proto){
    //alert("trace: initing female");
    proto.$SetM("Dance",function(){
        alert(this.Name+" is dancing");
    });
},human);

var male = GetInterface(function(){
},function(proto){
    //alert("trace: initing male");
    proto.$SetM("Fight",function(){
        alert(this.Name+" is fighting");
    });
    proto.$ShadowP("Name",function(parent_get){
        return "Mr. "+parent_get();
    },function(parent_set,value){
        parent_set(value);
    });
},human);

var child = GetInterface(function(){
},function(proto){
    //alert("trace: initing child");
    proto.$SetM("Play",function(){
        alert(this.Name+" is playing");
    });
},human);

var adult = GetInterface(function(){
},function(proto){
    //alert("trace: initing adult");
    proto.$SetM("Work",function(){
        alert(this.Name+" is working");
    });
},human);

var mammal = GetInterface(function(){
},function(proto){
    //alert("trace: initing mammal");
    proto.$SetM("DoMammalStuff",function(){
        alert("doing mammal stuff");
    });
});


var john=new male();
john.Name="john";
john.Sleep();

var mary=new female();
mary.$IsA(child);
mary.$IsA(mammal);
mary.$Setup(function(proto){
    proto.$ShadowP("Name",function(parent_get){
        return "Miss "+parent_get.call(this);
    },function(parent_set,value){
        parent_set.call(this,value);
    });
});
mary.Name="mary";
mary.Play();
</script>

TestPage.html:

 <!doctype html>
<script src="js.js"></script>
<script>
var human_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing human");
    proto.$SetM("Sleep",function(){
        alert(this.Name+" is sleeping");
    });
    proto.$SetP("Name",function(){
        return this._name;
    },function(value){
        this._name=value;
    });
});

var female_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing female");
    proto.$SetM("Dance",function(){
        alert(this.Name+" is dancing");
    });
},human_interface);

var male_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing male");
    proto.$SetM("Fight",function(){
        alert(this.Name+" is fighting");
    });
},human_interface);

var child_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing child");
    proto.$SetM("Play",function(){
        alert(this.Name+" is playing");
    });
},human_interface);

var adult_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing adult");
    proto.$SetM("Work",function(){
        alert(this.Name+" is working");
    });
},human_interface);

var mammal_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing mammal");
    proto.$SetM("DoMammalStuff",function(){
        alert("doing mammal stuff");
    });
});

var john={};
john.$IsA(adult_interface);
//the above 2 lines are equal to simply doing:
//var john=new adult_interface();
//you can think of it as a shortcut
john.$IsA(mammal_interface);
john.DoMammalStuff();
john.Name="john";
john.Sleep();

var mary=new female_interface();
mary.$IsA(child_interface);
mary.$IsA(mammal_interface);
mary.DoMammalStuff();
mary.Name="mary";
mary.Play();
mary.Dance();
</script>

Js.js:

"use strict";
var GetInterface;
(function(){
    //================================================================================//
    //(constructor:Function, setup:Function?, parent_interfaces:Function..):Function
    GetInterface = function (constructor, setup) {
        var parent_classes = GetParray(arguments, 2);
        var output = function () {
            output.$Init();
            for (var x = parent_classes.length - 1; x >= 0; --x) {
                parent_classes[x](this);
            }
            if(constructor===null){
                constructor.apply(this, arguments);
            }
        };
        output.$Init = Mize(function () {
            var output_proto = output.prototype;
            parent_classes.forEach(function (parent_class) {
                parent_class.$Init();
                Infect(output_proto, parent_class.prototype);
            });
            init_proto(output_proto,setup);
            if(setup!==undefined){
                setup(output_proto);
            }
        });
        return output;
    };
    var init_proto=function(proto){
        $defineProperty(proto, "$SetM", { value: set_m, writable: true, configurable: true });
        $defineProperty(proto, "$ShadowM", { value: shadow_m, writable: true, configurable: true });
        $defineProperty(proto, "$SetP", { value: set_p, writable: true, configurable: true });
        $defineProperty(proto, "$ShadowP", { value: shadow_p, writable: true, configurable: true });
    };
    var set_m = function (method_name, method) {
        this[method_name] = method;
    };
    var set_p = function (property_name, getter, setter) {
        $defineProperty(this, property_name, { get: getter, set: setter, enumerable: true, configurable: true });
    };
    var shadow_m = function (method_name, supplied_method) {
        var old_method = this[method_name];
        this[method_name] = function () {
            var args = GetParray(arguments);
            args.unshift(old_method.bind(this));
            supplied_method.apply(this, args);
        };
    };
    var shadow_p = function (property_name, getter, setter) {
        var old_descriptor = $getOwnPropertyDescriptor(this, property_name);
        var old_get = old_descriptor.get;
        var old_set = old_descriptor.set;
        $defineProperty(this, property_name, { get: function () {
            return getter.call(this, old_get.bind(this));
        }, set: function (value) {
            setter.call(this, old_set.bind(this), value);
        }, enumerable: true, configurable: true
        });
    };
    var $slice=Array.prototype.slice;
    var $defineProperty=Object.defineProperty;
    var $getOwnPropertyDescriptor=Object.getOwnPropertyDescriptor;
    if($defineProperty===undefined){
        throw "Object.defineProperty, Object.getOwnPropertyDescriptor, Object.keys are required";
    }
    //================================================================================//
    //(victim:Object, disease:Object):void
    var Infect=function (victim, disease, excludes) {
        var keys=Object.keys(disease);
        if(excludes!==undefined){
            excludes.forEach(function(exclude){
                ForEach(keys,function(key,x){
                    if(key===exclude){
                        keys.splice(x,1);
                        return false;
                    }
                });
            });
        }
        keys.forEach(function(key){
            $defineProperty(victim, key, $getOwnPropertyDescriptor(disease, key));
        });
    };
    //================================================================================//
    //(args:Object # arguments object #, start_index:int?):Array
    var GetParray = function (args, start_index) {
        if (start_index === undefined) {
            start_index = 0;
        }
        return $slice.call(args, start_index);
    };
    //================================================================================//
    //(array:Array, f:Function(item:Object|null, index:pint):boolean?):Object
    var ForEach=function(array,f){
        for (var x = 0, xx = array.length, last_index=xx-1; x < xx; ++x) {
            var result = f(array[x], x, last_index);
            if (result !== undefined) {
                return result;
            }
        }
    };
    //================================================================================//
    //provides memoization.
    //(f:Function, arity_fixed:boolean?true):Function
    //caching is done according to the inputs. the results of calling function(undefined) and function() are cached differently.
    //if arity is fixed, optimizations can be done
    var Mize=function(f, arity_fixed) {
        if (arity_fixed === undefined) {
            arity_fixed = true;
        }
        var used; //for 0 arg
        var result; //for 0 arg
        var results; //for >0 args
        var used_params; //for 1 arg
        var used_param_sets; //for >1 args
        var f_length = f.length;
        var use_generic = !arity_fixed || f_length > 3;
        if (use_generic) { //if `f_length` <= 3, it will be optimized (i.e. not using generic function)
            results = [];
            used_param_sets = [];
            return function () {
                var params = GetParray(arguments);
                var result_found = false;
                var result = ForEach(used_param_sets,function (used_param_set, x) {
                    if (used_param_set.length === params.length) {
                        var params_match = true;
                        ForEach(params,function (param, y) {
                            if (used_param_set[y] !== param) {
                                params_match = false;
                                return false;
                            }
                        });
                        if (params_match) {
                            result_found = true;
                            return results[x];
                        }
                    }
                });
                if (!result_found) {
                    used_param_sets.push(params);
                    result = f.apply(null, params);
                    results.push(result);
                }
                return result;
            };
        }
        if (f_length === 0) {
            used = false;
            return function () {
                if (!used) {
                    result = f();
                    used = true;
                }
                return result;
            };
        }
        if (f_length === 1) {
            used_params = [];
        } else {
            used_param_sets = [];
        }
        results = [];
        switch (f_length) {
            case 1:
                return function (arg) {
                    var result_found = false;
                    var result = ForEach(used_params,function (used_param, x) {
                        if (arg === used_param) {
                            result_found = true;
                            return results[x];
                        }
                    });
                    if (!result_found) {
                        used_params.push(arg);
                        result = f(arg);
                        results.push(result);
                    }
                    return result;
                };
                break;
            case 2:
                return function (arg1, arg2) {
                    var result_found = false;
                    var result = ForEach(used_param_sets,function (used_param_set, x) {
                        if (arg1 === used_param_set[0] && arg2 === used_param_set[1]) {
                            result_found = true;
                            return results[x];
                        }
                    });
                    if (!result_found) {
                        used_param_sets.push([arg1, arg2]);
                        result = f(arg1, arg2);
                        results.push(result);
                    }
                    return result;
                };
                break;
            case 3:
                return function (arg1, arg2, arg3) {
                    var result_found = false;
                    var result = ForEach(used_param_sets,function (used_param_set, x) {
                        if (arg1 === used_param_set[0] && arg2 === used_param_set[1] && arg3 === used_param_set[2]) {
                            result_found = true;
                            return results[x];
                        }
                    });
                    if (!result_found) {
                        used_param_sets.push([arg1, arg2, arg3]);
                        result = f(arg1, arg2, arg3);
                        results.push(result);
                    }
                    return result;
                };
                break;
            default:
                throw "Invalid `f_length`: " + f_length;
        }
    };
    //================================================================================//
    Object.prototype.$Setup=function(setup){
        setup(Object.getPrototypeOf(this));
    };
    //================================================================================//
    Object.prototype.$IsA=function(_interface){
        var excludes=GetParray(arguments,1);
        if(this.$SetM===undefined){
            this.$SetM=set_m;
            this.$SetP=set_p;
            this.$ShadowM=shadow_m;
            this.$ShadowP=shadow_p;
        }
        _interface.$Init();
        /*var this_proto={};
        init_proto(this_proto);
        Infect(this_proto,Object.getPrototypeOf(this));
        this.__proto__=this_proto;*/
        Infect(Object.getPrototypeOf(this),_interface.prototype,excludes);
    };
    //================================================================================//
})();
于 2011-07-12T08:32:59.093 に答える
0

ExtJSはJavaScriptOOの優れた例です。これは、JavaScriptで非常に洗練されたエンタープライズレベルのOO階層を実装し、箱から出してすぐに多くのことを実行します。気の遠くなるような読み物かもしれませんが(最後に3.Xでチェックインしましたが、1 MBを超える未加工の非圧縮JavaScriptでした)、多くのアイデアが得られます。まず、ドキュメントを確認して高レベルのビューを取得することから始めることができます。

于 2011-06-30T13:47:40.340 に答える
0

これは、探している OO プログラミングの基礎を示す例です。実世界での最良の例は、おそらく jQuery でしょう。

JavaScript を学ぶときは、根底にあるのは C や Java よりも、実際には Scheme に近いということを覚えておく必要があります。基本的にCの構文ではSchemeです。

特に API を作成している場合は、JavaScript で「new」を使用する必要があるケースはほとんどありません。JavaScript がプロトタイプのフレームワークについて確信が持てなかったため、「new」演算子が追加されたようです。C、C++、Java などの古典的な言語でプログラミングを始める私たちのほとんどにとって、これは奇妙に思えます。なぜなら、「新しい」というのは、簡単に変換できるため、一般的にまさに私たちが探しているものだからです。

あなたが尋ねる「新しい」を使用すべきではないのはなぜですか? さて、「new」の実装により、うっかりしてグローバル データを消去し始める可能性があります (覚えておいてください、すべてが JavaScript の関数に含まれているわけではありません)。たまたまこれの餌食になった場合、エラーや通知は表示されず、プログラムで予測できない動作が表示されるだけです。また、「クラス」内で「これ」が実際に何にバインドされているかが明確な場合とそうでない場合があります。

この問題は、主に「new」で呼び出されることを意図した関数を記述し、ユーザーが「new」を使用しない場合に発生します。API でそれを使用すると、ユーザーが不満を抱く可能性がある理由のヒント。

オブジェクト指向の「クラス」と継承の正しい方法は、JavaScript の最も強力な属性であるオブジェクトを使用することです。

オブジェクトを返す関数を記述して、「クラス」を確立できます。このオブジェクトに入れるもの (数値、文字列、メソッドなど) はすべて、「クラス」のパブリック プロパティです。返されるオブジェクト内にない関数内に記述するものはすべて非公開です。

「クラス」から継承するには、返すオブジェクトを「基本クラス」の結果に初期化し、その機能を拡張するだけです。

コードの次のセクションでは、プライベート変数とパブリック変数を使用して基本クラスを構築する方法と、2 レベルの継承を行う方法を示します。

ベース オブジェクト

//Base Object
var Animal = function(spec) {

    //This is our output object
    //Everything provided from 'spec' and
    //everything not addded to 'that' will
    //be 'private'. Everything added to
    //'that' is 'public'.
    var that = {};

    //Private Methods
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    var defaults = {
        name : 'Default Name',
        food : 'Default Food',
        saying : 'Default Saying',
    }

    extend(defaults,spec);

    //Public Methods
    that.name = function() {
        return defaults.name;
    }

    that.eats = function() {
        if(typeof(defaults.food) === 'string') {
            return defaults.food;
        } else if(typeof(defaults.food) === 'object') {
            return defaults.food.join(', ');
        }
    }

    that.says = function() {
        return defaults.saying;
    }

    return that;
}

var myAnimal = Animal();       //Create a new instance
alert(myAnimal.name());        //Alerts 'Default Name'
alert(myAnimal.eats());        //Alerts 'Default Food'
alert(myAnimal.says());        //Alerts 'Default Saying'
alert(myAnimal.saying);        //Alerts 'undefined'
//alert(myAnimal.extend());    //Has No Method Error

var myAnimal2 = Animal({       //Create a new instance using a spec
    name : 'Mike',
    food : ['Chicken','Duck'],
    saying : 'Rawr',
});    
alert(myAnimal2.name());        //Alerts 'Mike'
alert(myAnimal2.eats());        //Alerts 'Chicken, Duck'
alert(myAnimal2.says());        //Alerts 'Rawr'

継承

//Inheritance Object
var Mammal = function(spec) {

    //Private Methods

    //Have to redefine this since
    //I decided to use this as an
    //example of a private method
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    //New list of defaults
    var defaults = {
        name : 'Mammal',
        attributes : ['fur'],
    }

    extend(defaults,spec);

    //Inherrit from our Animal Object
    //Use Mammal defaults
    var that = Animal(defaults);


    that.attributes = function() {
        if(typeof(defaults.attributes) === 'string') {
            return defaults.attributes;
        } else if(typeof(defaults.attributes) === 'object') {
            return defaults.attributes.join(', ');
        } else {
            return false;
        }
    }

    return that;
}

//Second-Level Inheritance
var Cat = function(spec) {

    //Private Methods

    //Have to redefine this since
    //I decided to use this as an
    //example of a private method
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    //New list of defaults
    var defaults = {
        name : 'Cat',
        saying : 'Meow',
        food : ['fish','birds','frogs','MeowMix'],
        fur_color : 'Default Fur Color',
        attributes : ['fur','claws','crazy eyes','long tail'],
    }

    extend(defaults,spec);

    //Inherrit from our Mammal Object
    //We use our defaults for the cat
    var that = Mammal(defaults);

    that.fur_color = function() {
        return defaults.fur_color; 
    }

    that.purr = function(n) {
        var str = '';

        for(var i=0;i<n;i++) {
            if(i === 0) {
                str = 'p-';
            } else if(i === n-1) {
                str += 'r';
            } else {
                str += 'r-';
            }
        }

        return str
    };

    return that;
}


var myMammal = Mammal();
alert(myMammal.name());        //Alerts Mammal
alert(myMammal.attributes());  //Alerts 'fur'

var myCat = Cat();
alert(myCat.name());            //Alerts Cat
alert(myCat.says());            //Alerts Meow

var toonces = Cat({
    name : 'Toonces the Driving Cat',
    food : ['Whiskas','ham'],
    saying : 'Meeeooooowww',
    fur_color : 'Black',
    attributes : [ 
        'Can Drive a Car', 'Claws',
        'fur','crazy eyes','long tail',
        'Steals Hub Caps',
    ],
});

alert(toonces.name());            //Alerts 'Toonces the Driving Cat'
alert(toonces.says());            //Alerts 'Meeooooowww'
alert(toonces.eats());            //Alerts 'Whiskas, ham'
alert(toonces.fur_color());       //Alerts 'Black'
alert(toonces.attributes());      //Alerts 'Can Drive a Car, Claws,
                                  //fur, crazy eyes, long tail,
                                  // Steals Hub Caps',
alert(toonces.purr(5));           //Alerts 'p-r-r-r-r'

編集:「プロトタイプ」オブジェクトを使用していないことを警告されました。上記のテキストで述べたように、「new」演算子を使用しないようにするために、これを行いました。完全を期すために、以下のプロトタイプ オブジェクトを使用した例を示します...

プロトタイプ オブジェクトによる継承

//Building a class to use the prototype object
var Dog = function(spec) {

var that = this;

//Private Methods

    //Have to redefine this since
    //I decided to use this as an
    //example of a private method
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    //New list of defaults
    var defaults = {
        name : 'Dog',
        saying : 'Woof',
        food : ['bacon'],
        fur_color : 'Default Fur Color',
        attributes : ['fur','Barks at Mailman'],
    }


    //Attach the properties of a Mammal to "self"
    this.self = new Mammal(defaults);

    //Add a function to get the name
    this.getName = function() {
        return that.self.name();
    }
}

//Extend the prototype
Dog.prototype.growl = "grrrrrrr";

//Make a new dog...HAVE TO CALL NEW HERE OR ELSE BAD THINGS CAN HAPPEN
d= new Dog();

alert(d.growl);            //Alerts 'grrrrrrr'
alert(d.getName());        //Alerts 'Dog'
alert(d.self.says());      //Alerts 'Woof'

この投稿についてお気軽にお問い合わせください。楽しみ。

于 2011-07-11T20:03:28.950 に答える
0

私は現在、プロトタイプの OO パターンと jQuery プラグイン パターンを組み合わせようとする継承プラグイン モデルを使用しています。ここに私の回答で詳細に投稿されています:クラスをjQueryオブジェクトにアタッチする

注:言葉に触れて背を向けないでくださいClass

于 2011-07-12T00:49:07.023 に答える