Lodash valuesIn Execution Path for Prototype Values

This article traces the internal execution path Lodash traverses when resolving and mapping prototype property values using _.valuesIn. It details the step-by-step lifecycle from the public API call through key discovery, prototype-chain enumeration, and dynamic property access, showing precisely how inherited properties are gathered and returned.

The Entry Point: valuesIn

When _.valuesIn(object) is called, Lodash begins by validating the target argument. If the target is null or undefined, the method immediately returns an empty array. If the target is a valid object or primitive wrapper, valuesIn delegates to two internal routines: baseValues and keysIn:

function valuesIn(object) {
  return object == null ? [] : baseValues(object, keysIn(object));
}

The execution path splits into two distinct phases: discovering all enumerable property identifiers (both own and inherited) via keysIn, and dynamically projecting those identifiers to their respective values via baseValues.

Enumeration Path: keysIn and baseKeysIn

To access inherited prototype properties, Lodash must inspect the prototype chain. The keysIn utility invokes baseKeysIn(object), which implements the traversal logic:

  1. Object Type Validation: Lodash verifies that the argument is an object using isObject(object). Primitives are converted to objects using Object(object) to permit safe prototype inspection.
  2. Prototype Edge Case Check: Lodash determines whether the input itself is a prototype object via isPrototype(object). If it is, the runtime skips standard constructor keys to prevent accidental pollution or circular references.
  3. Dynamic Chain Traversal: baseKeysIn executes a JavaScript for...in statement:
    for (const key in object) {
      result.push(key);
    }

Because the ECMAScript specification dictates that for...in walks the target's entire [[Prototype]] chain, this loop dynamically captures all enumerable keys residing on upstream prototypes up to, but not including, Object.prototype.

Dynamic Mapping: baseValues

Once baseKeysIn returns the accumulated array of own and prototype keys, execution transfers to baseValues:

function baseValues(object, props) {
  return arrayMap(props, (key) => object[key]);
}

Inside baseValues, Lodash passes the discovered keys to arrayMap. For every key in the props array, dynamic property access (object[key]) is triggered.

When JavaScript evaluates object[key], the engine first looks for an own property on object. If the property does not exist directly on the instance, the V8/JavaScript engine walks the internal [[Prototype]] link dynamically until it resolves the value on the ancestor prototype where it was defined.

Isolating Strictly Prototype Values

Because _.valuesIn aggregates both own properties and prototype properties into a single output, strictly prototype values are those associated with keys where Object.prototype.hasOwnProperty.call(object, key) evaluates to false.

In Lodash's full execution path:

  1. keysIn dynamically harvests own and prototype keys via baseKeysIn using for...in.
  2. Inherited keys resolve strictly up the prototype chain.
  3. baseValues iterates the combined keys, querying the instance.
  4. The JavaScript runtime’s internal [[Get]] operation executes for each key, dynamically retrieving the corresponding value from the prototype.