2

最近、もう少し高度な JavaScript を学び始め (jQuery はいくつかの単純なタスクにしか使用していませんでした)、Alex MaxCaw の本「JavaScript Web アプリケーション」を購入しました。最初の章では、単純なクラス エミュレーターの作成について説明します。以下のコメントでマークされた2行のコードを除いて、ほとんどすべてを理解しています。

var Class = function(parent) {

    var _class = function() {
        this.init.apply(this, arguments);
    };

    if(parent) {
        var subclass = function() {};
        subclass.prototype = parent.prototype;
        _class.prototype = new subclass();
    };

    _class.prototype.init = function() {};

    _class.fn = _class.prototype;

    //????
    _class.fn.parent = _class;

    //????
    _class._super = _class.__proto__;

    return _class;
};

これらの2行の目的は何ですか?とても感謝しています。

4

2 に答える 2

3

コードのウォークスルー:

  • クラスは、提供された引数で init を呼び出す関数として定義されます。newこれは、 egを使用して標準のコンストラクター構文で呼び出すことができることを意味します。適切な値で呼び出されvar instance = new Thingy()た関数を取得します。initthis
  • 親クラスを渡すと、そのクラスのprototypeプロパティが新しい空のオブジェクトのプロトタイプ チェーンに追加され、それがその prototypeプロパティとして使用されます。最新のブラウザーでこれを行うより簡潔な方法は次のとおりです。_class.prototype = Object.create(parent.prototype);
  • init関数が定義されています。これは、インスタンスが作成された後に、より便利な初期化コードでオーバーライドされる可能性があり_classます (または、クラスの作成時に関数を渡すことができるようにコードを変更する必要がありinitます... または、インスタンスがプロトタイプ チェーンをたどって検索できるようにする必要があります)。その他のinit機能。
  • _class.fn_classコンストラクターのプロトタイプ関数への参照を提供するために作成されます。
  • _class.fn.parentコンストラクターへの参照を提供するために作成されます。これは、プロトタイプを他のコンテキストに適用していて、プロトタイプのコンストラクターへの参照が必要な場合に役立ちます。
  • _class._superコンストラクターの内部の非標準__proto__プロパティが割り当てられます。コンストラクターは関数であり、Javascript では関数はオブジェクトであることに注意してください。これは、独自の内部プロトタイプがあることを意味します。以前の への参照prototype、このコンストラクターで作成されたオブジェクトに割り当てられたプロトタイプであり、コンストラクターのプロトタイプ自体ではありません。すべての関数は Function.prototype から継承します。ここでbindapplyなどを取得します。_superこの場合は への参照にすぎませんFunction.prototype

このタイプの_superがいつ使用されるかについては、次のことを想像できます。

function Maker(){                  //this will be called as a constructor, ie. with new 
  var fun = function(){};          //Make a function
  fun.__proto__ = this.__proto__;  //yuck. Set the function's this value to the instance
  return fun;                      //return the function
}

Maker.prototype={say:function(){console.log("Javascript is fun!.. And weird.")}};

var fun = new Maker();
fun.say()                   //"Javascript is fun!.. And weird."
console.log(fun.__proto__)  // Object{say:function}
console.log(fun.bind)       // undefined!!

うわー!今何があったの?実際、関数の内部プロトタイプをオブジェクトに置き換えました。これにより、興味深いプロトタイプ チェーンを構築し、関数とオブジェクトの両方を同様の方法で操作できます。ただし、 とのリンクFunction.prototypeは切断されているため、 にアクセスできないことに注意してくださいbind。でも、もっと原型魔法で直しましょう!

function FunctionConnector(obj){
  for (var prop in obj){
    if(obj.hasOwnProperty(prop){
      this.prop=obj.prop
    }
  }
}

FunctionConnector.prototype=Function.prototype;

Maker.prototype=new FunctionConnector({say:function(){
                                       console.log("Javascript is fun!.. And weird.")
                                      }});

var fun = new Maker();
fun.say()                   //"Javascript is fun!.. And weird."
console.log(fun.__proto__)  // Object{say:function}
console.log(fun.bind)       // function bind(){ [native code] }

今それは何FunctionConnectorですか?オブジェクトを受け取り、コンストラクターとして呼び出されると、渡されたオブジェクトのすべてのプロパティを持ち、かつ から継承するオブジェクトを返しますFunction.prototype。ご覧のとおり、 へのアクセスbindが戻ってきました (もちろん、元の実装でFunction.prototype.bind.call間に合わせて、勝利への道を進むこともできました)。

この新しいパターンを手に入れると_super、コードで何をするのか、つまり、作成しているコンストラクターの組み込みプロトタイプを参照することがより明確になる場合が_classあります (この例では、 のインスタンスは にFunctionConnectorなります_super)。この参照を使用して、実行時にプロトタイプにパッチを適用したり、メソッドを呼び出しapplyたり、オブジェクトへの参照を使用できるその他のことを行うことができます。

これは、特に__proto__非標準であるため、少しハックに気づいたかもしれません。しかし、それが可能にするパターンを楽しむなら、それはややきれいでもあります. Javascript の継承に関する知識に自信がある場合にのみ、このようなことを行うことをお勧めします。また、コード ベース全体を担当している場合を除き、そうではない可能性もあります。

于 2013-09-26T21:39:22.700 に答える