Skip to content

Instantly share code, notes, and snippets.

@a-c-t-i-n-i-u-m
Last active February 24, 2016 12:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-c-t-i-n-i-u-m/35ec4060fe589908af59 to your computer and use it in GitHub Desktop.
Save a-c-t-i-n-i-u-m/35ec4060fe589908af59 to your computer and use it in GitHub Desktop.
js cloning objects
// obj clone
var clone = function(o) {
switch (Object.prototype.toString.call(o)) {
// if primitive types
case '[object Undefined]':
case '[object Null]':
case '[object Boolean]':
case '[object Number]':
case '[object String]':
case '[object Symbol]':
return o;
// obj cloning by constructor
case '[object Error]':
case '[object RegExp]':
case '[object Map]':
case '[object Set]':
// --(not tested)--
case '[object WeakMap]':
case '[object WeakSet]':
case '[object Int8Array]':
case '[object Uint8Array]':
case '[object Uint8ClampedArray]':
case '[object Int16Array]':
case '[object Uint16Array]':
case '[object Int32Array]':
case '[object Uint32Array]':
case '[object Float32Array]':
case '[object Float64Array]':
case '[object DataView]':
var a = new (o.constructor)(o);
break;
// fn; inheritance/extends
case '[object Function]':
var a = function() {
return o.apply(this, arguments);
};
//a.prototype = Object.create(o.prototype);
var tmp = function () {};
tmp.prototype = o.prototype;
a.prototype = new tmp();
a.prototype.constructor = a;
//a.prototype.__baseconstructor = o; // if needed
break;
// objects
default:
var a = new((o).constructor)();
break;
}
// clone properties
for (var k in o) {
if (o.hasOwnProperty(k)) {
a[k] = clone(o[k]);
}
}
return a;
};
/*
* test
*/
// test primitives
console.assert(undefined === clone(undefined), 'Error in cloning primitive object: %s', undefined);
console.assert(null === clone(null), 'Error in cloning primitive object: %s', null);
console.assert(true === clone(true), 'Error in cloning primitive objects: %s', true);
console.assert(false === clone(false), 'Error in cloning primitive object: %s', false);
var n = [
0, -1, 1,
Infinity, -Infinity,
Number.POSITIVE_INFITINY, Number.NEGATIVE_INFINITY,
0.00001, 10E8, 0xff,
Math.E, Math.PI,
Number.MAX_VALUE, Number.MIN_VALUE,
];
for (var i = 0; i < n.length; i++) {
console.assert(n[i] === clone(n[i]), 'Error in cloning primitive object: %s', n[i]);
}
console.assert(isNaN(clone(NaN)), 'Error in cloning NaN');
var s = Symbol('test');
console.assert(s === clone(s), 'Error in cloning Symbol');
// test function
var fn = function (a, b) {
return a + b;
};
var cfn = clone(fn);
console.assert(fn !== cfn && fn(1, 2) === cfn(1, 2), 'Error in cloning Function');
var myClass = function (name) {
this.name = name;
};
myClass.prototype.displayName = function () {
return this.name;
};
var cClass = clone(myClass);
cClass.prototype.displayName = function () {
return this.name + '...cloned';
};
cClass.prototype.printName = function () {
console.log(this.name);
};
var mInstance = new myClass('test');
var cInstance = new cClass('test');
console.assert(typeof myClass.prototype.printName === 'undefined', 'Error in separate prototype');
console.assert(myClass.prototype !== cClass.prototype, 'Error in separate prototype');
console.assert(cInstance.displayName() === 'test...cloned', 'Error in overriding method');
console.assert(cInstance instanceof myClass, 'Error in inheritance');
// objects
// array
var arr = [1, 2, 3, 4, 5];
var cArr = clone(arr);
cArr[100] = 100;
console.assert(cArr instanceof Array, 'Error in cloning array prototype');
console.assert(arr !== cArr, 'Error in cloning array');
console.assert(typeof arr[100] === 'undefined', 'Error in cloning array');
// date
var d = new Date(),
cd = clone(d);
d.setSeconds(30);
cd.setSeconds(0);
console.assert(d !== cd, 'Error in cloning date');
console.assert(cd instanceof Date, 'Error in cloning date prototype');
console.assert(d.getSeconds() === 30 && d.getHours() === cd.getHours(), 'Error in cloning date');
// regexp
var r = /test/g,
cr = clone(r);
console.assert(r !== cr, 'Error in cloning regexp');
console.assert(cr instanceof RegExp, 'Error in cloning regexp prototype');
console.assert('test test'.replace(r, 'a') === 'test test'.replace(cr, 'a'), 'Error in cloning regexp content');
// arraybuffer
var ab = new ArrayBuffer(3);
ab[0] = 'a';
ab[1] = 't';
ab[2] = 'x';
var cab = clone(ab);
cab[0] = 'i';
console.assert(ab !== cab, 'Error in cloning ArrayBuffer');
console.assert(cab instanceof ArrayBuffer, 'Error in cloning ArrayBuffer prototype');
console.assert(ab[0] === 'a', 'Error in cloning ArrayBuffer');
// map
var m = new Map();
m.set('a', 'test a');
m.set('b', 'test b');
var cm = clone(m);
cm.set('a', 'cloned a');
console.assert(cm !== m, 'Error in cloning map');
console.assert(cm instanceof Map, 'Error in cloning map prototype');
console.assert(m.get('a') === 'test a' && cm.get('b') === 'test b', 'Error in cloning map');
// set
var s = new Set();
s.add('test a');
s.add('test b');
var cs = clone(s);
cs.add('test c');
console.assert(cs !== s, 'Error in cloning set');
console.assert(cs instanceof Set, 'Error in cloning set prototype');
console.assert(s.has('test c') === false && cs.has('test b'), 'Error in cloning set');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment