JavaScriptの継承[クローズ]


80

javascriptで継承を実装しようとしています。私はそれをサポートするために次の最小限のコードを思いついた。

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

専門家の皆さん、これで十分か、または私が見逃したかもしれない他の重要な問題があるかどうかをお知らせください。直面している同様の問題に基づいて、他の変更を提案してください。

完全なテストスクリプトは次のとおりです。

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
    this.superalert = function(){
        alert('tst');
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

function Child(){
    Base.extend(this, Base);
    this.width = 20;
    this.height = 15;
    this.a = ['s',''];
    this.alert = function(){
        alert(this.a.length);
        alert(this.height);
    }
}

function Child1(){
    Base.extend(this, Child);
    this.depth = 'depth';
    this.height = 'h';
    this.alert = function(){
        alert(this.height); // display current object height
        alert(this.a.length); // display parents array length
        this.call(this.base.alert); 
          // explicit call to parent alert with current objects value
        this.call(this.base.superalert); 
          // explicit call to grandparent, parent does not have method 
        this.base.alert(); // call parent without overriding values
    }
}

var v = new Child1();
v.alert();
alert(v.height);
alert(v.depth);

継承が必要な場合は、すでに多くのライブラリがこれを提供しています。少なくともそれらを読んで、コードが間違っている場所を見つけてください。しかし、なぜ再発明するのですか?頭に浮かぶ2つの素晴らしいjavascript継承ライブラリはklassselfish.jsです(私は両方を使用しました、それらは素晴らしいです)
bejonbee 2011

Klassを使用しましたが、配列変数のオーバーライドに問題があります。わがままにやってみます。しかし、私のバージョンは単純な4行のコードですが、ほとんどのシナリオで機能します。後でこのアプローチで立ち往生するかどうかを知りたいだけです。
hungryMind 2011

2
同様の質問に対するこのSOの回答を確認することをお勧めします。すべての優れたヒントの中で、作成者は、子クラスを定義するときに親のコンストラクターへの呼び出しを削除する方法を示しています。
bejonbee 2011

@hungryMind:コードに関する特定の問題が心配な場合は、質問を編集して、恐れていることを正確に教えてください。あなたは自分のコードが大丈夫かどうかを尋ねているだけなので、あまり正義を与えないからです。あなたはおそらくあなたが探している答えを得ることができないでしょう。したがって、私はあなたQ.編集示唆
ロバートKoritnik

この質問は同じトピックに関するものです:stackoverflow.com/questions/711209/…–
アンダーソングリーン

回答:


139

ECMAScript 5でJavaScriptの継承を実装するには、オブジェクトのプロトタイプを定義し、それを使用Object.createして継承します。プロパティを必要なだけ追加/オーバーライドすることもできます。

例:

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.x = x;
    this.y = y;
}

// Inheritance
Translation.prototype = Object.create(Transform.prototype);

// Override
Translation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.angle = angle;
}

// Inheritance
Rotation.prototype = Object.create(Transform.prototype);

// Override
Rotation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Rotation " + this.angle;
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

2
Translation.prototype = Object.create(new Transform()); ?Translation.prototype = Object.create(Transform.prototype);
4esn0k 2012年

@ 4esn0kそうです、ありがとう。
Lorenzo Polidori 2012年

なぜだけではないのTranslation.prototype = new Transform()ですか?また、現在回答が機能していないので、編集しますか?
ジョーンZaefferer

@JörnZaeffererこちらをご覧ください:stackoverflow.com/q/4166616/885464。そして、「答えは現在機能していない」とはどういう意味ですか?
ロレンツォポリドリ

4
また、サブクラスのコンストラクターを明示的に設定する必要がありますTranslation.prototype.constructor = Translation。オブジェクトのクローンを作成するのに役立ちます(ほとんどの手法で)。
barboaz 2014年

41

Johnのソリューションと同様に、Crockfordsのソリューションは複雑すぎると思います。両方が説明しているように見えるよりも、JavaScriptの継承を取得する方がはるかに簡単です。考えてみましょう:

//Classes
function A() {
    B.call(this);
}

function B() {
    C.call(this);
    this.bbb = function() {
        console.log("i was inherited from b!");
    }
}

function C() {
    D.call(this);
}

function D() {
    E.call(this);
}

function E() {
    //instance property 
    this.id = Math.random()
}

//set up the inheritance chain (order matters) 
D.prototype = new E();
C.prototype = new D();
B.prototype = new C();
A.prototype = new B();

