// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returnedfunction extend(from, to){if (from == null || typeof from != "object") return from;if (from.constructor != Object && from.constructor != Array) return from;if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||from.constructor == String || from.constructor == Number || from.constructor == Boolean)return new from.constructor(from);
to = to || new from.constructor();
for (var name in from){to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];}
return to;}
测试:
var obj ={date: new Date(),func: function(q) { return 1 + q; },num: 123,text: "asdasd",array: [1, "asd"],regex: new RegExp(/aaa/i),subobj:{num: 234,text: "asdsaD"}}
var clone = extend(obj);
function clone(obj){if(typeof(obj) == 'function')//it's a simple functionreturn obj;//of it's not an object (but could be an array...even if in javascript arrays are objects)if(typeof(obj) != 'object' || obj.constructor.toString().indexOf('Array')!=-1)if(JSON != undefined)//if we have the JSON objtry{return JSON.parse(JSON.stringify(obj));}catch(err){return JSON.parse('"'+JSON.stringify(obj)+'"');}elsetry{return eval(uneval(obj));}catch(err){return eval('"'+uneval(obj)+'"');}// I used to rely on jQuery for this, but the "extend" function returns//an object similar to the one cloned,//but that was not an instance (instanceof) of the cloned class/*if(jQuery != undefined)//if we use the jQuery pluginreturn jQuery.extend(true,{},obj);else//we recursivley clone the object*/return (function _clone(obj){if(obj == null || typeof(obj) != 'object')return obj;function temp () {};temp.prototype = obj;var F = new temp;for(var key in obj)F[key] = clone(obj[key]);return F;})(obj);}
function clone(obj, clones) {// Makes a deep copy of 'obj'. Handles cyclic structures by// tracking cloned obj's in the 'clones' parameter. Functions// are included, but not cloned. Functions members are cloned.var new_obj,already_cloned,t = typeof obj,i = 0,l,pair;
clones = clones || [];
if (obj === null) {return obj;}
if (t === "object" || t === "function") {
// check to see if we've already cloned objfor (i = 0, l = clones.length; i < l; i++) {pair = clones[i];if (pair[0] === obj) {already_cloned = pair[1];break;}}
if (already_cloned) {return already_cloned;} else {if (t === "object") { // create new objectnew_obj = new obj.constructor();} else { // Just use functions as isnew_obj = obj;}
clones.push([obj, new_obj]); // keep track of objects we've cloned
for (key in obj) { // clone object membersif (obj.hasOwnProperty(key)) {new_obj[key] = clone(obj[key], clones);}}}}return new_obj || obj;}
循环阵列测试…
a = []a.push("b", "c", a)aa = clone(a)aa === a //=> falseaa[2] === a //=> falseaa[2] === a[2] //=> falseaa[2] === aa //=> true
功能测试…
f = new Functionf.a = aff = clone(f)ff === f //=> trueff.a === a //=> false
var clone = require('clone');
var a = { foo: { bar: 'baz' } }; // inital value of avar b = clone(a); // clone a -> ba.foo.bar = 'foo'; // change a
console.log(a); // { foo: { bar: 'foo' } }console.log(b); // { foo: { bar: 'baz' } }
//If Object.create isn't already defined, we just do the simple shim,//without the second argument, since that's all we need herevar object_create = Object.create;if (typeof object_create !== 'function') {object_create = function(o) {function F() {}F.prototype = o;return new F();};}
function deepCopy(obj) {if(obj == null || typeof(obj) !== 'object'){return obj;}//make sure the returned object has the same prototype as the originalvar ret = object_create(obj.constructor.prototype);for(var key in obj){ret[key] = deepCopy(obj[key]);}return ret;}
/*** Deep copy an object (make copies of all its object properties, sub-properties, etc.)* An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone* that doesn't break if the constructor has required parameters** It also borrows some code from http://stackoverflow.com/a/11621004/560114*/function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {if(src === null || typeof(src) !== 'object'){return src;}
//Honor native/custom clone methodsif(typeof src.clone == 'function'){return src.clone(true);}
//Special cases://Dateif(src instanceof Date){return new Date(src.getTime());}//RegExpif(src instanceof RegExp){return new RegExp(src);}//DOM Elementif(src.nodeType && typeof src.cloneNode == 'function'){return src.cloneNode(true);}
// Initialize the visited objects arrays if needed.// This is used to detect cyclic references.if (_visited === undefined){_visited = [];_copiesVisited = [];}
// Check if this object has already been visitedvar i, len = _visited.length;for (i = 0; i < len; i++) {// If so, get the copy we already madeif (src === _visited[i]) {return _copiesVisited[i];}}
//Arrayif (Object.prototype.toString.call(src) == '[object Array]') {//[].slice() by itself would soft clonevar ret = src.slice();
//add it to the visited array_visited.push(src);_copiesVisited.push(ret);
var i = ret.length;while (i--) {ret[i] = deepCopy(ret[i], _visited, _copiesVisited);}return ret;}
//If we've reached here, we have a regular object
//make sure the returned object has the same prototype as the originalvar proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);if (!proto) {proto = src.constructor.prototype; //this line would probably only be reached by very old browsers}var dest = object_create(proto);
//add this object to the visited array_visited.push(src);_copiesVisited.push(dest);
for (var key in src) {//Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.//For an example of how this could be modified to do so, see the singleMixin() functiondest[key] = deepCopy(src[key], _visited, _copiesVisited);}return dest;}
//If Object.create isn't already defined, we just do the simple shim,//without the second argument, since that's all we need herevar object_create = Object.create;if (typeof object_create !== 'function') {object_create = function(o) {function F() {}F.prototype = o;return new F();};}
/*** This is a quasi clone of jQuery's extend() function.* by Romain WEEGER for wJs library - www.wexample.com* @returns {*|{}}*/function extend() {// Make a copy of arguments to avoid JavaScript inspector hints.var to_add, name, copy_is_array, clone,
// The target object who receive parameters// form other objects.target = arguments[0] || {},
// Index of first argument to mix to target.i = 1,
// Mix target with all function arguments.length = arguments.length,
// Define if we merge object recursively.deep = false;
// Handle a deep copy situation.if (typeof target === 'boolean') {deep = target;
// Skip the boolean and the target.target = arguments[ i ] || {};
// Use next object as first added.i++;}
// Handle case when target is a string or something (possible in deep copy)if (typeof target !== 'object' && typeof target !== 'function') {target = {};}
// Loop trough arguments.for (false; i < length; i += 1) {
// Only deal with non-null/undefined valuesif ((to_add = arguments[ i ]) !== null) {
// Extend the base object.for (name in to_add) {
// We do not wrap for loop into hasOwnProperty,// to access to all values of object.// Prevent never-ending loop.if (target === to_add[name]) {continue;}
// Recurse if we're merging plain objects or arrays.if (deep && to_add[name] && (is_plain_object(to_add[name]) || (copy_is_array = Array.isArray(to_add[name])))) {if (copy_is_array) {copy_is_array = false;clone = target[name] && Array.isArray(target[name]) ? target[name] : [];}else {clone = target[name] && is_plain_object(target[name]) ? target[name] : {};}
// Never move original objects, clone them.target[name] = extend(deep, clone, to_add[name]);}
// Don't bring in undefined values.else if (to_add[name] !== undefined) {target[name] = to_add[name];}}}}return target;}
/*** Check to see if an object is a plain object* (created using "{}" or "new Object").* Forked from jQuery.* @param obj* @returns {boolean}*/function is_plain_object(obj) {// Not plain objects:// - Any object or value whose internal [[Class]] property is not "[object Object]"// - DOM nodes// - windowif (obj === null || typeof obj !== "object" || obj.nodeType || (obj !== null && obj === obj.window)) {return false;}// Support: Firefox <20// The try/catch suppresses exceptions thrown when attempting to access// the "constructor" property of certain host objects, i.e. |window.location|// https://bugzilla.mozilla.org/show_bug.cgi?id=814622try {if (obj.constructor && !this.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {return false;}}catch (e) {return false;}
// If the function hasn't returned already, we're confident that// |obj| is a plain object, created by {} or constructed with new Objectreturn true;}
var original = {a: 1};
// Method 1: New object with original assigned.var copy1 = Object.assign({}, original);
// Method 2: New object with spread operator assignment.var copy2 = {...original};
const clone = (o) =>typeof o === 'object' && o !== null ? // only clone objects(Array.isArray(o) ? // if cloning an arrayo.map(e => clone(e)) : // clone each of its elementsObject.keys(o).reduce( // otherwise reduce every key in the object(r, k) => (r[k] = clone(o[k]), r), {} // and save its cloned value into a new object)) :o; // return non-objects as is
var x = {nested: {name: 'test'}};
var y = clone(x);
console.log(x.nested !== y.nested);
function cloneDeep (o) {let newOlet i
if (typeof o !== 'object') return o
if (!o) return o
if (Object.prototype.toString.apply(o) === '[object Array]') {newO = []for (i = 0; i < o.length; i += 1) {newO[i] = cloneDeep(o[i])}return newO}
newO = {}for (i in o) {if (o.hasOwnProperty(i)) {newO[i] = cloneDeep(o[i])}}return newO}
let objectToCopy = someObj;let copyOfObject = {};Object.defineProperties(copyOfObject, Object.getOwnPropertyDescriptors(objectToCopy));// copyOfObject will now be the same as objectToCopy
function deepClone(obj) {/** Duplicates an object*/
var ret = null;if (obj !== Object(obj)) { // primitive typesreturn obj;}if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { // string objecsret = obj; // for ex: obj = new String("Spidergap")} else if (obj instanceof Date) { // dateret = new obj.constructor();} elseret = Object.create(obj.constructor.prototype);
var prop = null;var allProps = Object.getOwnPropertyNames(obj); //gets non enumerables also
var props = {};for (var i in allProps) {prop = allProps[i];props[prop] = false;}
for (i in obj) {props[i] = i;}
//now props contain both enums and non enumsvar propDescriptor = null;var newPropVal = null; // value of the property in new objectfor (i in props) {prop = obj[i];propDescriptor = Object.getOwnPropertyDescriptor(obj, i);
if (Array.isArray(prop)) { //not backward compatibleprop = prop.slice(); // to copy the array} elseif (prop instanceof Date == true) {prop = new prop.constructor();} elseif (prop instanceof Object == true) {if (prop instanceof Function == true) { // functionif (!Function.prototype.clone) {Function.prototype.clone = function() {var that = this;var temp = function tmp() {return that.apply(this, arguments);};for (var ky in this) {temp[ky] = this[ky];}return temp;}}prop = prop.clone();
} else // normal object{prop = deepClone(prop);}
}
newPropVal = {value: prop};if (propDescriptor) {/** If property descriptors are there, they must be copied*/newPropVal.enumerable = propDescriptor.enumerable;newPropVal.writable = propDescriptor.writable;
}if (!ret.hasOwnProperty(i)) // when String or other predefined objectsObject.defineProperty(ret, i, newPropVal); // non enumerable
}return ret;}
let deepCopy = (target, source) => {Object.assign(target, source);// check if there's any nested objectsObject.keys(source).forEach((prop) => {/*** assign function copies functions and* literals (int, strings, etc...)* except for objects and arrays, so:*/if (typeof(source[prop]) === 'object') {// check if the item is, in fact, an arrayif (Array.isArray(source[prop])) {// clear the copied referenece of nested arraytarget[prop] = Array();// iterate array's item and copy oversource[prop].forEach((item, index) => {// array's items could be objects too!if (typeof(item) === 'object') {// clear the copied referenece of nested objectstarget[prop][index] = Object();// and re do the process for nested objectsdeepCopy(target[prop][index], item);} else {target[prop].push(item);}});// otherwise, treat it as an object} else {// clear the copied referenece of nested objectstarget[prop] = Object();// and re do the process for nested objectsdeepCopy(target[prop], source[prop]);}}});};
obj={a:"lol",b:["yes","no","maybe"]}clonedObj = Object.assign({},obj);
clonedObj.b.push("skip")// changes will reflected to the actual obj as well because of its reference type.obj.b //will also console => yes,no,maybe,skip
所以对于深度克隆来说是不可能以这种方式实现的。
最好的解决办法是
var obj = Json.stringify(yourSourceObj)var cloned = Json.parse(obj);