现在的位置: 首页 > 综合 > 正文

第一类工厂与哈希对象

2013年11月16日 ⁄ 综合 ⁄ 共 18876字 ⁄ 字号 评论关闭

第一类工厂相当于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 没什么好说的
【上篇】
【下篇】

抱歉!评论已关闭.