mootools 的源代码TYPE 及Class解析

/*
---
MooTools: the javascript framework


web build:
 - http://mootools.net/core/58f64dfefa42b08cb566c95a6244e613


packager build:
 - packager build Core/Class


...
*/


/*
---


name: Core


description: The heart of MooTools.


license: MIT-style license.


copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).


authors: The MooTools production team (http://mootools.net/developers/)


inspiration:
  - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
  - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)


provides: [Core, MooTools, Type, typeOf, instanceOf, Native]


...
*/


(function(){


    this.MooTools = {
        version: '1.4.5',
        build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0'
    };


// typeOf, instanceOf


    var typeOf = this.typeOf = function(item){
        if (item == null) return 'null';


        if (item.$family != null) return item.$family();


        if (item.nodeName){
            if (item.nodeType == 1) return 'element';
            if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
        } else if (typeof item.length == 'number'){
            if (item.callee) return 'arguments';
            if ('item' in item) return 'collection';
        }


        return typeof item;
    };


    var instanceOf = this.instanceOf = function(item, object){
        if (item == null) return false;
        // 在这可以获得所有对象的$constructor, 也包括字符串, 数字,如'aaaa'.$constructor === String();
        var constructor = item.$constructor || item.constructor;


        while (constructor){


            if (constructor === object) return true;
            /*
               主要用来判定Class类的, Class的Matutors.extends方法会指定勾造函数的parent;
               var A=new Class({
                 initialize:function(){


                 }
                 })
                 var B=new Class({
                 Extends:A,
                 initialize:function(){
                 }
                 })


                 new Type('a',A);
                 new Type('b',B);
                 var b=new B();
                 console.log( instanceOf(b,A));
             */


            constructor = constructor.parent;
        }
        /*
         http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak
         有三个对象会导致这个问题
         window
         document
         element
         举例,if (window instanceof Object)  每次刷新会增加50kb的内存,原因是这三个对象在IE下不是真正的对象,没有hasOwnProperty 及valueOf方法。
         */
        /*<ltIE8>*/
        if (!item.hasOwnProperty) return false;
        /*</ltIE8>*/
        /*
         借用 instanceof 进行深度检测,那么 instanceOf(Array, Function)  true, instance of (Array, Object) true.
         */


        return item instanceof object;
    };


// Function overloading


    var Function = this.Function;


    var enumerables = true;
    for (var i in {toString: 1}) enumerables = null;
    if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];


    Function.prototype.overloadSetter = function(usePlural){
        var self = this;
        return function(a, b){
            if (a == null) return this;
            if (usePlural || typeof a != 'string'){
                for (var k in a) self.call(this, k, a[k]);
                if (enumerables) for (var i = enumerables.length; i--;){
                    k = enumerables[i];
                    if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
                }
            } else {
                self.call(this, a, b);
            }
            return this;
        };
    };


    Function.prototype.overloadGetter = function(usePlural){
        var self = this;
        return function(a){
            var args, result;
            if (typeof a != 'string') args = a;
            else if (arguments.length > 1) args = arguments;
            else if (usePlural) args = [a];
            if (args){
                result = {};
                for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
            } else {
                result = self.call(this, a);
            }
            return result;
        };
    };


    Function.prototype.extend = function(key, value){
        this[key] = value;
    }.overloadSetter();


    Function.prototype.implement = function(key, value){
        this.prototype[key] = value;
    }.overloadSetter();


// From


    var slice = Array.prototype.slice;


    Function.from = function(item){
        return (typeOf(item) == 'function') ? item : function(){
            return item;
        };
    };


    Array.from = function(item){
        if (item == null) return [];
        return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
    };


    Number.from = function(item){
        var number = parseFloat(item);
        return isFinite(number) ? number : null;
    };


    String.from = function(item){
        return item + '';
    };


// hide, protect


    Function.implement({


        hide: function(){
            this.$hidden = true;
            return this;
        },


        protect: function(){
            this.$protected = true;
            return this;
        }


    });


// Type


    var Type = this.Type = function(name, object){
        if (name){
            var lower = name.toLowerCase();
            var typeCheck = function(item){
                return (typeOf(item) == lower);
            };


            Type['is' + name] = typeCheck;
            if (object != null){
                /*
                    在开头的typeOf函数会调用这个$family, var A=function(){}; new Type('Atype',A); var a=new A(); console.log(typeOf(a));将会输出 atype;
                    A.prototype.$family=function(){return "atype";}, 所以实例会从原型中继承 $family方法。


                    注:这里可以不需要圆括号 object.prototype.$family=function(){return lower;}.hide();
                 */
                object.prototype.$family = (function(){


                    return lower;
                }).hide();


            }
        }


        if (object == null) return null;
        /*
         var A=function(){}
         var aType=new Type('A',A);
         this 指向 aType实例,这样在object 里就可以调用  type内的实例方法,如 A.mirror 方法。即将 type内的方法通过extend 变成 A的静态方法,而不是实例方法。
         */
        object.extend(this);


        /*
         用于instanceOf(Array,Type)的检测
         第一句的作用是判断 instanceOf(Array,Type) 为true
         第二句的作用是判断 var a=[1,2,3] instanceOf(a, Array) true;
         */
        object.$constructor = Type;




       object.prototype.$constructor = object;


        return object;
    };


    var toString = Object.prototype.toString;


    Type.isEnumerable = function(item){
        return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
    };
    /*
     注解ID: 勾子函数


     勾子函数,主要运用去implement方法内, 用来存取在implement方法执行必须执行的方法, 通过mirror将要先执行的函数添加进去。
     添加的方法有两个
     1. 如果给mirror传递的为一个普能函数,则在执行的implement, 先调用这个普能的函数
     2. 如果给mirror传凝视的为一个Type类别 B, 则传递的类别也将拥有这个implement的方法。
     如, var A=function(){};
     var B=function(){};
     A.prototype=new String();
     B.prototype=new String();
     var typeA=new Type('a',A);
     var typeB=new Type('b',B);
     typeA.mirror(function(){ console.log(' general functin') });
     typeA.mirror(typeB);
     typeA.implement('sayHello',function(arg1){ console.log(arg1);}); // 此时会输出 'general funcion'
     var a= new A();
     var b=new B();
     a.sayHello('this is a');  // 输出this is a.
     b.sayHello('this is b'); // 输出this is b. B中没有定义,但通过A的 勾子函数也实现了sayHello这个功能。


     */
    var hooks = {};


    var hooksOf = function(object){
        var type = typeOf(object.prototype);
        return hooks[type] || (hooks[type] = []);
    };


    var implement = function(name, method){
        if (method && method.$hidden) return;


        var hooks = hooksOf(this);


        for (var i = 0; i < hooks.length; i++){
            /*参见注解 勾子函数 202行*/
            var hook = hooks[i];
            if (typeOf(hook) == 'type'){
                implement.call(hook, name, method);


            }
            else hook.call(this, name, method);
        }


        /*
         如果 A 的原型方法中没有 name这个方法,或者 有 name这个方法,name方法没有写保护,则添加这个 name方法到 A的原型方法中。
         举例请见下一步
         */
        var previous = this.prototype[name];
        if (previous == null || !previous.$protected) this.prototype[name] = method;


        /*
         上一步是将name方法扩展到原型方法中, 此步将方法扩展到 A类的静态方法中,传入的第一个参数为 实例对像, 静态方法不会被重写
         举例:
         var A=function(){}
         new Type('A',A);
         var a=new A();
         A.implement('test',function(){  console.log('test');})
         A.implement('test',function(){ console.log('test1'):});
         A.test(a)   // 输出test
         a.test(); //输出test1, 因为实例方法可以被重写
         */


        if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
            return method.apply(item, slice.call(arguments, 1));
        });
    };


    var extend = function(name, method){
        if (method && method.$hidden) return;
        var previous = this[name];


        if (previous == null || !previous.$protected) this[name] = method;
    };


    Type.implement({


        implement: implement.overloadSetter(),


        extend: extend.overloadSetter(),
        /*
        方法别名的应用


         var str = 'howdy';
         // implement the original
         String.implement({
         repeat: function(times){
         var arr = [];
         while (times--) arr.push(this);
         return arr.join('');
         }
         });
         console.log(str.repeat(2)); // 'howdyhowdy'
         // alias repeat
         String.alias('again', 'repeat');
         console.log(str.again == str.repeat); // true
         console.log(str.again(2)); // 'howdyhowdy'
         */
        alias: function(name, existing){
            implement.call(this, name, this.prototype[existing]);
        }.overloadSetter(),
        /*参见注解 勾子函数 202行*/
        mirror: function(hook){
            hooksOf(this).push(hook);
            return this;
        }


    });
    /*
     new Type('Type', Type) 主要是将 Type构造函数的 object.prototype.$family='type', 那么 object.extend(this) 就能获得这个值。
     相当于设置 Type.prototype.$family=function(){return 'type'};
     *     如果不调用 new Type('Type', Type);
     *
     *     那么 var a= new Type('a',A) 返回的 数据将为 function,  而不是 Type.
     *
     * */
    new Type('Type', Type);
