dom Framework oop模块v2

正在重构整个框架,让命名空间对象dom也出于同一个继承体系下,就像mootools1.3的Type对象那样。

v2的目标大致如下:

  1. 减少入侵性,只保留ECMA262v5及极个别最有用的扩展,lang模块将与核心模块合而为一
  2. 模块即纯对象,去掉没有多大用处的protect方法,实现extend与include都能调用父方法
  3. 去掉构造器中的智能调用父构造器的功能,以后调用父方法统一为this._super()
  4. 增加不使用new关键字就能进行实例化(需要在配置对象中配置)

//by 司徒正美 http://www.cnblogs.com/rubylouvre/ 2010.10.14

var 

PROTO = "prototype",

CTOR = "constructor",

A_proto = Array[PROTO],

A_slice = A_proto.slice,

to_s = Object[PROTO].toString,

is = function (obj,type) {

    return   (type === "Object" && obj === Object(obj)) ||

    (type === "Array" && Array.isArray && Array.isArray(obj)) || // ECMA-5 15.4.3.2

    (type === "Null" && obj === null) ||

    (type === "Undefined" && obj === void 0 ) ||

    obj && to_s.call(obj).slice(8,-1) === type;

}

function extend(target,source){

    for(var name in source)

        if(source.hasOwnProperty(name) && !target[name]){

            target[name] = source[name];

        }

    return target;

}

//Object扩展

//fix ie for..in bug

var _dontEnum = [  'propertyIsEnumerable', 'isPrototypeOf','hasOwnProperty','toLocaleString', 'toString', 'valueOf', 'constructor'];

for (var i in {

    toString: 1

}) _dontEnum = false;

//第二个参数仅在浏览器支持Object.defineProperties时可用

extend(Object,{

    create:function( proto, props ) {//ecma262v5 15.2.3.5

        var ctor = function( ps ) {

            if ( ps &&  Object.defineProperties )

                Object.defineProperties( this, ps );

        };

        ctor[PROTO] = proto;

        return new ctor( props );

    },

    keys: function(obj){//ecma262v5 15.2.3.14

        var result = [],dontEnum = _dontEnum,length = dontEnum.length;

        for(var key in obj ) if(obj.hasOwnProperty(key)){

            result.push(key)

        }

        if(dontEnum){

            while(length){

                key = dontEnum[--length];

                if(obj.hasOwnProperty(key)){

                    result.push(key);

                }

            }

        }

        return result;

    }

});

//用于创建javascript1.6 Array的迭代器

function iterator(vars, body, ret) {

    return eval('[function(fn,scope){'+

        'for(var '+vars+'i=0,l=this.length;i<l;i++){'+

        body.replace('_', 'fn.call(scope,this[i],i,this)') +

        '}' +

        ret +

        '}]')[0];

};

//注释照搬FF官网

extend(Array[PROTO],{

    //定位类 返回指定项首次出现的索引。

    indexOf: function (el, index) {

        var n = this.length, i = ~~index;

        if (i < 0) i += n;

        for (; i < n; i++)

            if ( this[i] === el) return i;

        return -1;

    },

    //定位类 返回指定项最后一次出现的索引。

    lastIndexOf: function (el, index) {

        var n = this.length,

        i = index == null ? n - 1 : index;

        if (i < 0) i = Math.max(0, n + i);

        for (; i >= 0; i--)

            if (this[i] === el) return i;

        return -1;

    },

    //迭代类 在数组中的每个项上运行一个函数,若所有结果都返回真值,此方法亦返回真值。

    forEach : iterator('', '_', ''),

    //迭代类 在数组中的每个项上运行一个函数,并将函数返回真值的项作为数组返回。

    filter : iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'),

    //迭代类  在数组中的每个项上运行一个函数,并将全部结果作为数组返回。

    map :  iterator('r=[],', 'r[i]=_', 'return r'),

     //迭代类  在数组中的每个项上运行一个函数,若存在任意的结果返回真,则返回真值。

    some : iterator('', 'if(_)return true', 'return false'),

     //迭代类  在数组中的每个项上运行一个函数,若所有结果都返回真值,此方法亦返回真值。

    every : iterator('', 'if(!_)return false', 'return true'),

    //归化类 javascript1.8  对该数组的每项和前一次调用的结果运行一个函数,收集最后的结果。

    reduce: function (fn, lastResult, scope) {

        if (this.length == 0) return lastResult;

        var i = lastResult !== undefined ? 0 : 1;

        var result = lastResult !== undefined ? lastResult : this[0];

        for (var n = this.length; i < n; i++)

            result = fn.call(scope, result, this[i], i, this);

        return result;

    },

    //归化类 javascript1.8 同上,但从右向左执行。

    reduceRight: function (fn, lastResult, scope) {

        var array = this.concat().reverse();

        return array.reduce(fn, lastResult, scope);

    }

});



//修正IE67下unshift不返回数组长度的问题

//http://www.cnblogs.com/rubylouvre/archive/2010/01/14/1647751.html

if([].unshift(1) !== 1){

    A_proto.unshift = function(){

        var args = [0,0];

        for(var i=0,n=arguments.length;i<n;i++){

            args[args.length] = arguments[i]

        }

        A_proto.splice.apply(this, args);

        return this.length; //返回新数组的长度

    }

}

//String扩展

var metaObject = {

    '\b': '\\b',

    '\t': '\\t',

    '\n': '\\n',

    '\f': '\\f',

    '\r': '\\r',

    '"' : '\\"',

    '\\': '\\\\'

},rquote = /[\x00-\x1f\\]/g;

extend(String[PROTO],{

    //javascript1.5 firefox已实现

    quote:function () {

        var str = this.replace(rquote,function(chr){

            var meta = metaObject[chr];

            return meta ? meta :  '\\u' + ('0000'+chr.charCodeAt(0).toString(16)).slice(-4);



        });

        return '"'+ str +'"';

    },

    //ecma262v5 15.5.4.20

    //http://www.cnblogs.com/rubylouvre/archive/2009/09/18/1568794.html

    trim: function(){

        var str = this.replace(/^(\s|\u00A0)+/, ''),

        ws = /\s/,

        i = str.length;

        while (ws.test(str.charAt(--i)));

        return str.slice(0, i + 1);

    }

});



//Math扩展

//http://www.cnblogs.com/rubylouvre/archive/2010/10/09/1846941.html

var native_random = Math.random;

Math.random = function(min, max, exact) {

    if (arguments.length === 0) {

        return native_random();

    } else if (arguments.length === 1) {

        max = min;

        min = 0;

    }

    var range = min + (native_random()*(max - min));

    return exact === void(0) ? Math.round(range) : range.toFixed(exact);

}



extend(Function[PROTO],{

    //ecma262v5 15.3.4.5

    bind:function(scope) {

        if (arguments.length < 2 && scope===void 0) return this;

        var fn = this, argv = arguments;

        return function() {

            var args = [], i;

            for(i = 1; i < argv.length; i++)

                args.push(argv[i]);

            for(i = 0; i < arguments.length; i++)

                args.push(arguments[i]);

            return fn.apply(scope, args);

        };

    }

});

function _numarr(s) { // 补零用的辅助函数

    var r=[],k=-1,i=0,j,a=s.split(""),z=a.length;

    for(;i < z;++i){

        for(j=0;j < z;++j){

            r[++k]=a[i]+a[j];

        }

    }

    return r;

}

var numarr = _numarr("0123456789");

function toISOString() {

    var   ms = this.getUTCMilliseconds(),

    pad0 = (ms < 10) ? "00" : (ms < 100) ? "0" : "";

    return this.getUTCFullYear() + '-' +

    numarr[this.getUTCMonth() + 1] + '-' +

    numarr[this.getUTCDate()]      + 'T' +

    numarr[this.getUTCHours()]     + ':' +

    numarr[this.getUTCMinutes()]   + ':' +

    numarr[this.getUTCSeconds()]   + '.' +

    pad0 + this.getUTCMilliseconds() + 'Z';

}

extend(Date[PROTO],{

//ecma262v515.9.5.43

    toISOString:toISOString,

//ecma262v5 15.9.5.44

    toJSON:toISOString

});

extend(Date,{

//ecma262v5 15.9.4.4

    now : function(){

        return new Date().valueOf();

    }

});

全新的类工厂。


var oneObject = function(array,val){

    var result = {},value = val !== void 0 ? val :1;

    for(var i=0,n=array.length;i < n;i++)

        result[array[i]] = value;

    return result;

},

extendObject = oneObject(['_super',PROTO,  'extend', 'include','inherit','ancestors','parent']),

includeObject = oneObject(['_super',CTOR]),

classMethods =  {

    inherit: function(parent) {

        if (parent && parent[PROTO]) {

            this[PROTO] = Object.create(parent[PROTO]);//高效设置原型链

            this.parent = parent;

        }

        this.ancestors =  [];

        while (parent) {//收集所有父类,用于构建方法链时查找同名方法

            this.ancestors.push(parent);

            parent = parent.parent;

        }

        return this[PROTO][CTOR] = this;

    },

    extend: function(){//扩展类成员

        var parent = this.parent,names, name,n,method;

        arguments.length && A_slice.call(arguments).filter(function(module){

            return is(module,"Object");

        }).forEach(function(module){

            names = Object.keys(module);

            n = names.length;

            while(n){

                name = names[--n];

                //避开FF为Object私自添加的原型属性toSource watch unwatch

                if(extendObject[name]===1)

                    continue

                method = module[name];

                this[name] = method;

                if(is(method,"Function") && parent){

                    method.parent = parent[name];

                    method._name = name;

                }

            }

        },this)

        return this;

    },

    include:function(){//扩展原型成员

        var parent = this.parent && this.parent[PROTO],names, name,n,method;

        arguments.length && A_slice.call(arguments).filter(function(module){

            return is(module,"Object");

        }).forEach(function(module){

            names = Object.keys(module)

            n = names.length;

            while(n){

                name = names[--n];

                if(includeObject[name]===1)

                    continue

                method = module[name];

                this[PROTO][name] = method;

                if(is(method,"Function") && parent){

                    method.parent = parent[name];

                    method._name = name;

                }

            }

        },this)

        return this;

    }

}

