Kity筆記(五)の初歩を勉強します.

10110 ワード

過去二週間ぐらいで、kity、kityminder、nodejs、seajsなどの一連のプロジェクトを勉強しています.一部の認識は一定の時間を経て勉強して、すでに変化が発生しました.元のノートは時代遅れになりました.
Kityとkityminderの構築部分(grunt関連)もこの二日間見て、baiduの開発者に教えてもらいました.既存の構築できない問題を解決しました.コード自体を順調に勉強できます.このプロジェクトの中原にはmd形式の文書がいくつかあります.今見ても分かります.文書の第一章は基礎フレームです.Classシステムです.これはkityとkityminderの中ですべて大量の(重度)に依存されて使って、そのためとても注意深く分析する必要があって、惜しいもとの工事のはKity Graphics OOP文書が書いていないので、だから先に自分でコードを見て学ぶことしかできません.
kityプロジェクトでは、Classシステムがsrc/core/class.jsで実現され、 src/kity.jsエントリモジュールに引用されます.
クラスシステム
このモジュールはkity(kityminderも含む)のOOPサポートを提供します.
まずクラスクラスクラスを定義しました.すべてのkityクラスの基質として、このクラスも引き出します. (exports)
function Class() {
  //       ,         .
}
 
クラスはメンバー関数のセットを提供しています.クラスのシステムを作るのを助けています.このようなシステムは継承しやすく、混入して、クラスのメタ情報(例えば類名、親類)などを得ています.
//      Class          ,             .
class Class {
  //            ,    name       .
  //     :
  // Sub_Class.toString() = function() {
  //   //         toString()   .     c#/java   super/base   .
  //   return 'Hello ' + this.base('toString');
  // }  
  //          .
  function base(name) {
    // 1.             ,          .
    //         base()         ,         .
    var caller_method = arguments.callee.caller;

    // 2.         ,           Sub_Class.
    //   :       (   base  )      __KityMethodClass   .
    //                    .
    var method_class = caller_method.__KityMethodClass;

    // 3.        (  ).        class      __KityBaseClass.
    var base_class = method_class.__KityBaseClass;

    // 4.           .         prototype  (        ).
    var base_method = base_class.prototype[name];

    // 5.        (  this       this),            ...
    base_method.apply(this, ...arguments...);
  }
}
既存のコードは比較的簡単に書かれています.分かりやすくするために、一言に変えました.ここのポイントは必要な方法にあります.  __KityMethodClass属性、およびサブクラスには__uがあります.KityBaseClass属性.これらの属性がないと、この方法は実現できません.これらの属性を確立し、Classシステムの設計の重要な範囲に属しています.
そこでここにいくつかの問題を残します.  問題1:これら __KityXXX属性はいつ、どこで生まれましたか? (後に回答があります)  問題2:このベースを使って需要を呼び出せる他の方法がありますか?  問題3: ベース需要を実現するために支払うこれらのコストは価値がありますか?
 
==
まずクレアクラスの部分を詳しく調べてみます.
/*      .      classname   , defines     .
 *     (        ,            ):
 * Class.createClass('Cat', {
 *   base: Animal,      
 *   mixins: [Walkable],
 *   constructor: function() ---       
 *                 /   : this.callBase(), this.callMixins()
 *   toString: function() ---     .
 * });
 */
export function createClass(classname, defines) {
  // 1.     ,         Class      ,          .
  //        kity     createClass()     ,         Class   .
  var BaseClass = defines.base || Class;

  // 2.         ,             .         .
  var ctor = defines.constructor || default_ctor;

  // 3.   (  )  .
  var NewClass = inherit(ctor, BaseClass, classname);
  //   : ...       ,     ...       inherite()       .

}
 
