I’ve been reading through Reselect’s (only 107 lines unminified) and thought it might be worth unpacking some of the concepts in a blog post. source code Concept 1: Memoization In computing, or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. ( ) memoization source Differently put, if you have a pure function that hogs resources while running (e.g. ), memoization is a shortcut so that if you run it over and over again without changing then the function only runs the first time. After that, it just keeps a copy of the result and spits it out whenever the same is provided so that you don’t have to waste resources calculating the same value over and over. doResourceHoggingThing doResourceHoggingThing(argument) argument argument Since Reselect runs within the React render cycle, it’s primary concern is not saving of previous function executions, but just the , so that the (possibly expensive) update cycle can be skipped if it’s going to spit out a consistent value. all results last result Simple memoization (storing the last result for a function with a single parameter) is easy to accomplish in Javascript using a closure. const memoizeFunc = func => {// these variables inside the closure keep track of// the previous data to do the comparisonlet lastArg = null;let lastResult = null; return function (newArg) {// if the arguments don't match// calculate the result and return itif (newArg !== lastArg) {console.log('new', lastResult)lastResult = func(newArg)} // otherwise just return the old result lastArg = newArg; console.log('cached', lastResult) return lastResult; }} const identity = x => x;const memedFunc = memoizeFunc(identity); memedFunc(4) // 'new', 4memedFunc(5) // 'new', 5memedFunc(5) // 'cached', 4 However, performing memoization for any number of parameters is a little more complicated. Refresher 1: Equality Checks by Reference The main decision that a memoized function needs to make is “did my arguments change since this last time I was called?”, so the first function in Reselect is a simple equality check which is used to determine the equality of arguments passed into the function: // Reselect Function #1function defaultEqualityCheck(a, b) {return a === b} What’s worth understanding here is that this works by comparing two values by instead of by value. Since a memoized function will frequently take Javascript objects (any such as or ) as arguments, and since equality checking objects is itself potentially resource intensive, Reselect skips a deep comparison of object values and uses their underlying reference as a proxy for equality. reference non-primitive data type {} [] This shortcut is safe, because while it’s relatively easy to get this check to return for two objects that are equal by value but different by reference, I can’t think of a scenario where two objects can share a reference while having differing values. false const opt0 = {value: 0};const opt1 = {value: 1};const opt2 = {value: 1};const opt3 = opt1; const arr = [opt0, opt1, opt2, opt3] // Both values and reference matchdefaultEqualityCheck(arr[0], arr[0]) // true // Neither value nor reference matchesdefaultEqualityCheck(arr[0], arr[1]) // false // value matches, but reference doesn'tdefaultEqualityCheck(arr[1], arr[2]) // false // reference matchesdefaultEqualityCheck(arr[1], arr[3]) // true This is the side to err on in a React app, because this edge case (should it occur) would result in a redundant render cycle and not in a failed update when the underlying data changes. Refresher 2: The Arguments Object The object is “ . You can refer to a function’s arguments within the function by using the object. This object contains an entry for each argument passed to the function, the first entry's index starting at 0.” ( ) arguments a local variable available within all (non-arrow) functions arguments source It’d be nice if we could just run the equality check on the two instances of directly, but they’ll never share the same underlying reference so this won’t work. We’ll have to dig deeper, which brings us to the next Reselect function. arguments // Reselect Function #2function areArgumentsShallowlyEqual(equalityCheck, prev, next) {if (prev === null ||next === null ||prev.length !== next.length) {return false} // Do this in a for loop (and not a `forEach` or an `every`)// so we can determine equality as fast as possible.const length = prev.lengthfor (let i = 0; i < length; i++) {if (!equalityCheck(prev[i], next[i])) {return false}} return true} This just iterates over the properties in the two objects and shallowly compares them using a passed-in equality check. Since the object is an array-like object, it has a built-in property which allows for some quick tests before the loop to speed things up. arguments arguments length Concept 3: The Memoization Function Now that all the building blocks are understood, the default memoization function used in reselect is just their combination. // Reselect Function #3export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {let lastArgs = nulllet lastResult = null// we reference arguments instead of spreading them for performance reasonsreturn function () {if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {// apply arguments instead of spreading for performance.lastResult = func.apply(null, arguments)} lastArgs = arguments return lastResult }} I’m not 100% sure on the granular details of the enhancement added by using , but it looks like Babel transpiles to this under the hood. func.apply func(...arguments) Conclusion That’s it. The basics of Reselect in three functions. There’s a bit more in the source code so maybe I’ll add a part 2 in the near future.