//Add custom functions to each
A.prototype.foo = function() {
    console.log("a");
};
B.prototype.bar = function() {
    console.log("b");
};
C.prototype.baz = function() {
    console.log("c");
};
D.prototype.wee = function() {
    console.log("d");
};
E.prototype.woo = function() {
    console.log("e");
};

//Some tests
a = new A();
a.foo();
a.bar();
a.baz();
a.wee();
a.woo();
console.log(a.id);
a.bbb();
console.log(a instanceof A);
console.log(a instanceof B);
console.log(a instanceof C);
console.log(a instanceof D);
console.log(a instanceof E);​
var b = new B();
console.log(b.id)

上記のソリューションの完全な説明をブログ書いています。


1
すべてのパブリックメンバーのみをサポートすることを除いて
rodrigo-silveira 2012年

@ rodrigo-silveira、どういう意味かわからない。プライベートが必要な場合は、var x = "whatever"で宣言するだけです。
Marcosc 2012年

2
@ rodrigo-silveiraは、保護されたメンバーをサポートしないことを意味していると思います。どちらのソリューションもサポートしていません。(定義上、プライベートメンバーはサブクラスからアクセスできないため、意味がありません)。this._myProtectedVariable = 5;保護されたメンバーを作成するには、のようなものを使用する必要があります。
Ciantic 2012年

10
非常に優れたソリューションですが、(わずかな)欠点があり、コンストラクターは2回実行されます。一度D.call(this)、そして再び:new D()。これは通常大きな問題ではありませんが、回避したい場合は、次のようにObject.createを使用できます。C.prototype= new D();の代わりに。C.prototype = Object.create(D.prototype);と書くことができます。例:jsfiddle.net/9Dxkb/1
Ray Hulha 2013年

1
最後に、機能する紛らわしい説明!私はあなたの論理を逆にして、Eが逆方向に継承するようにしました(Eが最もそれを持っています)。ありがとう!
Ed Bayiates 2013

12

JSオブジェクトで遊んでいると、もっとミニマルな解決策が見つかりました:-)お楽しみください!

function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); }

function A() {
    this.info1 = function() {
        alert("A");
    }
}

function B(p1,p2) {
    extend(B,A,this);
    this.info2 = function() {
        alert("B"+p1+p2);
    }
}

function C(p) {
    extend(C,B,this,["1","2"]);
    this.info3 = function() {
        alert("C"+p);
    }
}


var c = new C("c");
c.info1(); // A
c.info2(); // B12
c.info3(); // Cc

8

これが最も簡単で、JSの継承を理解する最も簡単な方法を願っています。この例で最も役立つのは、PHPプログラマーです。

function Mother(){
    this.canSwim = function(){
        console.log('yes');
    }
}

function Son(){};
Son.prototype = new Mother;
Son.prototype.canRun = function(){
    console.log('yes');
}

これで、息子には1つのオーバーライドされたメソッドと1つの新しいメソッドがあります

function Grandson(){}
Grandson.prototype = new Son;
Grandson.prototype.canPlayPiano = function(){
    console.log('yes');
};
Grandson.prototype.canSwim = function(){
    console.log('no');
}

現在、孫には2つのオーバーライドされたメソッドと1つの新しいメソッドがあります

var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no


Object.create(new Son)として実装することは可能です
Alexander Serkin 2013

それはさらに悪いでしょう。
ベルギ2013

4

関数の代わりにオブジェクトを使用してみませんか:

var Base = {
    superalert : function() {
        alert('tst');
    }
};

var Child = Object.create(Base);
Child.width = 20;
Child.height = 15;
Child.a = ['s',''];
Child.childAlert = function () {
        alert(this.a.length);
        alert(this.height);
    }

var Child1 = Object.create(Child);
Child1.depth = 'depth';
Child1.height = 'h';
Child1.alert = function () {
    alert(this.height);
    alert(this.a.length);
    this.childAlert();
    this.superalert();
};

そしてそれをこのように呼んでください:

var child1 = Object.create(Child1);
child1.alert();

このアプローチは、関数を使用する場合よりもはるかにクリーンです。関数を使用した継承がJSでそれを行う適切な方法ではない理由を説明しているこのブログを見つけました:http//davidwalsh.name/javascript-objects-deconstruction

編集

var子は次のように書くこともできます:

var Child = Object.create(Base, {
    width : {value : 20},
    height  : {value : 15, writable: true},
    a : {value : ['s', ''], writable: true},
    childAlert : {value : function () {
        alert(this.a.length);
        alert(this.height);
    }}
});

4

これが私の解決策です。これは、LorenzoPolidoriの 回答で説明されている標準的なプロトタイプの継承方法に基づいています。

まず、これらのヘルパーメソッドを定義することから始めます。これにより、後で理解しやすく、読みやすくなります。

Function.prototype.setSuperclass = function(target) {
    // Set a custom field for keeping track of the object's 'superclass'.
    this._superclass = target;

    // Set the internal [[Prototype]] of instances of this object to a new object
    // which inherits from the superclass's prototype.
    this.prototype = Object.create(this._superclass.prototype);

    // Correct the constructor attribute of this class's prototype
    this.prototype.constructor = this;
};

Function.prototype.getSuperclass = function(target) {
    // Easy way of finding out what a class inherits from
    return this._superclass;
};

Function.prototype.callSuper = function(target, methodName, args) {
    // If methodName is ommitted, call the constructor.
    if (arguments.length < 3) {
        return this.callSuperConstructor(arguments[0], arguments[1]);
    }

    // `args` is an empty array by default.
    if (args === undefined || args === null) args = [];

    var superclass = this.getSuperclass();
    if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");

    var method = superclass.prototype[methodName];
    if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");

    return method.apply(target, args);
};

Function.prototype.callSuperConstructor = function(target, args) {
    if (args === undefined || args === null) args = [];

    var superclass = this.getSuperclass();
    if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");

    return superclass.apply(target, args);
};

これで、クラスのスーパークラスをで設定できるだけでなくSubClass.setSuperclass(ParentClass)、オーバーライドされたメソッドをSubClass.callSuper(this, 'functionName', [argument1, argument2...]):で呼び出すこともできます。

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Translation.callSuper(this, arguments);

    // Public properties
    this.x = x;
    this.y = y;
}
// Inheritance
Translation.setSuperclass(Transform);

// Override
Translation.prototype.toString = function() {
    return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Rotation.callSuper(this, arguments);

    // Public properties
    this.angle = angle;
}
// Inheritance
Rotation.setSuperclass(Transform);

// Override
Rotation.prototype.toString = function() {
    return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle;
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

確かに、ヘルパー関数を使用しても、ここでの構文はかなり厄介です。ありがたいことに、ECMAScript 6では、構文上の糖衣構文(最大限に最小限のクラス)が追加されて、物事がより美しくなりました。例えば:

/**
 * Transform base class
 */
class Transform {
  constructor() {
    this.type = "2d";
  }

  toString() {
    return "Transform";
  } 
}

/**
 * Translation class.
 */
class Translation extends Transform {
  constructor(x, y) {
    super(); // Parent constructor

    // Public properties
    this.x = x;
    this.y = y;
  }

  toString() {
    return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
  }
}

/**
 * Rotation class.
 */
class Rotation extends Transform {
  constructor(angle) {
    // Parent constructor
    super(...arguments);

    // Public properties
    this.angle = angle;
  }

  toString() {
    return super(...arguments) + this.type + " Rotation " + this.angle;
  }
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

ECMAScript 6はこの時点ではまだドラフト段階であり、私が知る限り、主要なWebブラウザーには実装されていないことに注意してください。ただし、必要に応じて、Traceurコンパイラのようなものを使用ECMAScript 6して、単純な古いECMAScript 5ベースのJavaScriptにコンパイルすることができます。Traceurを使用してコンパイルされた上記の例をここで見ることができます


2

上記のすべての回答に同意しますが、JavaScriptはオブジェクト指向である必要はなく(継承を回避する)、代わりにオブジェクトベースのアプローチであると感じています。にほとんどの場合で十分である。

Eloquent JavaScriptがオブジェクト指向プログラミングに関する第8章を開始して、OOについて話している方法が好きです。継承を実装するための最良の方法を解読する代わりに、JavaScriptの機能的側面を学ぶためにより多くのエネルギーを費やす必要があるため、関数型プログラミングに関する第6章の方が興味深いと思いました。


2
//This is an example of how to override a method, while preserving access to the original.
//The pattern used is actually quite simple using JavaScripts ability to define closures:

    this.somefunction = this.someFunction.override(function(args){
        var result = this.inherited(args);
        result += this.doSomethingElse();
        return result;
    });

//It is accomplished through this piece of code (courtesy of Poul Krogh):

/***************************************************************
    function.override overrides a defined method with a new one, 
    while preserving the old method.
    The old method is only accessible from the new one.
    Use this.inherited() to access the old method.
***************************************************************/

    Function.prototype.override = function(func)
    {
        var remember = this;
        var f = function() 
        {
             var save = this.inherited; 
             this.inherited = remember;
             var result = func.apply(this, Array.prototype.slice.call(arguments));
             this.inherited = save;
             return result;
        };
        return f;
    }

1

この単純なアプローチはどうですか

    function Body(){
        this.Eyes = 2;
        this.Arms = 2;
        this.Legs = 2;
        this.Heart = 1;
        this.Walk = function(){alert(this.FirstName + ' Is Walking')};
    }

    function BasePerson() {
        var BaseBody = new Body(this);
        BaseBody.FirstName = '';
        BaseBody.LastName = '';
        BaseBody.Email = '';
        BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); };
        return BaseBody;
    }

    function Person(FirstName,LastName)
    {
        var PersonBuild = new BasePerson();
        PersonBuild.FirstName = FirstName;
        PersonBuild.LastName = LastName;
        return PersonBuild;
    }

    var Person1 = new Person('Code', 'Master');
    Person1.IntroduceSelf();
    Person1.Walk();