// Default Types


    var force = function(name, object, methods){
        var isType = (object != Object),
            prototype = object.prototype;


        if (isType) object = new Type(name, object);
        /*
         将指写的方法保护起来,不能通过implement函数重写
         例:
         var A=function(){}
         A.prototype=new Array();
         new Type('a',A).implement('push',function(){})  // 不会重写Array 里面的push方法
         */


        for (var i = 0, l = methods.length; i < l; i++){
            var key = methods[i],
                generic = object[key],
                proto = prototype[key];


            if (generic) generic.protect();
            /*为什么不简单的设置为proto.protect()  ? */
            if (isType && proto) object.implement(key, proto.protect());


        }


        if (isType){
            /*
             遍列内置对象的方法,不能枚举的需要在methods数组中指定。如果methods的数组中有可枚举的方法,那么会
             被调用两次fn, 看起来有bug.
             */
            var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
            object.forEachMethod = function(fn){
                if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
                    fn.call(prototype, prototype[methods[i]], methods[i]);
                }
                for (var key in prototype) fn.call(prototype, prototype[key], key)
            };
        }


        return force;
    };


    force('String', String, [
        'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
        'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
    ])('Array', Array, [
            'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
            'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
        ])('Number', Number, [
            'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
        ])('Function', Function, [
            'apply', 'call', 'bind'
        ])('RegExp', RegExp, [
            'exec', 'test'
        ])('Object', Object, [  /*  将 Object 的静态方法保护起来 */
            'create', 'defineProperty', 'defineProperties', 'keys',
            'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
            'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
        ])('Date', Date, ['now']);


    Object.extend = extend.overloadSetter();


    Date.extend('now', function(){
        return +(new Date);
    });


    new Type('Boolean', Boolean);


