4

backbone.js の学習を開始する前に、JavaScript で OOP を学習しようとしていました。

データバインドをしたいのですが、うまくいきません。

予算を入力して支出した金額を入力できる予算 Web サイトの簡単なプロトタイプを作成しました。超過した場合は表示されます。

function BudgetItem(spent, budget){

    this.setSpent = function(spent){
        this.spent = spent;
    }
    this.setBudget = function(budget){
        this.budget = budget;
    }
    this.getSpent = function(){
        return this.spent;
    }
    this.getBudget = function(){
        return this.budget;
    }

}

function BudgetType(type){
    this.getType = function(){
        return type;
    }
}

BudgetType.prototype = new BudgetItem();

$(document).ready(function(){

    var food = new BudgetType('food');

    $('.budget').html(food.getBudget());
    $('.editbudget').change(function(){
        food.setBudget($('.editbudget').data())
    });
})

それがこれまでの私のコードです。私はそれを正しく行っているかどうかわかりません。私は物事を拡張することになっていますか?また、誰かがライブラリなしで動的にデータバインドする方法を説明できますか?

4

2 に答える 2

6

まず、いくつかの理論を説明します。Javascript 関数は動的オブジェクトであり、リスナーで行うのと同じようにObject、キーワードを使用して新しいインスタンスを作成できます。newこれが発生すると、関数自体はコンストラクターとして実行され、thisキーワードは新しく作成されたオブジェクトにバインドされます。上記で行っていることは、実際には、初めて値を渡すときにその場で新しいプロパティを追加することです...これは問題ありませんが、別の読者にはあまり明確ではありません.

トリッキーな部分です。すべての関数には、「隠された」Prototype オブジェクトへのリンクがあります。prototypeこれは、JavaScript ランタイムによって作成され、プロパティを通じてユーザー オブジェクトへの参照として渡される匿名 (名前ではアクセスできない) オブジェクトです。この Prototype オブジェクトには、そのconstructorプロパティを介した関数への参照もあります。私が言っていることを自分でテストするには、次のことを試してください。

BudgetItem.prototype.constructor === BudgetItem // true

すべてをまとめると、関数は、舞台裏で作成され、関数のプロトタイプ プロパティを介してアクセスできる (隠された) クラスへのコンストラクターと考えることができます。したがって、次のようにフィールドを Prototype オブジェクトに直接追加できます。

function BudgetItem(spent) { 
    this.spent = spent 
}           
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };

もう 1 つの問題は、継承とコンストラクターへのパラメーターの受け渡しです。繰り返しますが、バージョンは有効ですが、BudgetType を初期化するときに、使用済みと予算の値を渡すことができなくなります。私がすることは、プロトタイプを忘れて行くことです:

function BudgetType(type, spent) {
    var instance = new BudgetItem(spent);
    instance.type = type;
    return instance;
}

これは、Scott Sauyet が上で提案したものに近いですが、より強力です。これで、両方のパラメーター (およびそれ以上) を渡すことができ、より複雑な継承ツリーを持つことができます。

最後に、それ以外の場合は自動変数 (引数として渡されるか、関数内で初期化される変数) に getter を提供することにより、プライベート (または擬似プライベート、より正確には疑似プライベート) プロパティを作成することができます。これは言語の特別な機能であり、次のように機能します。

function BudgetType(type, spent) {
     var instance = new BudgetItem(spent);
     instance.getType = function() {
         return type;
     }
     return instance;
}

これで、obj.getType() によってコンストラクターに渡された「タイプ」にアクセスできますが、初期値をオーバーライドすることはできません。obj.type = 'New Value' を定義しても、 getType() は渡された初期パラメータを返します。これは、オブジェクトが初期化されたときに作成され、クロージャのために解放されなかった別のコンテキストへの参照があるためです。

それが役立つことを願っています...

于 2012-11-13T15:07:04.867 に答える
1

オブジェクトのすべてのインスタンスが同じメンバー/値を参照するようにする場合は、クロージャーを使用できます。

// create a constrctor for you object wrapped in a closure
myCon = (function() {

    // define shared members up here
    var mySharedObj = new function () {
        this.member = "a";
    }();

    // return the actual constructor   
    return function () {
        this.mySharedObj = mySharedObj;
    }
}());

// create two instances of the object
var a = new myCon();
var b = new myCon();


// Altering the shared object from one
a.mySharedObj.member = "b";

// Alters it for all
console.log(b.mySharedObj.member);





他のオブジェクトからオブジェクトを構築したい (他の言語のようなものclass whatever extends baseClass) が、参照を介して値を共有したくない (値のクローンではなく) 場合は、次のようなものを使用できます。

Object.prototype.extendsUpon = (function (_prop, _args) {
    return function (base) {
        for (var key in base) {
            if (_prop.call(base, key)) {
                this[key] = base[key];
            }
        }

        function con(child){
            this.constructor = child;
        }
        con.prototype = base.prototype;

        this.prototype = new con(this);
        this.__base__ = base.prototype;

        var args = _args.call(arguments);
        args.shift();
        base.constructor.apply(this, args);
    }
}(Object.prototype.hasOwnProperty, Array.prototype.slice));


次に、オブジェクトの上にオブジェクトを構築するには:

// Base Object Constructor
function Fruit(name) {
    this.fruitname = name;
}
Fruit.prototype.yum = function() {
    return "I had an " + this.fruitname;
}

// Object constructor that derives from the Base Object
function Favorite() {

    // Derive this object from a specified base object:
    //     @arg0  -> Object Constructor to use as base
    //     @arg1+ -> arguments passed to the BaseObject's constructor
    this.extendsUpon(Fruit, "apple");

    // From here proceed as usual

    // To access members from the base object that have been over-written,
    // use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
    return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();

// Outputs: "I had an apple and it was my favorite" 
mmm.yum();
于 2012-11-13T13:13:10.030 に答える