zoukankan      html  css  js  c++  java
  • MooTools 1.4 源码分析 Class 修正版

        MooTools最重要的两个核心模块,一个是Type,另一个就是Class,Type的源码分析已经有棍子上的萝卜分析了1.3版本的了,Class的源码分析网上只有1.2版本的,在1.3版本已经有了大的改变,现在把1.4版的Class尝试分析下,如理解有误欢迎指正:

     

    View Code
      1     /*
    2 ---
    3
    4 name: Class
    5
    6 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
    7
    8 license: MIT-style license.
    9
    10 requires: [Array, String, Function, Number]
    11
    12 provides: Class
    13
    14 源码分析: 苦苦的苦瓜(http://www.cnblogs.com/hmking)
    15
    16 ...
    17 */
    18
    19 (function () {
    20
    21 // #region Class
    22
    23 var Class = this.Class = new Type('Class', function (params) {
    24 // 如果参数是一个函数,当作构造函数处理,自动变为一个对象字面量,例如:
    25 // var Barn = new Class(function(name){ this.fowl = name; });
    26 if (instanceOf(params, Function)) {
    27 params = { initialize: params };
    28 }
    29
    30 // 先新建一个函数作为新建的类的原型
    31 // 然后调用extend函数把Class所有的特性复制给newClass
    32 // 然后params对象implement到newClass类中,这里调用的implement是Class的implement方法
    33 var newClass = function () {
    34 // 复制前先解除关联,为什么要剥离?因为原型继承,包含引用类型的原型属性会被所有实例共享啊......
    35 reset(this);
    36 // 判断是否处于类的设计阶段
    37 if (newClass.$prototyping) { return this; }
    38 this.$caller = null;
    39 // 类的实例运行阶段调用类本身的构造函数,将参数原样传递
    40 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
    41 this.$caller = this.caller = null;
    42 return value;
    43 } .extend(this).implement(params);
    44
    45 // 将newClass的构造函数设为Class
    46 newClass.$constructor = Class;
    47 // 指定newClass的原型的$constructor,使之可以正确的instanceOf
    48 newClass.prototype.$constructor = newClass;
    49 // this.parent可以访问父类的被覆盖的方法
    50 newClass.prototype.parent = parent;
    51
    52 // 返回了这个被包装过的类
    53 return newClass;
    54 });
    55
    56 // this.parent可以访问父类的被覆盖的方法
    57 var parent = function () {
    58 if (!this.$caller) {
    59 throw new Error('The method "parent" cannot be called.');
    60 }
    61 // 通过$name属性取得类方法名称
    62 var name = this.$caller.$name,
    63 // 通过$owner属性得到类对象(不是类的实例),调用类的静态属性parent的到父类对象
    64 parent = this.$caller.$owner.parent,
    65 // 取得父类原型中的同名方法
    66 previous = (parent) ? parent.prototype[name] : null;
    67 // 如果父类中不存在同名的方法,它就抛出一个错误
    68 if (!previous) {
    69 throw new Error('The method "' + name + '" has no parent.');
    70 }
    71 // 调用父类中的方法
    72 return previous.apply(this, arguments);
    73 };
    74
    75 /**
    76 * 对象的剥离(也就是clone),这里要详细说明一下reset函数的工作原理:
    77 * 首先创建了一个新的空函数F,然后将F的prototype属性设置为作为参数object传入的原型对象,prototype属性就是用来指向原型对象的,通过原型链机制,
    78 * 它提供了到所有继承而来的成员的链接,最后通过new运算符作用于F创建出一个新对象返回。这个新的对象就是一个以给定对象为原型对象的空对象,
    79 * 以下面的例子来解说,先执行reset(b)语句,然后读取b.ref.x的值,这时你得到的是其原型对象的同名属性值,其实是一个返指最初的a.x的链接,
    80 * 而在这之后你写入b.ref.x一个新值,也就是直接为b.ref对象定义了一个新的属性x,这时你再读取b.ref.x就不是指向a.x了
    81 * 如果想详细了解原型式继承可翻阅JavaScript设计模式一书,非常棒的一本书,真的很棒!!!哈哈......
    82 * var a = { x: 1 };
    83 * var b = { y: 2, ref: a };
    84 * log.info('b.ref == a : ' + (b.ref == a)); //输出true
    85 * log.info(b.y); // 输出2
    86 * log.info(b.ref.x); // 输出1
    87 * reset(b); //解除引用
    88 * log.info('b.ref == a : ' + (b.ref == a)); //输出false
    89 * log.info(b.y); // 输出2
    90 * log.info(b.ref.x); // 输出1
    91 * b.ref.x = 10;
    92 * log.info(b.ref.x); // 输出10
    93 * log.info(a.x); // 输出1
    94 **/
    95 var reset = function (object) {
    96 for (var key in object) {
    97 var value = object[key];
    98 switch (typeOf(value)) {
    99 case 'object':
    100 var F = function () { };
    101 F.prototype = value;
    102 object[key] = reset(new F);
    103 break;
    104
    105 case 'array':
    106 object[key] = value.clone();
    107 break;
    108 }
    109 }
    110 return object;
    111 };
    112
    113 /**
    114 * @function: wrap
    115 * @description: 将一个方法用wrapper函数重新包装,添加下面几个静态属性
    116 * @$owner - 类本身
    117 * @$origin - 指向未被包装的函数
    118 * @$name - 类的方法名称
    119 * @returns: (funciton) 包装过后的函数
    120 **/
    121 var wrap = function (self, key, method) {
    122 // 如果函数已被父类包装过,则调用最初未被包装的函数(函数的原始形态,呵呵)
    123 if (method.$origin) {
    124 method = method.$origin;
    125 }
    126 var wrapper = function () {
    127 // 如果方法设置了$protected属性,说明此方法不希望在类外面被调用,也就是类的实例不能调用类中设置了$protected属性的方法,只可远观而不可亵玩也,呵呵......
    128 // 但是如果一个类继承另一个类,同时在子类中覆盖了父类中设置了$protected属性的方法,在子类的实例中调用此方法就不会弹出错误警告了。
    129 // 当然如果子类的同名方法同样设置了$protected属性,那么子类的实例同样不能调用此方法。
    130 if (method.$protected && this.$caller == null) {
    131 throw new Error('The method "' + key + '" cannot be called.');
    132 }
    133 // 缓存类实例的caller和$caller两个属性
    134 var caller = this.caller,
    135 current = this.$caller;
    136 this.caller = current;
    137 // 将类实例的$caller属性指向调用的方法本身,Function的caller属性在Class中的完美模拟,这样parent函数才可以运行啊,呵呵......
    138 this.$caller = wrapper;
    139 // 挂为原型上的方法执行
    140 var result = method.apply(this, arguments);
    141 // 方法执行完毕将类实例caller和$caller两个属性值还原
    142 this.$caller = current;
    143 this.caller = caller;
    144 return result;
    145 } .extend({ $owner: self, $origin: method, $name: key });
    146 return wrapper;
    147 };
    148
    149 // 又见implement函数,第三次了,呵呵,这里是扩展类的方法属性
    150 var implement = function (key, value, retain) {
    151 // 首先检查类的的每一个属性和方法在Class.Mutators对象的是不是有mutator函数的对应的名字在里面。
    152 // 如果找到了,它就调用这个函数并且把键的值传给它做处理。
    153 if (Class.Mutators.hasOwnProperty(key)) {
    154 value = Class.Mutators[key].call(this, value);
    155 // 判断mutator函数有没有返回值,如果没有则退出。
    156 if (value == null) { return this; }
    157 }
    158
    159 if (typeOf(value) == 'function') {
    160 // $hidden属性表明此函数无法被其他对象implement
    161 if (value.$hidden) { return this; }
    162 // Implements mutator调用本函数时retain参数设为ture,表明只是合并方法到原型中
    163 // 而在创建类时(前面建立newclass)retain参数没有赋值,执行wrap函数包装方法到原型
    164 this.prototype[key] = (retain) ? value : wrap(this, key, value);
    165 } else {
    166 // 合并属性到原型
    167 Object.merge(this.prototype, key, value);
    168 }
    169
    170 return this;
    171 };
    172
    173 /**
    174 * @functoin: getInstance
    175 * @param klass - (class) 要继承的类
    176 * @description: 得到父类的一个实例
    177 **/
    178 var getInstance = function (klass) {
    179 // 设置标记,说明Class在设计阶段,不会执行构造函数
    180 klass.$prototyping = true;
    181 var proto = new klass;
    182 // 删除标记
    183 delete klass.$prototyping;
    184 return proto;
    185 };
    186
    187 // 暴露implement方法
    188 Class.implement('implement', implement.overloadSetter());
    189
    190 // #endregion Class
    191
    192 // #region Mutators
    193
    194 /**
    195 * 好了,接下来着重介绍一下Class.Mutators对象:
    196 *
    197 * Mutator是一个可以改变你的类的结构的一个很特殊的函数,它们是产生特别功能和优雅化继承和掺元的的有力工具。
    198 *
    199 * 建立一个Mutatorr有二个部分:mutator的关键字 和mutator的实际函数,关键字既是mutator的名字,
    200 * 也是在构建类时候的keyword。Mootools把mutators 储存在Class.Mutators对象中。
    201 *
    202 * 当你传一个对象给Class构造函数的时候,Mootools检查这个对象的的每一个键在Class.Mutators对象的是不是有
    203 * mutator函数的对应的名字在里面。如果找到了,它就调用这个函数并且把键的值传给它做处理。
    204 *
    205 * Class.Mutators对象包含了两个内建的Mutator: Extends 和 Implements,分别实现原型式继承和多亲继承。
    206 *
    207 * MooTools在Class.Extras模块中提供了三个掺元类Chain、Events、Options,至于作用就不用多说了吧,呵呵。
    208 **/
    209 Class.Mutators = {
    210
    211 // 取得传送给它的class的名字后,直接继承这个class
    212 Extends: function (parent) {
    213 // 静态属性,存储父类对象
    214 this.parent = parent;
    215 // 原型式继承
    216 this.prototype = getInstance(parent);
    217 },
    218
    219 // Implements mutator取得传送给它的class的名字后,把它们的方法和属性添加到新类。
    220 // 利用掺元类实现多亲继承
    221 Implements: function (items) {
    222 Array.from(items).each(function (item) {
    223 var instance = new item;
    224 for (var key in instance) {
    225 implement.call(this, key, instance[key], true);
    226 }
    227 }, this);
    228 }
    229 };
    230
    231 // #endregion
    232
    233 })();

  • 相关阅读:
    【郑轻邀请赛 G】密室逃脱
    【郑轻邀请赛 C】DOBRI
    【郑轻邀请赛 F】 Tmk吃汤饭
    【郑轻邀请赛 I】这里是天堂!
    【郑轻邀请赛 B】base64解密
    【郑轻邀请赛 A】tmk射气球
    【郑轻邀请赛 H】 维克兹的进制转换
    解决adb command not found以及sdk环境配置
    adb shell 命令详解,android, adb logcat
    Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
  • 原文地址:https://www.cnblogs.com/hmking/p/2196504.html
Copyright © 2011-2022 走看看