const object = { // プリミティブ型 a: 1, b: 'a', c: '', d: null, e: undefined, f: true, // 参照型 g: [1, 2, 3], h: function () { console.log('h'); }, i: { a: 1, b: 'a', c: '', d: null, e: undefined, f: true, g: [1, 2, 3], h: function () { console.log('h'); }, i: { a: 1 } } }; // lodash // const obj = _.cloneDeep(object); // jQuery // const obj = $.extend({}, object); // Deep copy? (undefinedやfunctionが消えてしまう) // const obj = JSON.parse(JSON.stringify(object)); // 勘違い(ES6) → シャローコピー // const obj = Object.assign({}, object); function deepClone(object) { let node; if (object === null) { node = object; } else if (Array.isArray(object)) { node = object.slice(0) || []; node.forEach(n => { if (typeof n === 'object' && n !== {} || Array.isArray(n)) { n = deepClone(n); } }); } else if (typeof object === 'object') { node = Object.assign({}, object); Object.keys(node).forEach(key => { if (typeof node[key] === 'object' && node[key] !== {}) { node[key] = deepClone(node[key]); } }); } else { node = object; } return node; } const cloned = deepClone(object); // Modify object.a = 2; object.b = 'b'; object.c = '_'; object.d = 'null'; object.e = 'undefined'; object.f = false; object.g = [3, 2, 1]; object.h = function () { console.log('cloned'); } object.i.a = 2; object.i.b = 'b'; object.i.c = '_'; object.i.d = 'null'; object.i.e = 'undefined'; object.i.f = false; object.i.g = [3, 2, 1]; object.i.h = function () { console.log('cloned'); } object.i.i.a = 2; // Check console.log(object.a === cloned.a, 'object.a:', object.a, 'cloned.a:', cloned.a); console.log(object.b === cloned.b, 'object.b:', object.b, 'cloned.b:', cloned.b); console.log(object.c === cloned.c, 'object.c:', object.c, 'cloned.c:', cloned.c); console.log(object.d === cloned.d, 'object.d:', object.d, 'cloned.d:', cloned.d); console.log(object.e === cloned.e, 'object.e:', object.e, 'cloned.e:', cloned.e); console.log(object.f === cloned.f, 'object.f:', object.f, 'cloned.f:', cloned.f); console.log(object.g === cloned.g, 'object.g:', ...object.g, 'cloned.g:', ...cloned.g); console.log(object.h === cloned.h, 'object.h:', object.h, 'cloned.h:', cloned.h); console.log(object.i.a === cloned.i.a, 'object.i.a:', object.i.a, 'cloned.i.a:', cloned.i.a); console.log(object.i.b === cloned.i.b, 'object.i.b:', object.i.b, 'cloned.i.b:', cloned.i.b); console.log(object.i.c === cloned.i.c, 'object.i.c:', object.i.c, 'cloned.i.c:', cloned.i.c); console.log(object.i.d === cloned.i.d, 'object.i.d:', object.i.d, 'cloned.i.d:', cloned.i.d); console.log(object.i.e === cloned.i.e, 'object.i.e:', object.i.e, 'cloned.i.e:', cloned.i.e); console.log(object.i.f === cloned.i.f, 'object.i.f:', object.i.f, 'cloned.i.f:', cloned.i.f); console.log(object.i.g === cloned.i.g, 'object.i.g:', ...object.i.g, 'cloned.i.g:', ...cloned.i.g); console.log(object.i.h === cloned.i.h, 'object.i.h:', object.i.h, 'cloned.i.h:', cloned.i.h); console.log(object.i.i.a === cloned.i.i.a, 'object.i.i.a:', object.i.i.a, 'cloned.i.i.a:', cloned.i.i.a);