// fixes NaN returning as Number


    Number.prototype.$family = function(){
        return isFinite(this) ? 'number' : 'null';
    }.hide();


// Number.random


    Number.extend('random', function(min, max){
        return Math.floor(Math.random() * (max - min + 1) + min);
    });


// forEach, each


    var hasOwnProperty = Object.prototype.hasOwnProperty;
    Object.extend('forEach', function(object, fn, bind){
        for (var key in object){
            if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
        }
    });


    Object.each = Object.forEach;


    Array.implement({


        forEach: function(fn, bind){
            for (var i = 0, l = this.length; i < l; i++){
                if (i in this) fn.call(bind, this[i], i, this);
            }
        },


        each: function(fn, bind){
            Array.forEach(this, fn, bind);
            return this;
        }


    });


// Array & Object cloning, Object merging and appending


    var cloneOf = function(item){
        switch (typeOf(item)){
            case 'array': return item.clone();
            case 'object': return Object.clone(item);
            default: return item;
        }
    };


    Array.implement('clone', function(){
        var i = this.length, clone = new Array(i);
        while (i--) clone[i] = cloneOf(this[i]);
        return clone;
    });


    var mergeOne = function(source, key, current){
        switch (typeOf(current)){
            case 'object':
                if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
                else source[key] = Object.clone(current);
                break;
            case 'array': source[key] = current.clone(); break;
            default: source[key] = current;
        }
        return source;
    };
    /*
     没有破坏 Object的原始链


     */
    Object.extend({


        merge: function(source, k, v){
            if (typeOf(k) == 'string') return mergeOne(source, k, v);
            for (var i = 1, l = arguments.length; i < l; i++){
                var object = arguments[i];
                for (var key in object) mergeOne(source, key, object[key]);
            }
            return source;
        },


        clone: function(object){
            var clone = {};
            for (var key in object) clone[key] = cloneOf(object[key]);
            return clone;
        },


        append: function(original){
            for (var i = 1, l = arguments.length; i < l; i++){
                var extended = arguments[i] || {};
                for (var key in extended) original[key] = extended[key];
            }
            return original;
        }


    });


// Object-less types
    /*
     仅仅是获得Type.isObject(item); Type.isTextNode(item) 等静态方法
     */
    ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
        new Type(name);
    });


// Unique ID


    var UID = Date.now();


    String.extend('uniqueID', function(){
        return (UID++).toString(36);
    });






})();


/*
---


name: Array


description: Contains Array Prototypes like each, contains, and erase.


license: MIT-style license.


requires: Type


provides: Array


...
*/


Array.implement({


/*<!ES5>*/
every: function(fn, bind){
for (var i = 0, l = this.length >>> 0; i < l; i++){
if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
}
return true;
},


filter: function(fn, bind){
var results = [];
for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
value = this[i];
if (fn.call(bind, value, i, this)) results.push(value);
}
return results;
},


indexOf: function(item, from){


var length = this.length >>> 0;
for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
if (this[i] === item) return i;
}
return -1;
},


map: function(fn, bind){
var length = this.length >>> 0, results = Array(length);
for (var i = 0; i < length; i++){
if (i in this) results[i] = fn.call(bind, this[i], i, this);
}
return results;
},


some: function(fn, bind){
for (var i = 0, l = this.length >>> 0; i < l; i++){
if ((i in this) && fn.call(bind, this[i], i, this)) return true;
}
return false;
},
/*</!ES5>*/


clean: function(){
return this.filter(function(item){
return item != null;
});
},


invoke: function(methodName){
var args = Array.slice(arguments, 1);
return this.map(function(item){
return item[methodName].apply(item, args);
});
},


associate: function(keys){
var obj = {}, length = Math.min(this.length, keys.length);
for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
return obj;
},


link: function(object){
var result = {};
for (var i = 0, l = this.length; i < l; i++){
for (var key in object){
if (object[key](this[i])){
result[key] = this[i];
delete object[key];
break;
}
}
}
return result;
},


contains: function(item, from){
return this.indexOf(item, from) != -1;
},


append: function(array){
this.push.apply(this, array);
return this;
},


getLast: function(){
return (this.length) ? this[this.length - 1] : null;
},


getRandom: function(){
return (this.length) ? this[Number.random(0, this.length - 1)] : null;
},


include: function(item){
if (!this.contains(item)) this.push(item);
return this;
},


combine: function(array){
for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
return this;
},


erase: function(item){
for (var i = this.length; i--;){
if (this[i] === item) this.splice(i, 1);
}
return this;
},


empty: function(){
this.length = 0;
return this;
},


flatten: function(){
var array = [];
for (var i = 0, l = this.length; i < l; i++){
var type = typeOf(this[i]);
if (type == 'null') continue;
array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
}
return array;
},


pick: function(){
for (var i = 0, l = this.length; i < l; i++){
if (this[i] != null) return this[i];
}
return null;
},


hexToRgb: function(array){
if (this.length != 3) return null;
var rgb = this.map(function(value){
if (value.length == 1) value += value;
return value.toInt(16);
});
return (array) ? rgb : 'rgb(' + rgb + ')';
},


rgbToHex: function(array){
if (this.length < 3) return null;
if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
var hex = [];
for (var i = 0; i < 3; i++){
var bit = (this[i] - 0).toString(16);
hex.push((bit.length == 1) ? '0' + bit : bit);
}
return (array) ? hex : '#' + hex.join('');
}


});








/*
---


name: String


description: Contains String Prototypes like camelCase, capitalize, test, and toInt.


license: MIT-style license.


requires: Type


provides: String


...
*/


String.implement({


test: function(regex, params){
return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
},


contains: function(string, separator){
return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
},


trim: function(){
return String(this).replace(/^\s+|\s+$/g, '');
},


clean: function(){
return String(this).replace(/\s+/g, ' ').trim();
},


camelCase: function(){
return String(this).replace(/-\D/g, function(match){
return match.charAt(1).toUpperCase();
});
},


hyphenate: function(){
return String(this).replace(/[A-Z]/g, function(match){
return ('-' + match.charAt(0).toLowerCase());
});
},


capitalize: function(){
return String(this).replace(/\b[a-z]/g, function(match){
return match.toUpperCase();
});
},


escapeRegExp: function(){
return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
},


toInt: function(base){
return parseInt(this, base || 10);
},


toFloat: function(){
return parseFloat(this);
},


hexToRgb: function(array){
var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
return (hex) ? hex.slice(1).hexToRgb(array) : null;
},


rgbToHex: function(array){
var rgb = String(this).match(/\d{1,3}/g);
return (rgb) ? rgb.rgbToHex(array) : null;
},


substitute: function(object, regexp){
return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
if (match.charAt(0) == '\\') return match.slice(1);
return (object[name] != null) ? object[name] : '';
});
}


});




/*
---


name: Function


description: Contains Function Prototypes like create, bind, pass, and delay.


license: MIT-style license.


requires: Type


provides: Function


...
*/


Function.extend({


attempt: function(){
for (var i = 0, l = arguments.length; i < l; i++){
try {
return arguments[i]();
} catch (e){}
}
return null;
}


});


Function.implement({


attempt: function(args, bind){
try {
return this.apply(bind, Array.from(args));
} catch (e){}


return null;
},


/*<!ES5-bind>*/
bind: function(that){
var self = this,
args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
F = function(){};


var bound = function(){
var context = that, length = arguments.length;
if (this instanceof bound){
F.prototype = self.prototype;
context = new F;
}
var result = (!args && !length)
? self.call(context)
: self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
return context == that ? result : context;
};
return bound;
},
/*</!ES5-bind>*/


pass: function(args, bind){
var self = this;
if (args != null) args = Array.from(args);
return function(){
return self.apply(bind, args || arguments);
};
},


delay: function(delay, bind, args){
return setTimeout(this.pass((args == null ? [] : args), bind), delay);
},


periodical: function(periodical, bind, args){
return setInterval(this.pass((args == null ? [] : args), bind), periodical);
}


});








/*
---


name: Number


description: Contains Number Prototypes like limit, round, times, and ceil.


license: MIT-style license.


requires: Type


provides: Number


...
*/


Number.implement({


limit: function(min, max){
return Math.min(max, Math.max(min, this));
},


round: function(precision){
precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
return Math.round(this * precision) / precision;
},


times: function(fn, bind){
for (var i = 0; i < this; i++) fn.call(bind, i, this);
},


toFloat: function(){
return parseFloat(this);
},


toInt: function(base){
return parseInt(this, base || 10);
}


});


Number.alias('each', 'times');


(function(math){
var methods = {};
math.each(function(name){
if (!Number[name]) methods[name] = function(){
return Math[name].apply(null, [this].concat(Array.from(arguments)));
};
});
Number.implement(methods);
})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);




/*
---


name: Class


description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.


license: MIT-style license.


requires: [Array, String, Function, Number]


provides: Class


...
*/


