//-----第一天
//框架名,对象
var MooTools = {
'version': '1.2dev', //里程碑版本
'build': '1519' //trac系统每次change的版本号
};
/*
Native 是对内置或将之作为内置的对象的包装化
*/
var Native = function(options){
/*
这种写法随处可见,根据ECMA规范,||运算会自动将两侧表达式转化为布尔值,
仅当表达式为0/undefined/null/false时为假,而且||的特性是当前表达式为false时才会执行后表达式,
用在这里的目的是使没传参时设置options的默认值,以避免下面的代码出错
*/
options = options || {};
//继续上面的写法,设默认值为一空方法,用于add中执行implement的后续操作
var afterImplement = options.afterImplement || function(){};
//方法静态化标记,为真时实例方法将被复制到类名下作为静态方法,此时静态方法的第一个参数会被作为实例方法内的this执行
var generics = options.generics;
//用!==比较,当且仅当generics为false时为false,其它值按true处理,这是比较提高可靠性的一种处理方式
generics = (generics !== false);
//用于对内置对象包装时的原对象
var legacy = options.legacy;
//Prototype风格的初始化方法
var initialize = options.initialize;
//是否保护原对象的原型方法,以免被继承的同名方法覆盖
var protect = options.protect;
//指定类名,以用于$type方法的取值
var name = options.name;
//又是||的写法,在不提供初始化方法时直接使用内置的对象作为原型
var ōbject = initialize || legacy;
//设置构造器
object.constructor = Native;
//用于$type方法的取值
object.$family = {name: 'native'};
//继承legacy
if (legacy && initialize) object.prototype = legacy.prototype;
object.prototype.constructor = object;
if (name){
//全部用小写,可以避免大小写敏感,当然可以换成大写,只是大写不美观了不直观
var family = name.toLowerCase();
//写在原型链上
object.prototype.$family = {name: family};
//类型化,现在可以使用object.type(object1)判断object与object1是否同一家族/类型
Native.typize(object, family);
}
//总的为对象添加方法的处理
var add = function(obj, name, method, force){
//仅当不指定对象受保存,或指定强制覆盖或原对象原型中不存在该方法时添加
if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
//方法静态化,此时的静态方法的第一个参数会被作为实例方法中的this执行
if (generics) Native.genericize(obj, name, protect);
//后续处理
afterImplement.call(obj, name, method);
return obj;
};
//implement静态方法
object.implement = function(a1, a2, a3){
if (typeof a1 == 'string') return add(this, a1, a2, a3);
for (var p in a1) add(this, p, a1[p], a2);
//返回当前对象可以使方法支持链式写法,如object.implement(...).implement(...),jQueryer的最爱
return this;
};
//实现方法别名的静态方法
object.alias = function(a1, a2, a3){
if (typeof a1 == 'string'){
a1 = this.prototype[a1];
if (a1) add(this, a2, a1, a3);
} else {
//使alias支持object.alias({a : 'a1', b : 'b1'});这样的多个方法进行别名处理
for (var a in a1) this.alias(a, a1[a], a2);
}
//使支持链式写法
return this;
};
return object;
};
//用于同时对多个对象进行扩展实现,子对象须被Native化,或者实现了名为implement的静态方法
Native.implement = function(objects, properties){
for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
};
//方法静态化
Native.genericize = function(object, property, check){
if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
//将arguments数组化,一种技巧
var args = Array.prototype.slice.call(arguments);
//将第一个参数作为原来实例方法的this指向
return object.prototype[property].apply(args.shift(), args);
};
};
//使类支持类型比较,闭包使用技巧
Native.typize = function(object, family){
if (!object.type) object.type = function(item){
return ($type(item) === family);
};
};
//用于同时对多个对象进行别名操作
Native.alias = function(objects, a1, a2, a3){
for (var i = 0, j = objects.length; i < j; i++) objects[i].alias(a1, a2, a3);
};
/*
因为js中的变量作用域只存在于function和with中,此处使用模块化写法避免全局变量污染,就地执行匿名方法
使Boolean/Native/Object支持类型比较操作
*/
(function(objects){
for (var name in objects) Native.typize(objects[name], name.toLowerCase());
})({'Boolean': Boolean, 'Native': Native, 'Object': Object});
/*
还是模块化写法
对下列内置类型进行Native化包装,使之支持类型化,别名,继承等
*/
(function(objects){
//其实new Native跟Native的结果应该是一样的,但是有时为了安全起见,用new能避免很多无法考虑的数据引用
for (var name in objects) new Native({name: name, initialize: objects[name], protect: true});
})({'String': String, 'Function': Function, 'Number': Number, 'Array': Array, 'RegExp': RegExp, 'Date': Date});
/*
模块化写法
让数组和字符串的实例方法静态化(因为数组和字符串的应用比较多)
现在可以使用Array.pop
*/
(function(object, methods){
for (var i = 0, l = methods.length; i < l; i++) Native.genericize(object, methods[i], true);
//虽然是匿名方法,但是仍然可以通过arguments.callee找到指向,这里return使(function(){})()()()()的写法成为可能
return arguments.callee;
})
(Array, ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'toString', 'valueOf', 'indexOf', 'lastIndexOf'])
(String, ['charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase', 'valueOf']);
//----------------------------------第二天
//检查对象是否已经定义或者已经赋值
function $chk(obj){
return !!(obj || ōbj === 0);
};
//通用清除计时器的方法,即能清setTimeout,又能清setInterval,即使计时器不存在也不会报错
function $clear(timer){
clearTimeout(timer);
clearInterval(timer);
return null;
};
/*
检查对象属性是否已初始化/定义,注意只能检查对象的属性,不能直接检查变量
因为未定义变量在调用本方法前便会抛出错误,切记
*/
function $defined(obj){
return (obj != undefined);
};
//一个空的函数,主要用于事件的初始化
function $empty(){};
//闭包应用,延后取指定的参数值
function $arguments(i){
return function(){
return arguments[i];
};
};
//lambda(匿名)函数,将指定变量函数化,保证返回一个function对象,类似$splat,将变量数组化
function $lambda(value){
return (typeof value == 'function') ? value : function(){
return value;
};
};
//浅拷贝扩展,不考虑object型属性的,只是简单的覆盖
function $extend(original, extended){
for (var key in (extended || {})) original[key] = extended[key];
return original;
};
//解链对象,主要是解决object类型的变量赋值时会影响原值的问题,所以修改其实我觉得叫clone的话更明了
function $unlink(object){
var unlinked = null;
switch ($type(object)){
case 'object':
unlinked = {};
//深拷贝
for (var p in object) unlinked[p] = $unlink(object[p]);
break;
case 'hash':
//深拷贝
unlinked = $unlink(object.getClean());
break;
case 'array':
unlinked = [];
//深拷贝
for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
break;
default: return object;
}
return unlinked;
};
//合并所有对象,参数位置越后优先级越高,就是说后面的参数对象属性会覆盖前面的,注意用到了$unlink
function $merge(){
var mix = {};
for (var i = 0, l = arguments.length; i < l; i++){
var ōbject = arguments[i];
if ($type(object) != 'object') continue;
for (var key in object){
var ōp = object[key], mp = mix[key];
mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
}
}
return mix;
};
//返回参数列表中从左到右第一个已定义的表达式的值
function $pick(){
for (var i = 0, l = arguments.length; i < l; i++){
if ($defined(arguments[i])) return arguments[i];
}
return null;
};
//在min到max之间取一个随机数
function $random(min, max){
return Math.floor(Math.random() * (max - min + 1) + min);
};
//变量数组化,通常用于保证之后的代码能执行数组的each方法
function $splat(obj){
var type = $type(obj);
return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
};
//当前的时间截,Fx中的时间周期判断使用较多
var $time = Date.now || function(){
return new Date()