diff --git a/build.js b/build.js index 7962cc5be..fdb692ea9 100755 --- a/build.js +++ b/build.js @@ -71,6 +71,7 @@ 'bindAll': ['bind', 'functions'], 'bindKey': ['isFunction', 'isObject'], 'clone': ['assign', 'forEach', 'forOwn', 'isArray', 'isObject'], + 'cloneDeep': ['clone'], 'compact': [], 'compose': [], 'contains': ['indexOf', 'isString'], @@ -239,6 +240,7 @@ /** List of methods used by Underscore */ var underscoreMethods = _.without.apply(_, [allMethods].concat([ 'bindKey', + 'cloneDeep', 'forIn', 'forOwn', 'isPlainObject', diff --git a/build/pre-compile.js b/build/pre-compile.js index e02f303e2..67f96e276 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -69,6 +69,7 @@ 'bindAll', 'bindKey', 'clone', + 'cloneDeep', 'collect', 'compact', 'compose', diff --git a/lodash.js b/lodash.js index d3c829cd0..5523aba2d 100644 --- a/lodash.js +++ b/lodash.js @@ -256,8 +256,8 @@ * `unshift`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: - * `clone`, `contains`, `escape`, `every`, `find`, `has`, `identity`, `indexOf`, - * `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, + * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, `identity`, + * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, * `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`, * `mixin`, `noConflict`, `pop`, `random`, `reduce`, `reduceRight`, `result`, @@ -967,14 +967,8 @@ /*--------------------------------------------------------------------------*/ /** - * Creates a clone of `value`. If `deep` is `true`, all nested objects will - * also be cloned, otherwise they will be assigned by reference. Functions and - * DOM nodes are **not** cloned. The enumerable properties of `arguments` objects - * and objects created by constructors other than `Object` are cloned to plain - * `Object` objects. - * - * Note: Lo-Dash's deep clone functionality is loosely based on the structured clone algorithm. - * See http://www.w3.org/TR/html5/common-dom-interfaces.html#internal-structured-cloning-algorithm. + * Creates a clone of `value`. If `deep` is `true`, nested objects will also + * be cloned, otherwise they will be assigned by reference. * * @static * @memberOf _ @@ -995,9 +989,6 @@ * { 'name': 'curly', 'age': 60 } * ]; * - * _.clone({ 'name': 'moe' }); - * // => { 'name': 'moe' } - * * var shallow = _.clone(stooges); * shallow[0] === stooges[0]; * // => true @@ -1076,6 +1067,35 @@ return result; } + /** + * Creates a deep clone of `value`. Functions and DOM nodes are **not** cloned. + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. + * + * Note: Lo-Dash's deep clone functionality is loosely based on the structured clone algorithm. + * See http://www.w3.org/TR/html5/common-dom-interfaces.html#internal-structured-cloning-algorithm. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to deep clone. + * @returns {Mixed} Returns the deep cloned `value`. + * @example + * + * var stooges = [ + * { 'name': 'moe', 'age': 40 }, + * { 'name': 'larry', 'age': 50 }, + * { 'name': 'curly', 'age': 60 } + * ]; + * + * var deep = _.cloneDeep(stooges); + * deep[0] === stooges[0]; + * // => false + */ + function cloneDeep(value) { + return clone(value, true); + } + /** * Assigns own enumerable properties of source object(s) to the `destination` * object for all `destination` properties that resolve to `null`/`undefined`. @@ -3730,8 +3750,6 @@ /** * This function returns the first argument passed to it. * - * Note: This function is used throughout Lo-Dash as a default callback. - * * @static * @memberOf _ * @category Utilities @@ -4257,6 +4275,7 @@ // add functions that return unwrapped values when chaining lodash.clone = clone; + lodash.cloneDeep = cloneDeep; lodash.contains = contains; lodash.escape = escape; lodash.every = every; diff --git a/test/test-build.js b/test/test-build.js index 796cefa6b..31c716294 100644 --- a/test/test-build.js +++ b/test/test-build.js @@ -147,6 +147,7 @@ var objectsMethods = [ 'assign', 'clone', + 'cloneDeep', 'defaults', 'extend', 'forIn', @@ -248,6 +249,7 @@ /** List of methods used by Underscore */ var underscoreMethods = _.without.apply(_, [allMethods].concat([ 'bindKey', + 'cloneDeep', 'forIn', 'forOwn', 'isPlainObject', diff --git a/test/test.js b/test/test.js index 91a6058a8..e34fb7886 100644 --- a/test/test.js +++ b/test/test.js @@ -243,7 +243,7 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.clone'); + QUnit.module('cloning'); (function() { function Klass() { this.a = 1; } @@ -277,7 +277,7 @@ _.forOwn(objects, function(object, key) { test('should deep clone ' + key, function() { - var clone = _.clone(object, true); + var clone = _.cloneDeep(object); ok(_.isEqual(object, clone)); if (_.isObject(object)) { @@ -291,7 +291,7 @@ _.forOwn(nonCloneable, function(object, key) { test('should not clone ' + key, function() { strictEqual(_.clone(object), object); - strictEqual(_.clone(object, true), object); + strictEqual(_.cloneDeep(object), object); }); }); @@ -304,7 +304,7 @@ test('should deep clone `index` and `input` array properties', function() { var array = /x/.exec('x'), - actual = _.clone(array, true); + actual = _.cloneDeep(array); equal(actual.index, 0); equal(actual.input, 'x'); @@ -319,15 +319,15 @@ object.foo.b.foo.c = object; object.bar.b = object.foo.b; - var clone = _.clone(object, true); + var clone = _.cloneDeep(object); ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c && clone !== object); }); test('should clone problem JScript properties (test in IE < 9)', function() { deepEqual(_.clone(shadowed), shadowed); notEqual(_.clone(shadowed), shadowed); - deepEqual(_.clone(shadowed, true), shadowed); - notEqual(_.clone(shadowed, true), shadowed); + deepEqual(_.cloneDeep(shadowed), shadowed); + notEqual(_.cloneDeep(shadowed), shadowed); }); }(1, 2, 3));