Skip to content

Instantly share code, notes, and snippets.

@janryWang
Created January 4, 2015 09:45
Show Gist options
  • Save janryWang/c898c163134f63379f8f to your computer and use it in GitHub Desktop.
Save janryWang/c898c163134f63379f8f to your computer and use it in GitHub Desktop.
一个数据处理器,api语法类似mongodb,可以对json任意层次的数据进行单元化克隆,混合,数组操作,查询排序等!功能非常强大
var dataOperator = (function() {
var COMMANDS,
DataOperator,
KEYWORDS,
bind,
copy,
forEach,
getType,
inPaths,
isArray,
isBoolean,
isEmptyArray,
isEmptyObj,
isFunction,
isObject,
isReference,
isString,
isValue,
merge,
toArray,
__slice = [].slice;
COMMANDS = {
OPERATORS: "$remove,$set,$push,$slice,$concat,$pop,$unshift,$merge,$deep_merge,$find,$sort,$foreach".split(","),
FILTERS: "$gt,$lt,$is,$gte,$lte,$icontains,$contains,$in,$not_in".split(","),
SORTS: "$desc,$asc".split(","),
CLONES: "$white_list,$black_list,$filter,$deep".split(","),
COMMONS: "$callback".split(",")
};
KEYWORDS = (function() {
var cmd_name,
cmds_name,
keywords,
_i,
_len,
_ref;
keywords = {};
for (cmds_name in COMMANDS) {
_ref = COMMANDS[cmds_name];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
cmd_name = _ref[_i];
keywords[cmd_name] = true;
}
}
return keywords;
})();
getType = function(val) {
return Object.prototype.toString.call(val);
};
isArray = function(arr) {
return getType(arr) === "[object Array]";
};
isEmptyArray = function(arr) {
return isArray(arr) && arr.length === 0;
};
toArray = function() {
var args;
args = [].slice.apply(arguments);
return [].slice.apply(args[0], args.slice(1));
};
isString = function(str) {
return getType(str) === "[object String]";
};
isFunction = function(fun) {
return getType(fun) === "[object Function]";
};
isObject = function(obj) {
return getType(obj) === "[object Object]";
};
isReference = function(val) {
return isArray(val) || isObject(val);
};
isEmptyObj = function(obj) {
return ! (isReference(obj) && Object.keys(obj).length > 0);
};
isBoolean = function(obj) {
return getType(obj) === "[object Boolean]";
};
isValue = function(val) {
return ! isReference(val);
};
bind = function() {
var args,
context,
fun;
fun = arguments[0],
context = arguments[1],
args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
return function() {
var res;
if (isFunction(fun) && (res = fun.apply(context, args))) {
return res;
} else {}
};
};
forEach = function(arr, callback) {
var index,
keys,
keys_length,
_results;
if (!isFunction(callback)) {
return;
}
if (isReference(arr)) {
keys = Object.keys(arr);
keys_length = keys.length;
index = 0;
_results = [];
while (index < keys_length) {
if (callback(arr[keys[index]], keys[index]) === false) {
break;
}
_results.push(index++);
}
return _results;
}
};
merge = function() {
var args,
args_length,
isDeep;
args = toArray(arguments);
isDeep = false;
if (isBoolean(args[0])) {
isDeep = args[0] === true ? true: false;
args = args.slice(1);
}
args_length = args.length;
if (args_length < 2) {
return args[0];
}
if (args_length === 2) {
forEach(args[1],
function(item, name) {
args[0][name] = args[0][name] || args[1][name].constructor();
if (isDeep && isReference(item)) {
merge(isDeep, args[0][name], item);
} else {
args[0][name] = item;
}
});
return args[0];
} else {
return merge(isDeep, args[0], merge.apply(null, [isDeep].concat(args.slice(1))));
}
};
copy = function() {
var args,
filter,
isDeep,
objType,
path,
res;
args = toArray(arguments);
isDeep = false;
if (isBoolean(args[0])) {
isDeep = args[0] === true ? true: false;
args = args.slice(1);
}
if (isValue(args[0])) {
return args[0];
}
filter = args[1] && isFunction(args[1]) ? args[1] : false;
path = args[2] && isString(args[2]) ? args[2] : "";
objType = isArray(args[0]) ? 1: 2;
res = args[0].constructor();
forEach(args[0],
function(item, name) {
var filter_res,
_path;
_path = path ? (objType === 2 ? path + "." + name: path + "[" + name + "]") : name;
if (filter) {
filter_res = filter(item, name, _path);
if (isBoolean(filter_res)) {
if (filter_res) {
if (isDeep && isReference(item)) {
res[name] = copy(isDeep, item, filter, _path);
_path = path;
} else {
res[name] = item;
}
} else {
res[name] = item;
}
} else {
if (isDeep && isReference(item)) {
res[name] = copy(isDeep, item, filter, _path);
_path = path;
} else {
res[name] = item;
}
}
} else {
if (isDeep && isReference(item)) {
res[name] = copy(isDeep, item, filter, _path);
_path = path;
} else {
res[name] = item;
}
}
});
return res;
};
inPaths = function(path, paths, _swap) {
var res,
_inPath;
res = false;
_inPath = function(a, b) {
var a_l,
b_l,
index;
a_l = a.length;
b_l = b.length;
index = 0;
while (index < b_l) {
if (b.charAt(index) !== a.charAt(index)) {
return false;
}
index++;
}
if (index === b_l) {
if (a_l === b_l) {
return true;
} else if (a_l > b_l && "[.".indexOf(a.charAt(b_l)) > -1) {
return true;
}
}
};
forEach(paths,
function(_path) {
res = _swap ? _inPath(_path, path) : _inPath(path, _path);
if (res) {
return false;
}
});
return res;
};
DataOperator = (function() {
function DataOperator(data, cmds) {
this.data = data;
this._commands.__parent__ = this;
this._filters.__parent__ = this;
if (cmds) {
this.exec(cmds);
}
}
DataOperator.prototype._collect = function(obj) {
var name,
res;
res = {
operators: {},
filters: {},
sorts: {},
clones: {},
commons: {},
props: {},
value: null
};
if (!isReference(obj)) {
res.value = obj;
return res;
}
for (name in obj) {
if (COMMANDS.OPERATORS.indexOf(name) > -1) {
res.operators[name] = obj[name];
} else if (COMMANDS.FILTERS.indexOf(name) > -1) {
res.filters[name] = obj[name];
} else if (COMMANDS.SORTS.indexOf(name) > -1) {
res.sorts[name] = obj[name];
} else if (COMMANDS.CLONES.indexOf(name) > -1) {
res.clones[name] = obj[name];
} else if (COMMANDS.COMMONS.indexOf(name) > -1) {
res.commons[name] = obj[name];
} else {
res.props[name] = obj[name];
}
}
return res;
};
DataOperator.prototype._filters = {
$is: function(a, b) {
return a === b;
},
$gt: function(a, b) {
return a > b;
},
$lt: function(a, b) {
return a < b;
},
$gte: function(a, b) {
return a >= b;
},
$lte: function(a, b) {
return a <= b;
},
$icontains: function(a, b) {
return a.toLowerCase().indexOf(b.toLowerCase()) > -1;
},
$contains: function(a, b) {
return a.indexOf(b) > -1;
},
$in: function(a, b) {
return b.indexOf(a) > -1;
},
$not_in: function(a, b) {
return b.indexOf(a) === -1;
}
};
DataOperator.prototype._commands = {
$set: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (isReference(prop_val)) {
ref[prop_name] = ref[prop_name] || prop_val.constructor();
_results.push(this.$set(ref[prop_name], this.__parent__._collect(prop_val)));
} else {
_results.push(ref[prop_name] = prop_val);
}
}
return _results;
},
$remove: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (!isArray(ref) && prop_val === true) {
_results.push(delete ref[prop_name]);
} else {
_results.push(void 0);
}
}
return _results;
},
$slice: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (ref[prop_name] && isArray(ref[prop_name])) {
if (!isArray(prop_val)) {
prop_val = [prop_val];
}
_results.push(ref[prop_name] = ref[prop_name].slice.apply(ref[prop_name], prop_val));
} else {
_results.push(void 0);
}
}
return _results;
},
$push: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (ref[prop_name] && isArray(ref[prop_name])) {
_results.push(ref[prop_name].push(prop_val));
} else {
_results.push(void 0);
}
}
return _results;
},
$concat: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (ref[prop_name] && isArray(ref[prop_name])) {
if (!isArray(prop_val)) {
prop_val = [prop_val];
}
_results.push(ref[prop_name] = ref[prop_name].concat(prop_val));
} else {
_results.push(void 0);
}
}
return _results;
},
$pop: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (ref[prop_name] && isArray(ref[prop_name])) {
_results.push(ref[prop_name].pop());
} else {
_results.push(void 0);
}
}
return _results;
},
$unshift: function(ref, collected) {
var prop_name,
prop_val,
_ref,
_results;
_ref = collected.props;
_results = [];
for (prop_name in _ref) {
prop_val = _ref[prop_name];
if (ref[prop_name] && isArray(ref[prop_name])) {
_results.push(ref[prop_name].unshift(prop_val));
} else {
_results.push(void 0);
}
}
return _results;
},
$merge: function(ref, collected) {
return merge(ref, collected.props);
},
$deep_merge: function(ref, collected) {
return merge(true, ref, collected.props);
},
$clone: function(ref, collected) {
var blackList,
callback,
filter,
isDeep,
res,
whiteList;
isDeep = !!collected.clones.$deep;
whiteList = collected.clones.$white_list;
blackList = collected.clones.$black_list;
filter = collected.clones.$filter;
callback = collected.commons.$callback;
if (!isEmptyArray(whiteList)) {
res = copy(isDeep, ref,
function(item, name, path) {
var filter_res;
if (inPaths(path, whiteList, true)) {
if (!isEmptyArray(blackList)) {
if (!inPaths(path, blackList)) {
if (isFunction(filter)) {
filter_res = filter(item, name, path);
}
if (isBoolean(filter_res)) {
if (filter_res) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
});
} else if (!isEmptyArray(blackList)) {
res = copy(isDeep, ref,
function(item, name, path) {
var filter_res;
if (!inPaths(path, blackList)) {
if (isFunction(filter)) {
filter_res = filter(item, name, path);
}
if (isBoolean(filter_res)) {
if (filter_res) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
});
} else if (isFunction(filter)) {
res = copy(isDeep, ref,
function(item, name, path) {
var filter_res;
if (isFunction(filter)) {
filter_res = filter(item, name, path);
}
if (isBoolean(filter_res)) {
if (filter_res) {
return true;
} else {
return false;
}
} else {
return true;
}
});
} else {
res = copy(isDeep, ref);
}
if (isFunction(callback)) {
return callback(res);
}
},
$find: function(ref, collected) {
var callback,
condition_length,
ok,
res,
_this;
_this = this;
callback = collected.commons.$callback;
ok = 0;
condition_length = Object.keys(collected.filters).length;
res = [];
if (!isEmptyObj(collected.filters)) {
forEach(ref,
function(ref_item) {
if (!isEmptyObj(ref_item)) {
forEach(collected.filters,
function(filter_body, filter_name) {
return forEach(filter_body,
function(item, key) {
if (_this.__parent__._filters[filter_name](ref_item[key], item)) {
return ok++;
}
});
});
if (ok >= condition_length) {
res.push(ref_item);
return false;
}
}
});
} else {
res = ref;
}
if (isFunction(callback)) {
return callback(res);
}
},
$foreach: function(ref, collected) {
if (isFunction(collected.value)) {
return forEach(ref, collected.value);
}
},
$sort: function(ref, collected) {
var key,
val,
_ref,
_results;
if (isArray(ref) && isReference(collected.value)) {
_ref = collected.props;
_results = [];
for (key in _ref) {
val = _ref[key];
if (val === "desc") {
_results.push(ref.sort(function(a, b) {
if (isReference(a) && isReference(b)) {
if (a[key] < b[key]) {
return 1;
} else {
return - 1;
}
} else {
if (a < b) {
return 1;
} else {
return - 1;
}
}
}));
} else {
_results.push(ref.sort(function(a, b) {
if (isReference(a) && isReference(b)) {
if (a[key] > b[key]) {
return 1;
} else {
return - 1;
}
} else {
if (a > b) {
return 1;
} else {
return - 1;
}
}
}));
}
}
return _results;
} else {
if (collected.value === "desc") {
return ref.sort(function(a, b) {
return b - a;
});
} else {
return ref.sort(function(a, b) {
return a - b;
});
}
}
}
};
DataOperator.prototype._exec = function(ref, cmd_obj) {
var cmd_body,
cmd_name,
_results;
_results = [];
for (cmd_name in cmd_obj) {
cmd_body = cmd_obj[cmd_name];
if (this._commands[cmd_name]) {
_results.push(this._commands[cmd_name](ref, this._collect(cmd_body)));
} else if (isReference(cmd_body) && !KEYWORDS[cmd_name]) {
ref[cmd_name] = ref[cmd_name] || cmd_body.constructor();
_results.push(this._exec(ref[cmd_name], cmd_body));
} else {
_results.push(void 0);
}
}
return _results;
};
DataOperator.prototype.exec = function(cmds) {
return this._exec(this.data, cmds);
};
return DataOperator;
})();
merge(DataOperator, {
exec: function(data, cmds) {
return new DataOperator(data, cmds);
},
isArray: isArray,
isString: isString,
isFunction: isFunction,
isObject: isObject,
isReference: isReference,
isEmptyObj: isEmptyObj,
isEmptyArray: isEmptyArray,
isValue: isValue,
bind: bind,
forEach: forEach,
merge: merge,
copy: copy
});
return DataOperator;
})();
@janryWang
Copy link
Author

下面是使用方法:
如果给定一个测试对象:
test_obj = {
name:"janry",
.....
};
如果要很简单的克隆只需要DataOperator.copy(test_obj)就行了,当然这是浅复制,
如果要深度复制DataOperator.copy(true,test_obj),这就是深度复制了,
如果你的需求有点变态,需要对于某个属性深度复制,其他属性则浅复制
DataOperator.copy(true,test_obj,function(value/属性值/,key/属性键名/,path/属性所在路径/){
if(condition){
return true;//说明深度复制
} else {
return false;//说明浅复制
}
});

这是对于静态方法的使用。

下面则是对于动态方法的使用
DataOperator.exec(test_obj,{
$set:{age:23}
});这种方式相当于给对象添加一个属性,其他类似的方法还有$remove,$push,$slice,$concat,$pop,$unshift,$merge,$deep_merge,$find,$sort,$foreach

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment