Skip to content

Instantly share code, notes, and snippets.

@stevenschobert
Last active August 29, 2015 14:12
Show Gist options
  • Save stevenschobert/76100e9f8519ad138742 to your computer and use it in GitHub Desktop.
Save stevenschobert/76100e9f8519ad138742 to your computer and use it in GitHub Desktop.
Object Cloning (with deep support) - modeled after Lodash's _.clone implementation. Supports strings, numbers, booleans, dates, regexps, objects, and arrays.
function clone(value, deep) {
var boo = '[object Boolean]';
var num = '[object Number]';
var str = '[object String]';
var obj = '[object Object]';
var arr = '[object Array]';
var date = '[object Date]';
var reg = '[object RegExp]';
var cloned;
var klass;
if (typeof value != 'object') {
return value;
}
klass = Object.prototype.toString.call(value);
switch (klass) {
case reg:
cloned = new value.constructor(value.source, /\w*$/.exec(value));
cloned.lastIndex = value.lastIndex;
break;
case boo:
case date:
cloned = new value.constructor(+value);
break;
case num:
case str:
cloned = new value.constructor(value);
break;
case arr:
cloned = new value.constructor();
for(var i=0; i < value.length; i++) {
if (deep) {
cloned.push(clone(value[i], deep));
} else {
cloned.push(value[i]);
}
}
break;
case obj:
cloned = new value.constructor();
for (var key in value) {
if (value.hasOwnProperty(key)) {
if (deep) {
cloned[key] = clone(value[key], deep);
} else {
cloned[key] = value[key];
}
}
}
break;
default:
cloned = value;
break;
}
return cloned;
}
describe('#clone', function() {
it('should return values for booleans', function() {
assert.equal(clone(true), true);
assert.equal(typeof clone(true), 'boolean');
});
it('should return values for numbers', function() {
assert.equal(clone(2), 2);
assert.equal(typeof clone(2), 'number');
});
it('should return values for strings', function() {
assert.equal(clone('test'), 'test');
assert.equal(typeof clone('test'), 'string');
});
it('should copy boolean objects', function() {
/* jshint -W053 */
var bool = new Boolean(true);
assert.notEqual(bool, clone(bool));
assert.equal(bool.valueOf(), clone(bool).valueOf());
});
it('should copy string objects', function() {
/* jshint -W053 */
var testStr = new String('test');
assert.notEqual(testStr, clone(testStr));
assert.equal(testStr.valueOf(), clone(testStr).valueOf());
});
it('should copy number objects', function() {
/* jshint -W053 */
var testNum = new Number(2);
assert.notEqual(testNum, clone(testNum));
assert.equal(testNum.valueOf(), clone(testNum).valueOf());
});
it('should copy regexp objects', function() {
var testRegex = new RegExp('hello.*', 'i');
var cloned = clone(testRegex);
assert.notEqual(testRegex, cloned);
assert.equal(testRegex.toString(), cloned.toString());
});
it('should copy date objects', function() {
var testDate = new Date();
var cloned = clone(testDate);
assert.notEqual(testDate, cloned);
assert.equal(testDate.toString(), cloned.toString());
});
it('should copy custom objects', function() {
function Droid(model) { this.model = model; }
var c3po = new Droid('protocol');
var cloned = clone(c3po);
assert.notEqual(cloned, c3po);
assert.deepEqual(cloned, c3po);
assert(cloned instanceof Droid);
});
it('should copy object keys', function() {
var testObj = { one: 1, two: 'two' };
assert.notEqual(clone(testObj), testObj);
assert.deepEqual(clone(testObj), testObj);
});
it('should copy objects with deep copying', function() {
var testObj1 = { test: 'test' };
var testObj2 = { one: testObj1 };
var cloned = clone(testObj2, true);
assert.notEqual(cloned.one, testObj1);
assert.deepEqual(cloned.one, testObj1);
});
it('should copy array values', function() {
var testArr = [ 'one', 2 ];
assert.notEqual(clone(testArr), testArr);
assert.deepEqual(clone(testArr), testArr);
});
it('should copy array values with deep copying', function() {
var testObj1 = { test: 'test' };
var testArr = [ testObj1, 2 ];
var cloned = clone(testArr, true);
assert.notEqual(cloned[0], testObj1);
assert.deepEqual(cloned[0], testObj1);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment