javascript 超级数组对象
此类依赖于第一类工厂。
下面的东西基本给IE用的
var dom = {},//命名空间 slice = Array.prototype.slice; dom.mixin = function (obj, bag) { if (arguments.length === 1) { bag = obj; obj = this; }; if (obj && bag && typeof bag === 'object') { for (var p in bag) { if(bag.hasOwnProperty(p)) obj[p] = bag[p]; } }; if (!+"\v1") {//IE不能在for...in循环中遍历toString与valueOf属性,需要单独处理 var t = bag.toString,v = bag.valueOf,op = Object.prototype; if (bag.hasOwnProperty("toString") && typeof t === "function" && t !== op.toString) obj.toString = t; if (bag.hasOwnProperty("valueOf") && typeof v === "function" && v !== op.valueOf) obj.valueOf = v; } return obj; }; dom.factory = function(obj){//第一类工厂 var init = obj.init, klass = function() { //如果传入参数与当前类是同一类型,则直接返回 if(arguments.length === 1 && arguments[0] instanceof klass) return arguments[0]; return new klass.fn.init(arguments); } 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(new function(){ var _toString = Object.prototype.toString, _slice = Array.prototype.slice, _push = Array.prototype.push, is = function(obj,type) { return _toString.call(obj).match(/^\[object\s(.*)\]$/)[1] === type; } return { isArray: function (obj) { return is(obj,"Array"); }, isFunction: function (obj) { return is(obj,"Function") ; }, isNumber: function (obj) { return is(obj,"Number") ; }, isString: function (obj) { return is(obj,"String") ; }, isUndefined: function (obj) { return obj === void(0); }, each: function (obj, fn, bind) { for (var key in obj) //只遍历本地属性 if (obj.hasOwnProperty(key)) fn.call(bind, obj[key], key, obj); }, isArrayLike : function (obj) {//包括Array if(dom.isArray(obj) || obj.callee) return true; if(is(obj,'NodeList')) return true; if(is(obj,'HTMLCollection')) return true; //不能为字符串,不能为window,具有length属性 if(dom.isNumber(obj.length) && !dom.isString(obj) && !obj.eval){ if(obj.nextNode || obj.item) return true; var n = obj.length - 1 < 0 ? 0 : obj.length - 1 ; //如果是具有数字键或length属性的对象,如jQuery对象 if(obj.hasOwnProperty(n) && obj.hasOwnProperty(0)) return true return false; } return false; }, toArray : function (arr) { //把普通对象变成原生数组对象 if(arguments.length === 0 || arr === null){ return []; }else if(arr.callee){//如果是Arguments对象 return _slice.call(arr); }else if(dom.isArray(arr)){//如果Array对象返回一个克隆 return arr.concat(); }else if(dom.isArrayLike(arr)){ try{//jQuery对象,dom对象,el.getElementsByTagName得到的HTMLCollection //与el.childNodes得到的NodeList return _slice.call(arr); }catch(e){//IE用slice处理元素或节点集合会出错,只能慢慢拷贝 var ret = [], i = arr.length; while (i) ret[--i] = arr[i]; //Clone数组 return ret; } }else {//普通函数,单个元素节点,字符串,数字,window对象 return [arr]; } }, setArray: function (els) { //把普通对象变成类数组对象 this.length = 0; _push.apply(this, els); return this; } } });
其核心函数:
var array = dom.factory({ init: function (obj) { //这里的obj总是为Arguments对象 if (obj.length === 1) { var first = obj[0]; if (dom.isArray(first)) { //将原生数组变成超级数组 this.setArray(first); } else if (dom.isNumber(first)) { //用一个数字初始化成数组,再用此数组变成超级数组 this.setArray(Array(first)); } else if (dom.isArrayLike(first)) { //将类组数转化为原生数组,再将原生数组变成超级数组 this.setArray(this.toArray(first)); } else {//如果传入单个字符串,window,函数 this.setArray([first]); } } else {//如果传入的是1,2,3,4, this.setArray(this.toArray(obj)); } }, toString: function () { //返回一个字符串 return this.valueOf().toString(); }, valueOf: function () {//获得里面的数组对象 return slice.call(this); }, get: function (index) {//获得里面的数组对象或数组元素 return arguments.length ? this[index]: this.valueOf(); }, setArray: dom.setArray, toArray: dom.toArray });
其他方法
//为超级数组对象添加原生数组对象的泛化方法 dom.each("pop,push,reverse,shift,sort,unshift,join,indexOf, \ lastIndexOf,forEach,every,some,reduce,reduceRight".match(/\w+/g), function (name) { if (dom.isFunction(Array.prototype[name])) array.fn[name] = Array.prototype[name]; }); dom.each({ //为超级数组对象添加自定义方法与改造了的泛化方法 concat: function () { var arr = slice.call(this), ret; if (arguments.length === 1) { var first = arguments[0] if (first instanceof dom.array) { ret = arr.concat(first.valueOf()) } else { ret = arr.concat(first) } } else { var args = this.toArray(arguments); ret = arr.concat(args) } return array(ret); }, splice: function () {//改变原对象 var args = this.toArray(arguments), arr = this.valueOf(), ret = Array.prototype.splice.apply(arr, args); this.setArray(arr); //修正原数组 return array(ret); //返回被删除元素组成的数组 }, slice: function () {//不会改变原对象 var args = this.toArray(arguments), arr = this.valueOf(), ret = slice.apply(arr, args); return array(ret); }, inArray: function (el) { if(Array.indexOf){ return this.valueOf().indexOf(el) !== -1; } for (var i = 0, n = this.length; i < n; i++) if (this[i] === el) return true; return false; }, indexOf: function (el, index) { var n = this.length, i = index == null ? 0 : index < 0 ? Math.max(0, n + index) : index; for (; i < n; i++) if (i in this && 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 (i in this && this[i] === el) return i; return -1 }, //对数组中的每个元素都执行一次指定的函数(fn) forEach: function (fn, bind) { for (var i = 0, n = this.length; i < n; i++) i in this && fn.call(bind, this[i], i, this) }, //对数组中的每个元素都执行一次指定的函数(f),并且创建一个新的超级数组, //该数组元素是所有回调函数执行时返回值为 true 的原数组元素。 filter: function (fn, bind) { if (Array.filter) { return array(this.valueOf().filter(fn, bind)); } else { var results = array(); this.forEach( function(value, index) { fn.call(bind, value, index, this) && results.push(value); }); return results; } }, without:function(){//去掉与传入参数相同的元素 var args = array(arguments) return this.filter(function (el) { return !args.contains(el); }); }, one : function(fn,bind){//类似上面,但只返回一个匹配者 for (var i = 0, n = this.length; i < n; i++) if(i in this && fn.call(bind, this[i], i, this)) return this[i] return null; }, //对数组中的每个元素都执行一次指定的函数(f),将它们的返回值放到一个新的超级数组 map: function (fn, bind) { if (Array.map) { return array(this.valueOf().map(fn, bind)) } else { var results = array(); this.forEach(function(value, index) { results.push(fn.call(bind, value, index, this)); }); return results; } }, //如果数组中每一个元素都满足参数中提供的测试函数,则返回真。 every: function (fn,bind) { for (var i = 0, n = this.length; i < n; i++) if (i in this && !fn.call(bind, this[i], i, this)) return false; return true }, //如果数组中至少有一个元素满足参数函数的测试,则返回真。 some: function (fn, bind) { for (var i = 0, n = this.length; i < n; i++) if (i in this && fn.call(bind, this[i], i, this)) return true; return false }, // 用回调函数迭代地将数组简化为单一的值。 // 如果指定了可选参数 initial,该参数将被当成是数组中的第一个值来处理, // 或者如果数组为空的话就作为最终返回值。如果数组为空并且没有传递 // initial 参数,则返回 null。 // 它回调函数的定义function(previousValue, currentValue, index, array){} // 相当于Prototype中的inject reduce: function (fn, initial, bind) { if (this.length == 0) return initial; var i = initial !== undefined ? 0 : 1; var ret = initial !== undefined ? initial : this[0]; for (var n = this.length; i < n; i++) ret = fn.call(bind, ret, this[i], i, this); return ret; }, reduceRight: function (fn, initial, bind) { if (this.length == 0) return initial; var i = initial !== undefined ? this.length - 1 : this.length - 2; var ret = initial !== undefined ? initial : this[this.length - 1]; for (; i >= 0; i--) { ret = fn.call(bind, ret, this[i], i, this); } return ret; }, isEmpty: function () { return this.length == 0; }, //如果不指明位置,默认是插在最前面 insertAt: function (item, position) { this.splice(position, 0, item); return this; }, //http://msdn.microsoft.com/zh-cn/library/bb383786.aspx //移除 Array 对象中某个元素的第一个匹配项。 remove: function (item) { var index = this.indexOf(item); if (index != -1) this.removeAt(index); return item; }, //移除 Array 对象中指定位置的元素。 removeAt: function (index) { return this.splice(index, 1) }, //将数组对象变成普通对象,以传入数组的元素作为键,原来数组的元素作为值 toObject: function (keys) { var obj = {},length,i; if(!!keys && dom.isArray(keys)){ length = Math.min(this.length, keys.length); for(i = 0; i < length; i++) obj[keys[i]] = this[i]; }else{ for(i = 0,length=this.length;i<length;i++) obj[i] = this[i] } return obj; }, first: function () { return this[0]; }, last: function () { return this[this.length - 1]; }, clear: function () { for (var i = this.length - 1; i >= 0; i--) delete this[i]; this.length = 0; return this; }, swap: function (index1, index2) { var arr = this; if (index1 < 0) index1 += arr.length; // starting from the end if (index2 < 0) index2 += arr.length; arr[index1] = arr[index1] ^ arr[index2]; arr[index2] = arr[index2] ^ arr[index1]; arr[index1] = arr[index1] ^ arr[index2]; return this; }, shuffle: function () { // Jonas Raoni Soares Silva //http://jsfromhell.com/array/shuffle [v1.0] for (var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x); return this; }, max: function () { return Math.max.apply({}, this.valueOf()); }, min: function () { return Math.min.apply({}, this.valueOf()); }, compact: function () { return this.filter(function (el) { return el != null; }); }, difference: function (other) { var len = Math.max(this.length, other.length), i, p, ret = array(), diff = {}; for (i = 0; i < len; i++) { if (i < this.length) diff[this[i]] = diff[this[i]] ? 2 : 1; if (i < other.length) diff[other[i]] = diff[other[i]] ? 2 : 1; } for (p in diff) if (diff[p] == 1) ret.push(p); return ret; }, flatten: function () { var _flatten = function () { for (var ret = [], i = 0, n = arguments.length; i < n; i++) { var el = arguments[i]; dom.isArray(el) ? ret.push.apply(ret, _flatten.apply(null, el)) : ret.push(el) } return ret }; var arr = _flatten(this.valueOf()); this.setArray(arr); return this; }, norepeat: function () {//返回数组中只出现过一次的元素 var arr = this.valueOf(),results=[]; for(var i=0,n=arr.length,tmp={};i<n;i++){ tmp[arr[i]]?tmp[arr[i]]++:(tmp[arr[i]]=1); } for(var p in tmp){ if(tmp[p]===1) results.push(p); } return array(results); }, ensure: function (item) { //如果原来数组不存在就合并它 if (!this.inArray(item)) this.push(item); return this; }, combine: function (array) { //取两个数组的并集 for (var i = 0, l = array.length; i < l; i++) this.ensure(array[i]); return this; }, unique: function () { //取数组中唯一的元素并放进新数组中返回 return array().combine(this); } },function(method,name){ if(!dom.isFunction(array.fn[name])){ array.fn[name] = method; } }); array.alias({ forEach:"each", inArray:"contains" }); array.staticizeWithout(['toArray','setArray']); dom.array = array;
下面测试代码:
超级数组对象 | |
---|---|
pop | 同Array.pop |
push | 同Array.push |
reverse | 同Array.reverse,不过返回的是超级数组 |
sort | 同Array.sort,不过返回的是超级数组 |
splice | 同Array.splice,不过返回的是超级数组 |
slice | 同Array.slice,不过返回的是超级数组 |
join | 同Array.join |
unshift | 同Array.unshift,将新加的参数添加到原对象的前面 |
shift | 同Array.shift |
indexOf | 返回给定元素在超级数组中的索引值,没有则返回-1 |
lastIndexOf | 返回给定元素在超级数组中的索引值,没有则返回-1,只不过这次是从后面数起 |
forEach或each | 类似Array.forEach,迭代执行回调函数 |
map | 类似Array.map,迭代执行回调函数,把执行结果放到一个新超级数组对象返回 |
filter | 类似Array.filter,迭代执行回调函数,把符合条件的键值对放到一个新超级数组对象返回 |
every | 类似Array.every,如果所有元素都满足回调函数,为真 |
some | 类似Array.some,只要有一个满足回调函数就为真 |
one | 类似Array.one,返回第一个满足回调函数的元素 |
without | 过滤与传入参数相同的元素,放进一个新超级数组返回 |
reduce | 用回调函数迭代地将数组简化为单一的值。 如果指定了可选参数 initial,该参数将被当成是数组中的第一个值来处理, 或者如果数组为空的话就作为最终返回值。如果数组为空并且没有传递 initial 参数,则返回 null。 回调函数的样子应该为function(previousValue, currentValue, index, array){} |
reduceRight | 同reduce,不过自右到左执行 |
isEmpty | 判断对象是否为空 |
insertAt | 在指定的索引值后插入新元素 |
remove | 移除第一个与参数相同的元素 |
removeAt | 移除指定位置上的元素 |
toObject | 以传入数组的元素作为键,原超级数组的值作为值,构造一个普通对象 |
first | 返回第一个元素 |
last | 返回最后一个元素 |
clear | 清空所有元素 |
swap | 交换两个索引值上的元素 |
shuffle | 对超级数组的元素进行乱序 |
max | 取得数值最大的元素 |
min | 取得数值最小的元素 |
compact | 移除超级数组中的null元素与undefined元素 |
flatten | 对超级数组进行平整化处理,确保是一维的超级数组 |
norepeat | 以超级数组形式返回超级数组中所有只出现过一次的元素, |
unique | 去掉超级数组中的重复元素 |
ensure | 只有原超级数组中没有此元素才允许加入它,返回新的超级对象 |
inArray与contains | 检测超级数组是否已存在与参数相同的元素 |
combine | 与传入(超级)数组取并集 |
difference | 与传入(超级)数组取并集后再减去它的交集,换言之,取对方都没有的元素组成的一个新的超级对象 |
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年