0

Javascriptでの継承を少し単純化したいと思っています。私がこれまでに集めたものから、「クラス」間の「継承」を達成するための良い方法は次のとおりです。

function ParentClass() {
    //Parent Constructor
}

ChildClass.prototype = new ParentClass(); //Step 1: Use parent as prototype
ChildClass.prototype.constructor = ChildClass; //Step 2: Designate appropriate constructor
function ChildClass() {
    ParentClass.call(this, arguments); //Step 3: Call the parent's constructor from the child's

    //Child Constructor
}

上記のラベルを付けたように、プロセスを3つの「ステップ」に分割するのが好きです(ステップ1、2、および3)。これらの3つのステップすべてを1つの関数(Javaのバックグラウンドから取得し、「extend」とラベル付けしました)に入れて、次のように関数コンストラクターオブジェクトから呼び出すことができます。

function ParentClass() {
    //Parent Constructor
}

ChildClass.extend(ParentClass); //Execute steps 1, 2 and 3 all in this function
function ChildClass() {
    //Child Constructor
}

これは私がこれまでに持っているものです:

Function.prototype.extend = function (parent) {
    var oldConstructor = this.prototype.constructor;
    this.prototype = new parent(); //Step 1
    this.prototype.constructor = function (arguments) { //Step 2
        parent.apply(this, arguments); //Step 3
        oldConstructor(arguments);
    };
}

このコンテキストでは、extend関数のステップ1と2は正常に機能しますが、ステップ3で問題が発生します。私がやろうとしているのは、子のコンストラクター関数を、親のコンストラクターを呼び出してから子のコンストラクターを呼び出す新しい関数に置き換えることです。ただし、これを実行すると、親コンストラクターが呼び出されません。問題を特定できませんでした(「this」キーワードを正しく使用していますか?)。おそらく私はこれに間違った方法でアプローチしています。これを行う関数を作ることは可能ですよね?どうすれば機能する「拡張」機能を作成できますか?

アップデート:

本当の問題は、「this」キーワードの使用にあるようです。これが私が今見ているコードです:

function ParentClass(x) {
    this.value = x;
}

function ChildClass() {
}
ChildClass.extend(ParentClass);


function testtest() {
    var a = new ParentClass("hello world"); //Alerts "hello world"
    alert(a.value);
    var b = new ChildClass("hello world"); //Alerts "undefined"
    alert(b.value);
}

最初のアラートが機能し、2番目のアラートが機能しないのはなぜですか?「これ」とは、関数が実行されているコンテキストを指していると思いました。どちらの場合も、コンストラクター(aまたはb)を呼び出すオブジェクトになります。

4

2 に答える 2

2

本当にこれをやりたいのなら、おそらくCoffeescriptを使うべきです。または、少なくともそこからいくつかのアイデアを得てください。

Javascript の上でクラスと継承を透過的にサポートし、ここで使用しているのとほとんど同じアイデアを使用してそれを行います。

これが学術的な演習である場合は、ぜひ先に進んでください (Coffeescript がどのようにアイデアを得るかを確認してください)。しかし、それ以外の場合は、車輪を再発明する必要はありません。

直接比較するには、次をhttp://js2coffee.org/に貼り付けます。

class Shape
  area: -> undefined
  name: -> "Shape"

class Rectangle extends Shape
  constructor: (w, h) ->
    @w = w
    @h = h

  area: ->
    @w * @h

  name: -> "Rectangle" + super

Rectanglename()は を返すようになりRectangleShapeました。名前はばかげていますが、どのように機能するかがわかりsuperます。

JS でどのように見えるか (__extends関数内のすべての配管に注意してください):

var Rectangle, Shape,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

Shape = (function() {

  function Shape() {}

  Shape.prototype.area = function() {
    return void 0;
  };

  Shape.prototype.name = function() {
    return "Shape";
  };

  return Shape;

})();

Rectangle = (function(_super) {

  __extends(Rectangle, _super);

  function Rectangle(w, h) {
    this.w = w;
    this.h = h;
  }

  Rectangle.prototype.area = function() {
    return this.w * this.h;
  };

  Rectangle.prototype.name = function() {
    return "Rectangle" + Rectangle.__super__.name.apply(this, arguments);
  };

  return Rectangle;

})(Shape);
于 2013-03-21T19:58:24.647 に答える
1

2 番目のブロックのコードが同じ順序でステップを実行していないことに気付きました。extend を呼び出した後に関数を宣言すると、extend 関数によって作成されたコンストラクターがオーバーライドされます。最初に子クラスを宣言してから、それを拡張してみてください。

これは私のために働く:

function Parent() {
  console.log("Parent Constructor");
}

function Child() {
  console.log("Child Constructor");
}

Child.extend(Parent);

new Child()

出力:

Parent Constructor
Child Constructor
于 2013-03-21T20:24:58.123 に答える