Upgrading Lodash from 3.x to 4.x

There are many breaking changes from version 3.x to 4.x; all changes are detailed in the Lodash changelog. There is also a list of deprecated functions, with a regex you can use to detect usages in your code.

However, since it is not an exhaustive list, I will list the changes I encountered when performing my own migration, to help anyone undergoing the same process.

Direct renames

This section includes functions in which only the name changed, i.e. the arguments and return value are the same.

3.x 4.x
contains includes
first head
rest tail
invoke invokeMap
padLeft padStart
padRight padEnd

Direct renames if not using thisArg

This section includes functions in which the only change is dropping "thisArg". If you are not using it, you can just rename. If you are using thisArg in 3.x, it can be dropped if you are using iteratee to access the collection elements. If you want to bind some other object, you can use bind.

3.x 4.x
any some
indexBy keyBy
all every

Different arguments

3.x 4.x Changes
extend assignIn If you were using the customizer argument, use _.map beforehand to perform the conversion. If you were using thisArg, drop it, or use bind
pluck map Plucking can be done with _.map, by passing a single property name as a string as the 2nd argument (property shorthand), or an array of strings to pluck more than one.
sum sumBy If you are just adding numbers in an array, it's okay to leave sum as it is. However, if you are adding properties in objects, you need to use sumBy instead (you can use the property shorthand instead of a function; see the examples in the docs).
omit omit Change the second argument to an array of string instead of a single string, if using the property shorthand (like pluck).
uniq uniqBy Same change as sum and sumBy (property shorthand is valid, try it in REPL in the 4.x docs).
pick pick In the new version, the 2nd argument cannot be a predicate function, just a string array with property names to pick.
min minBy Same change as sum and sumBy.
max maxBy Same change as sum and sumBy.

Special case: _.zipObject

This function is tricky, because it is apparently the same; however, the way arguments are interpreted has changed. In 3.x, the first argument can be an array in which each element is a 2-item array representing a key-value pair. However, in 4.x, the first argument is an array with the keys, and the second argument is an array with the values. So if you see _.zipObject receiving a single argument, you're in trouble. Since converting arguments to the new convention in each call is a hassle, and quite error prone, I implemented my own zipObject function:

/**
 * Converts [[key0, value0], [key1, value1], ..., [keyN, valueN]]
 * to {key0: value0, key1: value1, ..., keyN: valueN}
 * @param keyValuePairs Array of key-value pairs, where each element is an array of
 *                      two elements [keyi, valuei]
 * @returns An object whose properties are keyi: valuei
 */
Utils.zipObject = function(keyValuePairs) {
  var zippedObject = {};
  for(var i=0; i<keyValuePairs.length; i++) {
    if(keyValuePairs[i] && keyValuePairs[i].length === 2) {
      zippedObject[keyValuePairs[i][0]] = keyValuePairs[i][1];
    }
  };
  return zippedObject;
}

Conclusion

As in most cases involving breaking changes, it is very helpful to have a test harness to detect as many errors introduced by the changes as possible. In my particular case, I had Mocha + Chai + Sinon tests in place. To debug them when they broke, VS Code was very helpful. So, if you don't have a test harness in place, I would recommend implementing one which covers all Lodash usages before tackling this migration.

About Lodash usage today, some people advocate removing the dependency, since lots of Lodash functions have been made obsolete by recent additions to the ECMA standard, or Modern JS as some call it. It is certainly a point to consider, specially if you are not using complex, specific Lodash functions which are not yet in the standard. Because each Lodash function is available as a separate npm package, you can replace as many usages as possible with Modern JS, and keep the rest as separate packages, avoiding referencing all of Lodash and thus reducing your app's footprint.

Comments

Popular posts from this blog

VB.NET: Raise base class events from a derived class

C++/CLI: Convert a String to BSTR or some other nasty stuff