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 | 与传入(超级)数组取并集后再减去它的交集,换言之,取对方都没有的元素组成的一个新的超级对象 |
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
浙公网安备 33010602011771号