zoukankan      html  css  js  c++  java
  • 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)
    
  • 相关阅读:
    JAVA面试基础
    扔硬币问题
    随机数生成随机数
    囚犯猜帽子问题
    十道智力题(三)
    十道智力题(二)
    十道智力题(一)
    lintcode:排颜色 II
    机器学习中的几个常见概念(持续更新中......)
    如何打印一棵树(Java)
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1851729.html
Copyright © 2011-2022 走看看