関数inherite()は、新しいクラスを定義するために使用され、指定されたベースクラスBaseClassから継承されます.
function inherite(ctor, BaseClass, classname) {
  // 1.       eval()       ,            :
  //       ,      classname='Cat'
  class-define-string := function Cat(__inherite_flag) {
    if (__inherite_flag != KITY_INHERIT_FLAG) {
      KityClass.__KityConstructor.apply(this, arguments);
    }
    this.__KityClassName = KityClass.__KityClassName;
  }
  var KityClass = eval(class-define-string);  //       .

  //            .
  // 1.    __inherite_flag   ,            KITY_INHERITE_FLAG
  //         ctor   .           .
  // 2.         (this)    __KityClassName   .

  //   ...
}
この部分のコードは問題1の一部であるインスタンスの_u u u u u u u u u_uと答えています.KityClass Name属性は作成されたコンストラクションに設定されています.しかし、私はまた新しい問題が生まれました.4:なぜここでeval()の方法を使ってクラスを生成しますか?
上記の関数で定義された実際のkity.Point類を例に挙げます.
class kity.Point {
  //               Point     .
  static string __KityClassName = 'Point';        //      .
  static string __KityMethodName = 'constructor'; // Point()         .
  static Class __KityBaseClass = Class;    //   .
  static Class __KityMethodClass = Point;  // Point()      Point  .
  static function __KityConstructor = point_ctor(x,y); // Point        .

  //       Point.prototype        .
  constructor = Point;   //     constructor      Point  .
  function toString() ...      //        .
  
  //         ...
}
ブラウザdebugger/consolieで見ると、kity.Pointオブジェクトは、上記のような構造が見られます.
 
kity.Pointの例を作成すると、var p=new kity.Point(3,4);pを観察すると、次のようになります.
p = {
  x: 3, y: 4,
  __KityClassName: 'Point' //    eval    Point          ...,       ?
}
forでpのプロパティを巡回します.
> for (var i in p)
    if (p.hasOwnProperty(i))
      console.log(i);
>    : x, y, __KityClassName
 
p.hasOwnProperty(i)を限定しないと基質クラスからの方法が多く表示されます.ここでは省略します.
学習研究のためにmixinに関するホームページを検索します.   http://www.cnblogs.com/snandy/archive/2013/05/24/3086663.html    http://www.cnblogs.com/snandy/archive/2013/05/27/3097429.html 中にはBackboneと言ってmixinが広く使われています.
==
次にinheit()関数の後ろの部分を見ます.
function inherit(ctor, BaseClass, classname) {
  //     eval()        .
  var KityClass = eval(...);
  //   KityClass     static    __KityConsturctor.       1.
  KityClass.__KityConstructor = ctor;
  
  //       .          ,              ,    
  //     Class     . (  5)
  //       KITY_INHERIT_FLAG         ,         . (  6)
  var proto = KityClass.prototype = new BaseClass(KITY_INHERIT_FLAG);

  //           (   )           . (  7:   ?)
  var base_proto = BaseClass.prototype;
  for (var name in base_proto) {
    if (base_proto.hasOwnProperty(name) && name.not_include_Kity)
      proto[name] = base_proto[fname];
  }

  //          constructor.
  proto.constructor = KityClass;

  return KityClass;  //        .
}
そしてますます多くの問題があります.   問題5:クラスをデフォルトクラスとして使わなくてもいいですか?あるいは根本的に私達の新しい種類は要らないですか?   問題6:KITY_インペリットFLAGはオブジェクトを使うほうがいいですか?   問題7:なぜ基質の原型上の属性と方法を新しいクラスにコピーしますか? このようにすると何か長所と短所がありますか?
まず、問題7自体が正しいかどうか、すなわち属性と方法がサブクラスにコピーされているかを検証します.
for (var i in kity.Class.prototype)
  if (Class.prototype.hasOwnProperty(i))
    console.log(i);
  : base, mixin, pipe   Class   .

for (var i in kity.Point.prototype) 
  if (Point.prototype.hasOwnProperty(i)) 
    console.log(i);
  : base, mixin, pipe  ;     offset, valueOf, toString   Point    .
今はNewClassが作成されました.関数createClass()で次のステップを行います.
export function createClass(classname, defines) {
  //           createClass(),        .
  var NewClass = inherit(ctor, BaseClass, classname);
  //            ,        (       ).
  NewClass = mixin(NewClass, defines.mixins)
 
  //   ...
}

