日期:2014-05-16 浏览次数:20488 次
//继承
//实现singlaton
//可以调用基类函数
//JavaScript通过构造函数和原型的方式模拟实现了类的功能。
var Class = (function(){
//IE不会遍历几个特殊属性:"constructor", "toString", "valueOf"
var IS_DONTENUM_BUGGY = void function(){
for (var p in { toString: 1}) return false;
return true;
}();
function create(options){
var options = options || {}, uniqueInstance = null;
//判定是否需要实现单例
var singleton = !!options.singleton;
delete options.singleton;
//父类
var superclass = options.inherit || {};
delete options.inherit;
function klass(){
if (!singleton) this.init.apply(this, arguments);
}
//添加类方法
$U.extend(klass, Class.Methods);
//是否继承
if ($U.isFunction(superclass)) {
var bridge = function(){};
bridge.prototype = superclass.prototype;
klass.prototype = new bridge;
klass.superclass = superclass;
}
//添加原型方法
klass.addMethods(options);
if (!klass.prototype.init)
klass.prototype.init = function(){
};
//修正constructor
klass.prototype.constructor = klass;
//__proto__是什么?我们在这里简单地说下。每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性时,如果
//这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样
//一直找下去,也就是我们平时所说的原型链的概念。
//按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,
//我们可以对外访问和设置。
//修复IE与Opera中的第二条原型链
if (!klass.prototype.__proto__) klass.prototype.__proto__ = klass.prototype;
//处理函数:如果singleton模式,则private constructor
return singleton ? {
getInstance: function(){
if (!uniqueInstance) {// Instantiate only if the instance doesn't exist.
uniqueInstance = new klass;
uniqueInstance.init.apply(uniqueInstance, arguments);
}
return uniqueInstance;
}
} : klass;
}
function addMethods(source){
var ancestor = this.superclass && this.superclass.prototype, properties = $U.keys(source);
//处理IE不能遍历的特殊属性。
if (IS_DONTENUM_BUGGY) {
if (source.toString != Object.prototype.toString)
properties.push("toString");
if (source.valueOf != Object.prototype.valueOf)
properties.push("valueOf");
}
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i], value = source[property];
//在C#中,如果子类有意隐藏基类成员,使用关键字"new"
//使用base关键字显示调用基类构造函数
//这这里约定如果子类方法第一个参数是“$super”,则调用父类的方法.
if (ancestor && $U.isFunction(value) && (value.argumentNames()[0] === "$super")) {
var method = value;
//var f = (function(m){ return function(){ return ancestor[m].apply(this, arguments)}})(property)
//f.wrap(method)
//F.prototype[name] = (function(name, fn) {
// return function() {
// var that = this;
// $super = function() {
// return baseClass.prototype[name].apply(that, arguments);
// };
// return fn.apply(this, Array.prototype.concat.apply($super, arguments));
// };
//})(name, prop[name]);
//总之,实现把基类函数作为子函数的第一个参数,以此调用父函数。
value = ancestor[property].wrap(method);
value.valueOf = method.valueOf.bind(method);
// 因为我们改变了函数体,所以重新定义函数的toString方法
// 这样用户调用函数的toString方法时,返回的是原始的函数定义体