function _super() {//构建方法链

    var self= arguments.callee.caller,parent = self.parent;

    if(parent){

        return parent.apply(this,arguments.length? arguments : self.arguments);

    }else{

        throw 'this method "'+ self._name +'" no super method.';

    }

}

function classPropsInject(klass,props){

    ['extend','include'].forEach(function(name){

        var modules = props[name];

        if(is(modules,"Object") || is(modules,"Array")){

            klass[name].apply(klass,[].concat(modules));

            delete props[name];

        }

    })

}

function oop(obj){

    obj = obj || {};

    var superclass = obj.inherit; //父类

    delete obj.inherit;

    var nonew = !!obj.nonew;//不用new关键字进行实例化

    delete obj.nonew;

    var klass = function() {

        var that = this;

        if(that.singleton && klass.instance){

            return klass.instance;

        }

        if(nonew && !(that instanceof klass)){

            that = new klass;

        }

        that.init && that.init.apply(that,arguments);

        if(that.singleton){

            klass.instance = that;

        }

        return that;//为nonew准备的出口

    };

    extend(klass,classMethods).inherit(superclass).extend(superclass);

    classPropsInject(klass,obj);

    klass._super = klass[PROTO]._super = _super;

    return klass.include(obj);

}

扩展类成员以及在类方法中调用超类同方法:


var MyMath = oop({});

MyMath.extend({

    PI:3.14,

    getPI:function(){

       return this.PI;

   }

});

var SonMath = oop({inherit:MyMath});

SonMath.extend({

    getPI:function(){

         return this._super()+0.0015926;

    }

});

p(SonMath.getPI());

扩展原型成员,extend、include的属性可以是单个对象,也可以是对象数组。


var movable = {

  run:function(){

    p("能跑")

  },

  fly:function(){

    p("能飞")

  }

}

var recognition  ={

  watch:function(){

    p("看东西")

  },

  smell:function(){

    p("能嗅东西")

  }

}

var Robot = oop({

  init:function(name,type){

    this.name = name;

    this.type = name;

  },

  include:[movable,recognition]

});

var chi = new Robot("小叽","Chobits") ;

p(chi.name);

chi.watch();

chi.fly();

配置单例类


var God = oop({

  init:function(name){

    this.name = name;

    this.alertName = function(){

      p(this.name)

    }

  },

  singleton:true//注意这里,使用singleton属性

});

var god = new God("耶和华");

god.alertName();      //alerts 耶和华

var lucifer = new God("撒旦");

lucifer.alertName();   //alerts 耶和华

p(god === lucifer )//alerts true

配置不使用new关键字使可以实例化。


        var dom2 = oop({

          init:function(selector){

            this.selector = selector

            return this;

          },

          nonew:true,

          getSelectors : function(){

            return (this.selector ||"").split(/\s+/)

          }

        });

      p(dom2('.aaa .bbb .ccc').getSelectors())

继承示例1


      var Animal = oop({

        init:function(name){

          this.name = name;

        },

        getFood:function(){

          return "各种各样的食物"

        },

        extend:{

          getClassName:function(){

            return "Animal";

          }

        }

      });

      var Human = oop({

        inherit:Animal,

        extend:{

          getClassName:function(){

            return this._super()+"-->人";

          }

        }

      });

      var me = new Human("john");

      p(Human.getClassName());

      p(me.getFood());

      var Man = oop({

        inherit:Human,

        init:function(name,sex){

          this._super();

          this.sex = sex;

        },

        getFood: function(){

          return this._super()+",尤其是肉类";

        }

      });

      var Genghis_Khan = new Man("成吉思汗","男");

      p( Genghis_Khan.sex);

      p( Genghis_Khan.name);

      p( Genghis_Khan.getFood());

继承示例2


      var Polygon = oop({

        init:function(sides){

          this.sides = sides

        },

        getArea:function(){

          return 0 //此只是个抽象类,不能用于具体计算

        }

      });

      p("==============Triangle===============")

      var Triangle = oop({

        inherit:Polygon,

        init:function(base,height){

          this._super(3);

          this.base = base;

          this.height = height;

        },

        getArea:function(){

          return 0.5*this.base*this.height;

        }

      });

      var t = new Triangle(2,6);

      p(t.sides);

      p(t.getArea());

      p("==============Rectangle===============")

      var Rectangle = oop({

        inherit:Polygon,

        init:function(length,width){

          this._super(4);

          this.length = length;

          this.width = width;

        },

        getArea:function(){

          return this.length*this.width;

        }

      });

      var r = new Rectangle(7,6);



      p(r.sides);

      p(r.getArea(Rectangle));

      p(r instanceof Polygon)

      p("==============Square===============")

      var Square = oop({

        inherit:Rectangle,

        init:function(side){

          this._super(side,side);

        }

      })

      var s = new Square(6);

      p(s.sides);

      p(s.getArea())

      p(s instanceof Polygon)

      p(s instanceof Square)

你可能感兴趣的:(framework)