//      mixin    kity.Curve    .
function mixin(NewClass, mixins) {
  if (mixins is not Array) return;  //      .
  
  //   NewClass        __KityMixins,           .
  NewClass.__KityMixins = {
    constructor: []
  };

  // mixins      ,       mixin.
  for-each (mixin in mixins) {
    //    mixin.prototype      (  ),       __Kity    .
    for-each-own-property (method in mixin.prototpye) {
      //   mixin          NewClass   .
      //   __KityMixins        .     ctor          .
      NewClass.prototype[method] 
          = NewClass.__KityMixins[method]
          = mixin.prototype[method];
    }
  }
}
 
実際のブラウザはCurveクラスを調べます.
class Curve {
  static object __KityMixins = {
    constructor: [PointContainer],  //           .
    addItem: function, //       1.
    ...         ...            ?
  }
  static prototype: {
    addItem: function, //       
    ...          ...
  }
}
Curiveが確かにいくつかの方法に混入されていることを示します.mixinも他の種類の方法/属性をターゲットクラスのprototypeにコピーします.
次にクレアクラスを見ます.
export function createClass(classname, defines) {
  //      ,         .
  var NewClass = inherit-and-mixin(...);
  

  //      NewClass      __Kity        .
  //        .         1.
  //   ctor   this.__KityClassName = KityClass.__KityClassName;      .
  NewClass.__KityClassName = ctor.__KityClassName = classname;
  //         ,    BaseClass     .
  NewClass.__KityBaseClass = ctor.__KityBaseClass = BaseClass;
  //    NewClass   ctor     ,     method name,class   .
  NewClass.__KityMethodName = ctor.__KityMethodName = 'constructor';
  NewClass.__KityMethodClass = ctor.__KityMethodClass = NewClass;

  //               .
  delete defines.base, .mixins, .constructor;

  //      ,   defines            NewClass   prototype  .
  NewClass = extendClass(NewClass, defines);
  return NewClass;
}
 
ここではNewClass(クラスとしても、関数としても)にいくつかの__を設定しています.KityXXX属性は、実際にkity.Curve類を調べてみます.
class Curve {
  static string __KityClassName = 'Curve';
  static string __KityMethodName = 'constructor';
  static object __KityMixins = { ... };  //      .
  static Class __KityBaseClass = Path;  // Curve      Path  .
  static Class __KityMethodClass = Curve;  //         Curve    .
  static function __KityConstructor = ...; //       ctor()   .

  static prototype = {
    __KityClassName: 'Path',  //     prototype     ,     .
    constructor: Curve,  //    .
  }
}
最後のextendClassを以下に考察します. 方法:
export function extendClass(BaseClass, extension) {
  if (extension is kity-defined-class)
    extension = extension.prototype;  //      .

  //    extension       .        method-name    ...
  //       __Kity    ,   constructor   ...
  for-each-own-property (method-name in extension) {
    //          BaseClass   prototype  .
    var method = BaseClass.prototype[method-name] = extension[method-name];
    //        `  '   ...? (  8)
    method.__KityMethodClass = BaseClass;
    method.__KityMethodName = method-name;
  }
}
そこでここで私達は新しい問題が発生しました.  (1)ここではmethodいつもの方法を仮定していますが、extensionには属性が含まれています. この属性があると仮定します.      cache:{a:1,b:2}ここで処理するとcacheになります.  (2)常にmethodに_を添加するKityXXXの二つの属性は、base()、calBase()をサポートするためのいくつかの方法で、       少数の用途のために、各関数にものを追加します.コストは高すぎますか?それとも他の方法がありますか?       それとも私達は心を安らかに実現すればいいですか?
後ろのkityは、kityminderのすべての種類(現在見ているコードによると)がcreateClass()の方法で作成されたので、kityのシステムに合っているので、詳しく分析しなければなりません.ここを理解して、他の部分のコードを勉強するのにも役立ちます.
時間があれば、他のクラスの創建類の方式を見てみたいです.研究よりも示唆があるかもしれません.