(function(){


var Class = this.Class = new Type('Class', function(params){
if (instanceOf(params, Function)) params = {initialize: params};


var newClass = function(){
        /*
         this 指向通过 new newClass(arge) 构造的实例
         一步步讲解一下
         var A=function(param){
         reset(this);
         }
         function reset(object){
         for(var key in object) console.log(key);
         }
         1. 如果A只是简单的构造函数,那么this的prototype为Oject, 即不输出任何内容
         2. 如果指写A的原型为new String, 而String的prototype有定义方法,则会输出定议的方法
         3. 如果在A的构造函数里面指定了this.a=param, 则reset里面也会输出a.
         4. 如果将方法 b指定为A的原型, A.prototype.b=function(){}, 则reset里面也会输出b.


         所以this指向的就是newClass的实例。
         下面讲解下这个 this 会有哪些值。
         implement 会加param 添加到这个newClass构造函数的原型上。 那么 newClass将会引用这些个属性或方法




         */
reset(this);
if (newClass.$prototyping) return this;


this.$caller = null;
var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
this.$caller = this.caller = null;
return value;
        /*
         extend,将Class对象的上的一些方法,设置为newClass类的静态方法,如implement
            var A=new Class({a:'hello',say:function(){console.log('hello');});
            若没有设置 extend 那么,A.implement只是调用 Function原型中设置的implement,
            右设置了extend,那么A.implemnt会调用之后Class定义的implemnt.
         通过extend(this),可以不将Class做为newClass的原型,只是将Class的方法复制到newClass上。
            var B= new Class()
           B instanceof Class //false;
          */
}.extend(this).implement(params);
    /*
     如果设置了这个
     var B = new Class()
     instanceOf(B,Class); //true;


     */
newClass.$constructor = Class;
newClass.prototype.$constructor = newClass;
newClass.prototype.parent = parent;


return newClass;
});


var parent = function(){


if (!this.$caller) throw new Error('The method "parent" cannot be called.');
var name = this.$caller.$name,
parent = this.$caller.$owner.parent,
previous = (parent) ? parent.prototype[name] : null;
if (!previous) throw new Error('The method "' + name + '" has no parent.');
return previous.apply(this, arguments);
};
/*
    将传入的对象进行重置,即只做传值处理,不会改变原始的对象。
     obj={text:'Hello,Robin'};
     var B=new Class({a:'hello','say':function(){console.log('annnn')},obj:obj});
     var b=new B();
     b.obj.text='hello';
     console.log(obj.text);
     console.log(b.obj.text);
 */
var reset = function(object){
for (var key in object){


var value = object[key];
switch (typeOf(value)){
case 'object':
var F = function(){};
F.prototype = value;
object[key] = reset(new F);
break;
case 'array': object[key] = value.clone(); break;
}
}
return object;
};


var wrap = function(self, key, method){
if (method.$origin) method = method.$origin;


var wrapper = function(){
        /*
         var A=new Class({
         say:function(){
         console.log('hi A');
         }
         })
         var B=new Class({
         Extends:A,
         say:function(){
         this.parent();
         console.log('hi B')
         }
         })
         var C=new Class({
         Extends:B,
         say:function(){
         this.parent();
         console.log('hi C');
         }
         })
         var c=new C('test');
         c.say();


         调用过程如下:
            1. c.say(),  设置 caller, current, this->caller,$this.$caller= c.say为空
            2. 完成以上两个值后,调用this.parent(), c.say()还没有完成,到 b.say(), caller=null, current=c.say(),            this->caller =c.say(), this->$caller=b.say();
            3.完成设置后,调用 this.parent(), b.say 还没有完成,到 a.say(),caller=c.say(), current=b.say(),                  this->caller=b.say(), this->$caller=a.say();
            4.因为 A中没有parent(),log "hi A" , 调用链重置, 此时this->caller=c.say(), $this->$caller=b.say(); 参考3.
            5. 返回到 B, log "hi B" ,调用链重置 $this->caller=null, $this->current=c.say(), 参考2.
            6. 返厍到C, log 'Hi c', 设用链重置 $this->caller=null , $this-current=null 参考1。


         */
if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
        // current用来保存上一个方法, caller保存上上一个方法, this.$caller 为当前方法, this.caller为上一个方法
var caller = this.caller,
            current = this.$caller;


this.caller = current; this.$caller = wrapper;
var result = method.apply(this, arguments);
this.$caller = current; this.caller = caller;


return result;
}.extend({$owner: self, $origin: method, $name: key});
return wrapper;
};


var implement = function(key, value, retain){


    /*
        如果有指定特定的函数,如果有在Class.Mutators, 则按照Class.Mutators里面指定的方法执行。
        同时执行完成后,需要Class.Mutators没有指定返回值, if(varlue==null) 为true, 直接退出implement。




     */
if (Class.Mutators.hasOwnProperty(key)){
value = Class.Mutators[key].call(this, value);
if (value == null) return this;
}


if (typeOf(value) == 'function'){
if (value.$hidden) return this;
this.prototype[key] = (retain) ? value : wrap(this, key, value);
} else {
Object.merge(this.prototype, key, value);
}
    // 因为调用implement都是调用overloadSetter,  而它是不需要有返回值的。
return this;
};


var getInstance = function(klass){
    /*
       通过$prototyping, 不让父类创建一个实例,只是调用父类的reset方法,即获得父类的原型属性
       var A=new Class({
            name:'robin',
            email:'154371199',
            implement:function(){
                console.log('hello');
            }


       })
       var B=new Class({
            Extedns:A


       })
       var b=new B();
       console.log(b.name);


     */
klass.$prototyping = true;
var proto = new klass;
delete klass.$prototyping;


return proto;
};


Class.implement('implement', implement.overloadSetter());


Class.Mutators = {


Extends: function(parent){
this.parent = parent;
this.prototype = getInstance(parent);


},


Implements: function(items){
Array.from(items).each(function(item){
var instance = new item;
for (var key in instance) implement.call(this, key, instance[key], true);
}, this);
}
};


})();


你可能感兴趣的:(mootools 的源代码TYPE 及Class解析)