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 | 与传入(超级)数组取并集后再减去它的交集,换言之,取对方都没有的元素组成的一个新的超级对象 |
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库