From 9b920cf813365d0bbc37ffd757ec93832898d3ae Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 8 May 2014 23:42:40 -0700 Subject: [PATCH] Add `baseFunctions` to ensure `_.mixin` only iterates over own keys of `source` objects. --- lodash.js | 44 +++++++++++++++++++++++++++++++------------- test/test.js | 33 ++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/lodash.js b/lodash.js index b193655d4..3c3d9a1ee 100644 --- a/lodash.js +++ b/lodash.js @@ -1599,6 +1599,30 @@ return baseForRight(object, callback, keys); } + /** + * The base implementation of `_.functions` which creates a sorted array of + * function property names from those returned by `keysFunc`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Array} Returns the new sorted array of property names. + */ + function baseFunctions(object, keysFunc) { + var index = -1, + props = keysFunc(object), + length = props.length, + result = []; + + while (++index < length) { + var key = props[index]; + if (isFunction(object[key])) { + result.push(key); + } + } + return result.sort(); + } + /** * The base implementation of `_.isEqual`, without support for `thisArg` * binding, that allows partial "_.where" style comparisons. @@ -6000,7 +6024,7 @@ } /** - * Creates a sorted array of property names of all enumerable function + * Creates a sorted array of function property names from all enumerable * properties, own and inherited, of `object`. * * @static @@ -6015,14 +6039,7 @@ * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] */ function functions(object) { - var result = []; - - baseForIn(object, function(value, key) { - if (isFunction(value)) { - result.push(key); - } - }); - return result.sort(); + return baseFunctions(object, keysIn); } /** @@ -7922,8 +7939,9 @@ } /** - * Adds function properties of a source object to the destination object. - * If `object` is a function methods will be added to its prototype as well. + * Adds all own enumerable function properties of a source object to the + * destination object. If `object` is a function methods will be added to + * its prototype as well. * * @static * @memberOf _ @@ -7955,7 +7973,7 @@ */ function mixin(object, source, options) { var chain = true, - methodNames = source && functions(source); + methodNames = source && baseFunctions(source, keys); if (!source || (!options && !methodNames.length)) { if (options == null) { @@ -7963,7 +7981,7 @@ } source = object; object = this; - methodNames = functions(source); + methodNames = baseFunctions(source, keys); } if (options === false) { chain = false; diff --git a/test/test.js b/test/test.js index dd48716db..6e2d2de1a 100644 --- a/test/test.js +++ b/test/test.js @@ -6383,6 +6383,22 @@ var value = ['a'], source = { 'a': function(array) { return array[0]; }, 'b': 'B' }; + test('should mixin `source` methods into lodash', 4, function() { + _.mixin(source); + + strictEqual(_.a(value), 'a'); + strictEqual(_(value).a().__wrapped__, 'a'); + + delete _.a; + delete _.prototype.a; + + ok(!('b' in _)); + ok(!('b' in _.prototype)); + + delete _.b; + delete _.prototype.b; + }); + test('should use `this` as the default `object` value', 3, function() { var object = _.create(_); object.mixin(source); @@ -6425,20 +6441,11 @@ delete wrapper.prototype.b; }); - test('should mixin `source` methods into lodash', 4, function() { - _.mixin(source); + test('should not assign inherited `source` properties', 1, function() { + function Foo() {} + Foo.prototype = { 'a': _.noop }; - strictEqual(_.a(value), 'a'); - strictEqual(_(value).a().__wrapped__, 'a'); - - delete _.a; - delete _.prototype.a; - - ok(!('b' in _)); - ok(!('b' in _.prototype)); - - delete _.b; - delete _.prototype.b; + deepEqual(_.mixin({}, new Foo, {}), {}); }); test('should accept an `options` argument', 16, function() {