8

私は Python と Smalltalk のバックグラウンドから Javascript に来ており、この言語における Self と Lisp の系統に感謝しています。ECMAScript5 を使用して、new 演算子を使用せずにプロトタイプの OO を試してみたかったのです。

制約:

  • クラスを作成するオプションの new 演算子
  • instanceof のプロトタイプ チェーンは正しくなければなりません
  • WebInspector デバッグ サポート用の名前付きコンストラクター
  • alloc().init() は、Objective-C や Python のような作成シーケンス

基準を満たすための実装での私の試みは次のとおりです。

function subclass(Class, Base) {
    "use strict";
    function create(self, args) {
        if (!(self instanceof this))
            self = Object.create(this.prototype);
        var init = self.__init__;
        return init ? init.apply(self, args) : self;
    }
    if (Base instanceof Function) Base = Base.prototype;
    else if (Base===undefined) Base = Object.prototype;

    Class.prototype = Object.create(Base);
    Class.prototype.constructor = Class;
    Class.create = create;

    Class.define = function define(name, fn) { return Class.prototype[name] = fn; };
    Class.define('__name__', Class.name);
    return Class;
}

そして、それは単純なモックアップで動作するようです:

function Family(){return Family.create(this, arguments)}
subclass(Family, Object);
Family.define('__init__', function __init__(n){this.name=n; return this;});

function Tribe(){return Tribe.create(this, arguments)}
subclass(Tribe, Family);
function Genus(){return Genus.create(this, arguments)}
subclass(Genus, Tribe);
function Species(){return Species.create(this, arguments)}
subclass(Species, Genus);

クラスをファクトリ関数として使用する:

var dog = Species('dog');
console.assert(dog instanceof Object);
console.assert(dog instanceof Family);
console.assert(dog instanceof Tribe);
console.assert(dog instanceof Genus);
console.assert(dog instanceof Species);

または new 演算子を使用します。

var cat = new Species('cat');
console.assert(cat instanceof Object);
console.assert(cat instanceof Family);
console.assert(cat instanceof Tribe);
console.assert(cat instanceof Genus);
console.assert(cat instanceof Species);

console.assert(Object.getPrototypeOf(dog) === Object.getPrototypeOf(cat))

私の実装でプロトタイプ OO の必要な機能を見落としていませんか? 変更が必要な Javascript の規則や相互作用はありますか? 要約すると、ここでの「落とし穴」は何ですか? また、明らかな改善点はありますか?

コンストラクターの定義を DRYer にしたかったのですが、関数の name プロパティが書き込み可能ではないことがわかりました。これが、WebKit Inspector のオブジェクト名をサポートする理由です。私は自分が望んでいたことを達成するために評価を構築することができましたが、... うーん。

4

4 に答える 4

4

これはあなたの質問の答えにはならないかもしれませんし、おそらくあなたが望んでいることのすべてを実行するわけではありませんが、これは OO JavaScript に関するもう 1 つの方法です。主に構文が気に入っています。理解するのは簡単ですが、あなたのバックグラウンドはありません。

// ------- Base Animal class -----------------------
var Animal = function(name) {
    this.name = name;
};

Animal.prototype.GetName = function() {
    return this.name;
};
// ------- End Base Animal class -----------------------

// ------- Inherited Dog class -----------------------
var Dog = function(name, breed) { 
    Animal.call(this, name);
    this.breed = breed;
};

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

Dog.prototype.GetBreed = function() {
  return this.breed; 
};

Dog.prototype.Bark = function() {
    alert(this.GetName() + ' the ' + this.GetBreed() + ' says "Arf!"');
};
// ------- End Inherited Dog class -----------------------

// Usage
var harper = new Dog('Harper', 'miniature pinscher');
harper.Bark();
于 2012-03-06T22:57:19.113 に答える
4

シェーン 私はあなたのバックグラウンドから来て、Javascript があなたがやろうとしていることとは異なる方法で動作することを伝えることができます. その答えをすぐに嫌う前に、読み進めてください...

私は OOP が大好きで、非常に OOP フレンドリーなバックグラウンドを持っています。Prototype オブジェクトに頭を悩ませるのに時間がかかりました (プロトタイプ メソッドを静的関数と考えてください... 初期化されたオブジェクトでのみ機能します)。JavaScript で行われる多くのことは、優れたセキュリティとカプセル化を使用する言語から来ると非常に「間違っている」と感じます。

「new」演算子を使用する唯一の本当の理由は、複数のインスタンスを作成する場合、またはイベントがトリガーされるまで何らかのタイプのロジックが実行されないようにする場合です。

これが答えではないことはわかっています...コメントを入力するには多すぎました。本当により良い視点を得るには、オブジェクトと変数を作成し、DOM を表示する必要があります...これにより、文字通り任意のコンテキストからどこにでもアクセスできることがわかります。これらの記事は、詳細を記入するのに非常に役立つことがわかりました.

幸運を祈ります。

アップデート

したがって、同じオブジェクトの異なるインスタンスを作成するためにファクトリ メソッドが必要な場合は、次のヒントを参考にしてください。

  • OO カプセル化から学んだ、知っているすべてのルールを忘れてください。これは、プロト オブジェクト、リテラル オブジェクト、およびインスタンス オブジェクトを一緒に使用すると、あなたにとって自然ではない方法で物事にアクセスする方法が非常に多くなるためです。
  • 何らかのタイプの抽象化または継承を使用する予定がある場合は、DOM を使用することを強くお勧めします。いくつかのオブジェクトを作成し、それらを DOM で探して、何が起こっているかを確認してください。既存のプロトタイプを使用して継承をシミュレートできます (拡張するインターフェイスと抽象クラスがないので、私は殺されました!)。
  • JavaScript のすべてがオブジェクトであることを知っておいてください...これにより、いくつかの非常にクールなことを行うことができます (関数を渡したり、関数を返したり、簡単なコールバック メソッドを作成したりします)。JavaScript 呼び出しの '.call()'、'.apply()'、および '.bind()' を見てください。

これら 2 つのことを知っていると、ソリューションを解決する際に役立ちます。DOM をきれいに保ち、適切な JavaScript 開発の実践に従うには、グローバル名前空間 (DOM のウィンドウ参照) をきれいに保ちます。これにより、自分のしていることについて「間違っている」と感じているすべてのことについて、「気分が良くなる」ようにもなります。そして、一貫性を保ちます。

これらは私が試行錯誤して学んだことです。Javascript は、従来の OO 言語との違いに頭を悩ませることができれば、優れたユニークな言語です。幸運を!

于 2012-03-03T04:41:50.313 に答える
1

evalなしで名前付きコンストラクターを作成することはできません。ライブラリが名前空間を実装している場合は、名前が隠されたプロパティを持つコンストラクターだけが見つかります。

残りの質問に答えると、JavaScriptクラスライブラリがたくさんあります。独自に作成することもできますが、正しい方法で実行したい場合は、正しい継承システムを理解して実装するのは少し面倒です。

私は最近、すべてのライブラリを改善するために独自のクラスライブラリを作成しました:ClassfulJS。シンプルなデザイン、使用法、およびサブクラスからスーパーメソッドを呼び出すなどのその他の改善点があるため、一見の価値があると思います(これを実行できるライブラリは見たことがありません。すべて、実行中のスーパーメソッドのみを呼び出すことができます。オーバーライド)。

于 2012-03-06T14:52:12.407 に答える