问题
I am struggling with deep copies of objects in nodeJS. my own extend is crap. underscore's extend is flat. there are rather simple extend variants here on stackexchange, but none are even close to jQuery.extend(true, {}, obj, obj, obj) .. (most are actually terrible and screw up the benefits of asnyc code.)
hence, my question: is there a good deep copy for NodeJS? Has anybody ported jQuery's ?
回答1:
You want jQuery's, so just use it:
function extend() {
var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false,
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
push = Array.prototype.push,
slice = Array.prototype.slice,
trim = String.prototype.trim,
indexOf = Array.prototype.indexOf,
class2type = {
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",
"[object Function]": "function",
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Object]": "object"
},
jQuery = {
isFunction: function (obj) {
return jQuery.type(obj) === "function"
},
isArray: Array.isArray ||
function (obj) {
return jQuery.type(obj) === "array"
},
isWindow: function (obj) {
return obj != null && obj == obj.window
},
isNumeric: function (obj) {
return !isNaN(parseFloat(obj)) && isFinite(obj)
},
type: function (obj) {
return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"
},
isPlainObject: function (obj) {
if (!obj || jQuery.type(obj) !== "object" || obj.nodeType) {
return false
}
try {
if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
return false
}
} catch (e) {
return false
}
var key;
for (key in obj) {}
return key === undefined || hasOwn.call(obj, key)
}
};
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (typeof target !== "object" && !jQuery.isFunction(target)) {
target = {}
}
if (length === i) {
target = this;
--i;
}
for (i; i < length; i++) {
if ((options = arguments[i]) != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target === copy) {
continue
}
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : []
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// WARNING: RECURSION
target[name] = extend(deep, clone, copy);
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
return target;
}
and a small test to show that it does deep copies
extend(true,
{
"name": "value"
},
{
"object": "value",
"other": "thing",
"inception": {
"deeper": "deeper",
"inception": {
"deeper": "deeper",
"inception": {
"deeper": "deeper"
}
}
}
}
)
But remember to provide attribution: https://github.com/jquery/jquery/blob/master/src/core.js
回答2:
It's already been ported. node-extend
Note the project doesn't have tests and doesn't have much popularity, so use at your own risk.
As mentioned you probably don't need deep copies. Try to change your data structures so you only need shallow copies.
Few months later
I wrote a smaller module instead, recommend you use xtend. It's not got an implementation containing jQuery baggage nor does it have bugs like node-extend does.
回答3:
A quick and dirty answer to deep copies is just to cheat with a little JSON. It's not the most performant, but it does do the job extremely well.
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
回答4:
Please use the built-in util module:
var extend = require('util')._extend;
var merged = extend(obj1, obj2);
回答5:
I know this is an old question, but I'd just like to throw lodash's merge into the mix as a good solution. I'd recommend lodash for utility functions in general :)
回答6:
This works for deep object extension... be warned that it replaces arrays rather than their values but that can obviously be updated how you like. It should maintain enumeration capabilities and all the other stuff you probably want it to do
function extend(dest, from) {
var props = Object.getOwnPropertyNames(from), destination;
props.forEach(function (name) {
if (typeof from[name] === 'object') {
if (typeof dest[name] !== 'object') {
dest[name] = {}
}
extend(dest[name],from[name]);
} else {
destination = Object.getOwnPropertyDescriptor(from, name);
Object.defineProperty(dest, name, destination);
}
});
}
回答7:
In Node.js, You can use Extendify to create an _.extend function that supports nested objects extension (deep extend) and is also immutable to it's params (hence deep clone).
_.extend = extendify({
inPlace: false,
isDeep: true
});
回答8:
node.extend does it deep and has familiar jQuery syntax
回答9:
just install extend. docs: node extend package install:
npm install extend
then enjoy it:
extend ( [deep], target, object1, [objectN] )
deep is optional. default is false. if switch to true it will recursively merge your objects.
回答10:
Sharped version called whet.extend.
I re-write node-extend with CoffeeScript and add travis-ci test suite, because I need deep coping in Node for myself, so now it is here.
And yes, I think in some case its absolutely correctly to use deep merge, for example I use it at config works, when we are need to merge default and user branches together.
回答11:
You also can use my version of extend plugin https://github.com/maxmara/dextend
来源:https://stackoverflow.com/questions/9399365/deep-extend-like-jquerys-for-nodejs