1

基本的なプロトタイプの継承

JavaScriptで継承を行うための簡単ですが効果的な方法は、次の2つのライナーを使用することです。

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

これはこれを行うのと似ています:

B.prototype = new A();

両方の主な違いは、のコンストラクターがAを使用するときに実行されないObject.createことです。これは、より直感的で、クラスベースの継承に似ています。

のコンストラクターに追加することによりA、の新しいインスタンスを作成するときに、オプションでのコンストラクターをいつでも実行することを選択できます。BB

function B(arg1, arg2) {
    A(arg1, arg2); // This is optional
}

あなたは、すべての引数を渡したい場合BにはA、あなたも使用することができますFunction.prototype.apply()

function B() {
    A.apply(this, arguments); // This is optional
}

あなたがのコンストラクタチェーンに別のオブジェクトをミックスインする場合B、あなたは組み合わせることができますObject.createObject.assign

B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;

デモ

function A(name) {
  this.name = name;
}

A.prototype = Object.create(Object.prototype);
A.prototype.constructor = A;

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

function mixin() {

}

mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);
C.prototype.constructor = C;

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


独自のラッパーを作成する

コード全体でほぼ同じ2ライナーを記述したくない場合は、次のような基本的なラッパー関数を記述できます。

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

このラッパーのしくみ:

  1. 1つのパラメータを渡すと、そのプロトタイプはから継承されObjectます。
  2. 2つのパラメーターを渡すと、最初のプロトタイプは2番目のパラメーターから継承されます。
  3. 3つ以上のパラメーターを渡すと、最初のパラメーターは2番目のパラメーターから継承され、他のパラメーターのプロトタイプが混合されます。

デモ

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

function A(name) {
  this.name = name;
}

inheritance(A);

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

inheritance(B, A);

function mixin() {

}

inheritance(mixin);

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

inheritance(C, B, mixin);

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


注意

Object.createIE9 +を含むすべての最新ブラウザで安全に使用できます。Object.assignIEのどのバージョンでも、一部のモバイルブラウザでも機能しません。それが推奨されポリフィル Object.createおよび/またはObject.assign、それらを使用して、それらを実装していないブラウザをサポートする場合にれます。

あなたは用ポリフィルを見つけることができるObject.create ここ とに1つObject.assign ここに


0
//
//  try this one:
//  
//    function ParentConstructor() {}
//    function ChildConstructor()  {}
//
//    var 
//        SubClass = ChildConstructor.xtendz( ParentConstructor );
//
Function.prototype.xtendz = function ( SuperCtorFn ) {

    return ( function( Super, _slice ) {

                // 'freeze' host fn 
                var
                    baseFn = this, 
                    SubClassCtorFn;

                // define child ctor
                SubClassCtorFn = function ( /* child_ctor_parameters..., parent_ctor_parameters[] */ ) {

                    // execute parent ctor fn on host object
                    // pass it last ( array ) argument as parameters
                    Super.apply( this, _slice.call( arguments, -1 )[0] );

                    // execute child ctor fn on host object
                    // pass remaining arguments as parameters
                    baseFn.apply( this, _slice.call( arguments, 0, -1 ) );

                };

                // establish proper prototype inheritance
                // 'inherit' methods
                SubClassCtorFn.prototype = new Super;

                // (re)establish child ctor ( instead of Super ctor )
                SubClassCtorFn.prototype.constructor = SubClassCtorFn;

                // return built ctor
                return SubClassCtorFn;

    } ).call( this, SuperCtorFn, Array.prototype.slice );
};

// declare parent ctor
function Sup( x1, x2 ) {
    this.parent_property_1 = x1;
    this.parent_property_2 = x2;
}

// define some methods on parent
Sup.prototype.hello = function(){ 
   alert(' ~  h e l l o   t h e r e  ~ ');
};


// declare child ctor
function Sub( x1, x2 ) {
    this.child_property_1 = x1;
    this.child_property_2 = x2;
}

var
    SubClass = Sub.xtendz(Sup), // get 'child class' ctor
    obj;

// reserve last array argument for parent ctor
obj = new SubClass( 97, 98, [99, 100] ); 

obj.hello();

console.log( obj );
console.log('obj instanceof SubClass      -> ', obj instanceof SubClass      );
console.log('obj.constructor === SubClass -> ', obj.constructor === SubClass );
console.log('obj instanceof Sup           -> ', obj instanceof Sup           );
console.log('obj instanceof Object        -> ', obj instanceof Object        );

//
//  Object {parent_property_1: 99, parent_property_2: 100, child_property_1: 97, child_property_2: 98}
//  obj instanceof SubClass      -> true
//  obj.constructor === SubClass -> true
//  obj instanceof Sup           -> true
//  obj instanceof Object        -> true
//

-1

AWebライブラリを使用する最も簡単な方法。公式サンプル:

   /**
     * A-class
     */
   var ClassA = AWeb.class({
     public : {
        /**
          * A-class constructor
          */
        constructor : function() {
           /* Private variable */
           this.variable1 = "A";
           this.calls = 0;
        },

        /**
          * Function returns information about the object
          */
        getInfo : function() {
           this.incCalls();

           return "name=" + this.variable1 + ", calls=" + this.calls;
        }
     },
     private : {
        /**
          * Private function
          */
        incCalls : function() {
           this.calls++;
        }
     }
  });
  /**
    * B-class
    */
  var ClassB = AWeb.class({
     extends : ClassA,
     public : {
        /**
          * B-class constructor
          */
        constructor : function() {
           this.super();

           /* Private variable */
           this.variable1 = "B";
        },

        /**
          * Function returns extended information about the object
          */
        getLongInfo : function() {
           return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined";
        }
     }
  });
  /**
    * Main project function
    */
  function main() {
     var a = new ClassA(),
         b = new ClassB();

     alert(
        "a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" +
        "a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" +

        "b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" +
        "b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" +

        "b.getInfo()=" + b.getInfo() + "\n" +
        "b.getLongInfo()=" + b.getLongInfo()
     );
  }

-1

物事を拡張してプロトタイピングするよりもはるかに簡単な解決策を見つけました。見た目はきれいで機能的ですが、実はこれがどれだけ効率的かはわかりません。

var A = function (p) {
    if (p == null) p = this;
    p.a1 = 0;
    this.a2 = 0;
    var a3 = 0;
};

var B = function (p) {
    if (p == null) p = this;
    p.b1 = new A(this);
    this.b2 = new A(this);
    var b3 = new A(this);
    this b4 = new A();
};

var a = new A ();
var b = new B ();

結果:

a
    a1        0
    a2        0
b
    a1        0
    b1
        a2    0
    b2
        a2    0
    b4
        a1    0
        a2    0

実例:

var Point = function (p) {
    if (p == null) p = this;
    var x = 0;
    var y = 0;
    p.getPoint = function () { return [x,y]; };
    p.setPoint = function (_x,_y) { x = _x; y = _y; };
};

var Dimension = function (p) {
    if (p == null) p = this;
    var w = 0;
    var h = 0;
    p.getDimension = function() { return [w,h] };
    p.setDimension = function(_w,_h) { w = _w; h = _h };
};

var Rect = function (p) {
    if (p == null) p = this;
    var dimension = new Dimension(this);
    var location  = new Point(this);
};

var rect = new Rect ();
rect.setDimension({w:30,h:40});
rect.setPoint({x:50,y:50});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.