第一类工厂与哈希对象

第一类工厂相当于mootools的Native方法,用于创建一些具有扩展能力的类,但这些类并没有继承能力,此类工厂也不能以某个类作为蓝本创建子类。总之,一切从简。第一类工厂要依赖一些辅助方法,一并写出来了。


         var dom = {};//命名空间
        dom.mixin = function (obj, bag) {
          if (arguments.length === 1) {
            bag = obj;
            obj = this;
          };
          var nil = {};
          if (obj && bag && typeof bag === 'object') {
            for (var p in bag) {
              if (nil[p] === void 0 || nil[p] != bag[p]) obj[p] = bag[p];
            }
          };
          if (!+"/v1") {
            p = bag.toString;
            if (typeof p === "function" && p !== obj.toString && p !== nil.toString && p !== "/nfunction toString() {/n    [native code]/n}/n") {
              obj.toString = bag.toString;
            }
          }
          return obj;
        };
        dom.factory = function(obj){//
          var klass = obj.klass,
          init = obj.init;
          klass.fn = klass.prototype = {
            init :init,
            constructor: klass
          };
          klass.fn.init.prototype = klass.fn;
          delete obj.klass;delete obj.init;
          dom.mixin(klass.fn, obj);
          //用于扩展原型方法
          klass.mixin = function(bag){
            dom.mixin(this.fn,bag);
            return this;
          };
          klass.alias = function(oldName, newName){
            var bag = {};
            if (dom.isString(oldName) && dom.isString(newName)){
              var method = this.fn[oldName]
              if (!!method){
                bag[newName] = method;
                return this.mixin(bag);
              };
            };
            //如果是一个属性包,如Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
            bag = oldName;
            for (var name in bag)
              if(bag.hasOwnProperty(name))
                this.alias(name,bag[name]);
            return this;
          };
          klass.staticizeWithout = function(arr){
            var conditions = {},keys = arr || [],me = this;
            for(var i=0,n = keys.length;i<n;i++){
              conditions[keys[i]] = 1;
            }
            dom.each(me.fn,function(method, name){
              if(!conditions[name] && dom.isFunction(me.fn[name]) && dom.isUndefined(me[name])&&
                name !== 'init' && name !== 'toString' && name !== 'valueOf' ){
                me[name] = function () {
                  var args = dom.toArray(arguments),
                  caller = args.shift();
                  method.name = name; //为其泛化方法添加一个name属性
                  return method.apply(me(caller), args);
                }
              }
            });
            return me;
          }
          return klass;
        }
        dom.mixin({
          is : function(obj,type) {
            return Object.prototype.toString.call(obj).match(/^/[object/s(.*)/]$/)[1] === type;
          },
          isArray: function (obj) {
            return dom.is(obj,"Array");
          },
          isFunction: function (obj) {
            return dom.is(obj,"Function") ;
          },
          isNumber: function (obj) {
            return dom.is(obj,"Number") ;
          },
          isString: function (obj) {
            return dom.is(obj,"String") ;
          },
          isUndefined: function (obj) {
            return  obj === void(0);
          },
          isWindow:function(obj){
            return obj.document && obj.document.nodeType === 9 ||
              obj.contentDocument && obj.contentDocument.nodeType === 9
          },
          each: function (obj, fn, bind) {
            for (var key in obj) //只遍历本地属性
              if (obj.hasOwnProperty(key))
                fn.call(bind, obj[key], key, obj);
          },
          toArray: function( array ) {
            var ret = [];
            if ( array != null ) {
              var i = array.length;
              if ( array.length == null || dom.isString(array) || dom.isFunction(array) || dom.isWindow(array)) {
                ret[0] = array
              } else {
                while(i)
                  ret[--i] = array[i];
              }
            }
            return ret;
          }
        });

这样dom就有如下几个方法mixin,factory,isArray,isFuction,isNumber,isString,isUndefined,isWindow,toArray,each与is,走实用主义路线,像isObject基本没有用。最新版的jQuery1.4a2好像加了两个特别的验证方法,isPlainObject(验证其是javascript core的Object而非宿主对象或DOM对象)与isEmptyObject(空对象,有点像{},但要保证其原型没有被扩展)。

哈希正是本文要说的,虽然javascript的Object什么都是,但显然力不从心嘛,像mootools,Prototype与Base2都搞了一个Hash类,我觉得jQuery也应该有一个,起码它来构建jQuery.data比较爽一些。


 var hash = dom.factory({
          klass:function(obj) {
            if(obj instanceof arguments.callee) return obj;
            return new arguments.callee.fn.init(arguments);
          },
//支持多种创建方式
//[1]传入一个普通对象
//hash({ key: "val" }) ==> { key: "val" }
//[2]传入两个参数,第一个必须是字符串
//hash("key", nasami) ==> { key: nasami }
//[3]传入一个以逗号隔开的字符串
//hash("key,a,key2,b") ==> { key: "a", key2: "b" }
//[4]传入一个以空白隔开的字符串
//hash(" key a key2 b") ==> { key: "a", key2: "b" }
//[5]传入一个数组
//hash([aa,bb,cc]) ==> { 1:aa,2:bb,3:cc }
          init: function(obj) {
            var key = obj[0],
            value = obj[1],
            core = {},
            i = 0;
            if(obj.length === 2){//如果有两个参数
              core[key] = value;
            }else{
              if(dom.isString(key)){
                key = key.replace( /^/s+|/s+$/g, "");//进行trim操作
                var arr = key.indexOf(",") !== -1 ? key.split(",") : key.split(//s+/g);
                while ((value = arr[i++]))
                  core[value] = arr[i++];
              }else if(dom.isArray(key)){
                for(var i= 0,n=key.length;i<n;i++)
                  core[i] = key[i]
              }else{
                core = key;
              }
            };
            this.empty();
            if(core)
              this.update(core);
          },
          empty: function() {
            this._hash = {};
            this.length = 0;
            return this;
          },
          //用于初始化hash
          //把普通对象的键值利用put方法传入_hash中,不考虑其prototype的成员
          update: function(obj) {
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                this.put(prop, obj[prop]);
            return this;
          },
          contains: function(key) {
            return this.get(key) !== void(0);
          },
          put: function(key, value) {
            if(!this.contains(key)) {//如果没包含则
              this.length++;
            }
            this._hash[key] = value;
            return value;
          },
          //取得相应的值
          get: function(key) {
            return this._hash[key];
          },
          //移除一个键值对
          remove: function(key) {
            delete this._hash[key];
            this.length--;
            return this;
          },
          //移除指定的键值对,并返回对应的值
          pop: function(key) {
            var results = this.get(key);
            this.remove(key);
            return results;
          },
          //取得所有的键,以数组形式返回
          keys: function() {
            var keys = [],obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                keys.push(prop);
            return keys;
          },
          //取得所有的值,以数组形式返回
          values: function() {
            var values = [],obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                values.push(obj[prop]);
            return values;
          },
          //取得所有的键值对,以数组形式返回
          items: function() {
            var items = [],obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                items.push([prop, obj[prop]]);
            return items;
          },
          //变成普通对象
          toObject: function() {
            return this._hash;
          },
          //仅当此键不存在时才添加,
          ensure: function(key, value) {
            var results = this.get(key);
            if(results === void(0))
              return this.put(key, value);
            return results;
          },
          forEach: function(fn, bind){
            var pairs = this.items();
            for(var i=0,n=pairs.length;i<n;i++){
              fn.call(bind, pairs[i][1], pairs[i][0]);
            }
          },
          map: function(fn, bind){
            var results = hash({});
            this.each(function(value, key){
              results.put(key, fn.call(bind, value, key));
            });
            return results;
          },
          filter: function(fn, bind){
            var results = hash({});
            this.each(function(value, key){
              if (fn.call(bind, value, key))
                results.put(key, value);
            });
            return results;
          },
          index: function(val) {//与get方法相反,取得其key
            var obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop) && obj[prop] === val)
                return prop;
            return null;
          },
          toString:function(){
            var pairs = this.items(),results = [];
            for(var i=0,n=pairs.length;i<n;i++){
              results[i] = pairs[i][0]+":"+pairs[i][1]
            }
            return "{ "+results.join(", ")+" }";
          }
        });
        hash.alias("forEach","each");
        hash.staticizeWithout();
        dom.hash = hash;

一些测试代码:

对于某些人看来,第一类工厂也有太过臃肿,为生成一个对象太劳师动众了(我一并写出来是为了方便我测试类工厂),下面是一个精简版。不需要类工厂,自行构建哈希,不过少了一些静态方法:


  var hash = function(obj) {
          if(obj instanceof arguments.callee) return obj;
          return new arguments.callee.fn.init(arguments);
        };
         hash.fn = hash.prototype= {
          init: function(obj) {
            var key = obj[0],
            value = obj[1],
            core = {},
            toString = Object.prototype.toString,
            i = 0;
            if(obj.length === 2){//如果有两个参数
              core[key] = value;
            }else{
              if(toString.call(key) === '[object String]'){
                key = key.replace( /^/s+|/s+$/g, "");//进行trim操作
                var arr = key.indexOf(",") !== -1 ? key.split(",") : key.split(//s+/g);
                while ((value = arr[i++]))
                  core[value] = arr[i++];
              }else if(toString.call(key) === '[object Array]'){
                for(var i= 0,n=key.length;i<n;i++)
                  core[i] = key[i]
              }else{
                core = key;
              }
            };
            this.empty();
            if(core)
              this.update(core);
          },
          empty: function() {
            this._hash = {};
            this.length = 0;
            return this;
          },
          //用于初始化hash
          //把普通对象的键值利用put方法传入_hash中,不考虑其prototype的成员
          update: function(obj) {
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                this.put(prop, obj[prop]);
            return this;
          },
          contains: function(key) {
            return this.get(key) !== void(0);
          },
          put: function(key, value) {
            if(!this.contains(key)) {//如果没包含则
              this.length++;
            }
            this._hash[key] = value;
            return value;
          },
          //取得相应的值
          get: function(key) {
            return this._hash[key];
          },
          //移除一个键值对
          remove: function(key) {
            delete this._hash[key];
            this.length--;
            return this;
          },
          //移除指定的键值对,并返回对应的值
          pop: function(key) {
            var results = this.get(key);
            this.remove(key);
            return results;
          },
          //取得所有的键,以数组形式返回
          keys: function() {
            var keys = [],obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                keys.push(prop);
            return keys;
          },
          //取得所有的值,以数组形式返回
          values: function() {
            var values = [],obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                values.push(obj[prop]);
            return values;
          },
          //取得所有的键值对,以数组形式返回
          items: function() {
            var items = [],obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop))
                items.push([prop, obj[prop]]);
            return items;
          },
          //变成普通对象
          toObject: function() {
            return this._hash;
          },
          //仅当此键不存在时才添加,
          ensure: function(key, value) {
            var results = this.get(key);
            if(results === void(0))
              return this.put(key, value);
            return results;
          },
          forEach: function(fn, bind){
            var pairs = this.items();
            for(var i=0,n=pairs.length;i<n;i++){
              fn.call(bind, pairs[i][1], pairs[i][0]);
            }
          },
          map: function(fn, bind){
            var results = hash({});
            this.each(function(value, key){
              results.put(key, fn.call(bind, value, key));
            });
            return results;
          },
          filter: function(fn, bind){
            var results = hash({});
            this.each(function(value, key){
              if (fn.call(bind, value, key))
                results.put(key, value);
            });
            return results;
          },
          index: function(val) {//与get方法相反,取得其key
            var obj = this._hash;
            for(var prop in obj)
              if(obj.hasOwnProperty(prop) && obj[prop] === val)
                return prop;
            return null;
          },
          toString:function(){
            var pairs = this.items(),results = [];
            for(var i=0,n=pairs.length;i<n;i++){
              results[i] = pairs[i][0]+":"+pairs[i][1]
            }
            return "{ "+results.join(", ")+" }";
          },
          each:this.forEach
        }
        hash.fn.init.prototype = hash.fn;

哈希对象
empty清空hash。
contains检测hash是否包含此键值对,参数为key
put向hash增加一个键值对,参数两个,key与value
get根据key取得相应的value
remove根据key移除相应的键值对,返回修改后的hash
pop根据key移除相应的键值对,返回被移除的value
keys取得所有的键,以数组形式返回
values取得所有的值,以数组形式返回
items取得所有的键值对,以数组形式返回
toObject变成普通对象
ensure仅当此键不存在时才添加新的键值对
forEach或each类似Array.forEach,迭代执行传入函数
map类似Array.map,迭代执行传入函数,把执行结果放到一个新hash返回
filter类似Array.filter,迭代执行传入函数,把符合条件的键值对放到一个新hash返回
toString没什么好说的
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值