6

OOとは古典的なOOを意味します。モジュールパターンを使用してプライバシーを提供する「クラス」(javascriptには従来のクラスはありません)を定義することと、オブジェクトリテラルを使用して「パブリックスタティック」のコレクションを作成することの間を行き来しています。

どのタイプの組織を使用するかを決定できる「クラス」を作成するとき、私には指導力がありません。ええと、私のコードがjshintとjslintの両方をパスし、オプションが設定されていないという事実に加えて。

私は約1500行のコードで作業しているので、コードが管理できなくなる前に「ガイド力」が必要であり、それを廃棄する必要があります。

私はJavaScriptで「クラス」を書くさまざまな方法をよく知っています。AlexMacCawによって作成されたJavaScriptWebアプリケーションによって教えられたものと、ここにSOにリストされているさまざまな方法。

ただし、アプリケーションに関しては、どの方法を使用すればよいかわかりません。

最も単純なのは、次のようなオブジェクトリテラル内のメソッドと変数のコレクションのようです。

var public_statics = {
    public_func: function () {},
    public_var: "hello"
}

そして最も複雑なのは-IIFEのようです。

(function(){
    var private_var;
    function private_func(){
    }
})();

どちらを使用するか、またはその間のバリエーションが多数あるかをどのように知ることができますか?

具体的な例として、MVCのコントローラーについてはどうでしょうか。

現在(そしてランダムに選択されたものもありますが)、私は次のようなコントローラーを実装しています:

var Co = {};
Co.Controller = function(){
    // 'classes' from Mo are called here
    // 'classes' from Su are called here
}

それから私はCoに他のコントロール関連の方法に取り組みます。

使用するOOのスタイルを選択するにはどうすればよいですか?


更新しました

私のライブラリは現在、4つの名前空間に分割されています。

var Mo = {},
    Vi = {},
    Co = {},
    Su = {};

モデル、ビュー、コントローラーは自明である必要があり、(サポート)サポートはMVCに含まれていないすべての「クラス」(DOMアクセス、エフェクト、デバッグコードなど)を対象としています。

このライブラリ/コードをさらに整理するには、どのOOスタイルを使用する必要がありますか?

コントローラの「クラス」の例:

/**
 **  Controller
 */

Co.Controller = function (o_p) {
    var o_p_string_send;
    Su.time();
    o_p = Mo[o_p.model].pre(o_p);
    if (o_p.result !== 'complete') {
        o_p_string_send = JSON.stringify(o_p);
        Su.time();
        //Su.log(o_p_string_send);
        Co.serverCall('pipe=' + o_p_string_send, function (o_p_string_receive) {
            Su.time();
            //Su.log(o_p_string_receive);
            o_p.server = JSON.parse(o_p_string_receive);
            Mo[o_p.model].post(o_p);
            Su.time(true);
            Su.log('Server time: [' + o_p.server.time + ']');
        });
    }
};
4

3 に答える 3

2

IFFEs は読みにくいことが多く、個人的には、なぜそんなに主流になったのかわかりません。コードは読みやすく簡潔であるべきだと思います。言語仕様の一部ではない言語の動作をシミュレートしようとすることは、多くの場合、非常にばかげた考えです。

たとえば、JavaScript は多重継承、ポリモーフィズム、その他多くの興味深いパラダイムをサポートしていません。そのため、多くの場合、JS でポリモーフィズムやプライベート メンバーなどを使用して、ある種のクレイジーな方法を作成しようとしている人々を目にします。これは間違いだと思います。

私は現在、高性能の JS データ構造ライブラリに関する一種の趣味のプロジェクトとして取り組んでいます (Google のクロージャーや他の多くのものを凌駕しようとしています)。C++ と Java のバックグラウンドを持つ私は、クラスを作成するのが好きで、継承などが好きです。いくつかのコード スニペットを共有させてください。最初は、次のようなものを書いていたので、自分が賢いと思っていました。

function __namespace(n, v) {
    return {"meta":{"namespace":n,"version":v}};
}

var FJSL = FJSL == undefined ? new __namespace("Fast JavaScript Library", 0.1) : FJSL;

__using = function(parent, child) {
    clazz = new child();
    clazz.super = new parent();
    if (clazz.super == undefined) return clazz;
    for (a in clazz.super) {
        for (b in clazz) {
            if (a == "constructor" || b == "constructor") continue;
            if (clazz[b] === clazz.super[a]) continue;
            if (a == b && typeof clazz[b] != typeof clazz.super[a]) throw "Typesafety breached on '" + a + "' while trying to resolve polymorphic properties."; 
            if (a == b && typeof clazz[b] == typeof clazz.super[a]) {
                clazz["_"+a] = clazz.super[a];
            } else if (clazz[a] == undefined) {
                clazz[a] = clazz.super[a];
            }
        }
    }
    return clazz;
};

そして、私はそれを次のように使用していました(単純なキューの例で):

FJSL.Array = function() { 
    this.data = [];

    this.contains = function(idx, element) {
        for (var i = idx; i < this.data.length; i++) {
            if (this.data[i] === element)
                return i;
        }
        return -1;
    }

    this.size = function() {
        return this.data.length;
    }
}

FJSL.Queue = function() {
    return __using(FJSL.Array, 
    function() {
        this.head = 0;
        this.tail = 0;

        this.enqueue = function(element) {
            this.data[this.tail++] = element;
        };

        this.dequeue = function() {
            if (this.tail == this.head)
                return undefined;
            return this.data[this.head++];
        };

        this.peek = function() {
            return this.data[this.head];
        };

        this.size = function() {
            return this.tail - this.head;
        };

        this.contains = function(element) {
            return this._contains(this.head, element);
        };
    }
)};

あなたは、私がどのように継承を偽装しているかに気付くでしょう (Queue は Array を使用します、har har、私は賢いです)。しかし、これは a ) 読んb) 理解するのには絶対に正気ではありません。このミームを思い出さずにはいられませんでした:

ここに画像の説明を入力

この手の込んだ前処理と後処理をすべて実行しようとせずに、機能的に同等のコードをお見せしましょう。

FJSL.Queue = function(opts) {
    this.options = opts;
    this.head = 0;
    this.tail = 0;
    this.data = [];
};

FJSL.Queue.prototype = {
    add : function(element) {
        this.data[this.tail++] = element;
    },

    enqueue : function(element) {
        this.data[this.tail++] = element;
    },

    dequeue : function() {
        if (this.tail == this.head) {
            return undefined;
        }
        return this.data[this.head++];
    },

    peek : function() {
        return this.data[this.head];
    },

    size : function() {
        return this.tail - this.head;
    },

    contains : function(element) {
        // XXX: for some reason a for : loop doesn't get JIT'ed in Chrome
        for (var i = this.head; i < this.data.length; i++) {
            if (this.data[i] === element) {
                return true;
            }
        }
        return false;
    },

    isEmpty : function() {
        if (size) {
            return true;
        }
        return false
    }, 

    clear : function() {
        this.data = [];
    }
};

明らかに、配列を使用する可能性のある他の構造のプロトタイプ コンストラクターを複製する必要がありますが、私が達成しようとしていることは非常に明確であり、初心者の JS プログラマーでも何が起こっているかを知ることができます。それだけでなく、人々がコードを変更したい場合、どこに行って何をすべきかを正確に知っています。

私の提案は、JS を C++ や Java のように動作させようとする狂気に巻き込まれないことです。それは決して行くつもりはありません。ええ、継承とプライベート/パブリック/保護されたメンバーを偽造することはできますが、JS はそれを意図したものではありません。この種の肥大化したコード (非標準の動作をシミュレートしようとする) の影響は、高性能の Web アプリとその同類に非常に負担がかかると思います。

要するに、オブジェクト リテラルを使用することをお勧めします。

var public_statics = {
    public_func: function () {},
    public_var: "hello"
}

理解しやすく、変更しやすく、拡張しやすいです。誰かが誤って「プライベート」変数を変更した場合にシステムがクラッシュして燃えるほど壊れやすい場合は、単にそれを文書化する必要があります。

于 2012-08-22T20:40:39.727 に答える
1

メソッドを非公開にできるという理由だけで、個人的には IIFE を好みます。そうしないと、アンダースコアを使用してある種の奇妙な規則を実行する必要があります。

さらに、スタイル的には、関数内にカプセル化する場合、セミコロンを作成するオプションがあります-そのプレーンな古いjavascript. オブジェクト リテラルの各行をコンマで終了する必要があるのは、私にはおかしいと思います。

于 2012-08-22T20:20:06.780 に答える
0

JavaScript 言語自体はさまざまな方法で実装されているため、つまり、ブラウザごとに異なるため、すでに一貫性のないところから始めなければなりません。

JavaScript は従来の継承を直接サポートしていません。(プロトタイプの継承をサポートしています)。

私のニーズでは、古典的な継承を実装しないことを選択します。これは理想的ではありません。従来の継承により、ベスト プラクティスの OO (カプセル化、継承、ポリモーフィズム) を直接実装できます。

ただし、言語が古典的な継承などを介して OO を直接サポートするまで待つことを好みます。

それまでは、基本的なプロトタイプの継承を使用して、コードを再利用できるようにします。

于 2012-08-25T17:26:09.103 に答える