Last active
February 24, 2016 12:34
-
-
Save a-c-t-i-n-i-u-m/35ec4060fe589908af59 to your computer and use it in GitHub Desktop.
js cloning objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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