@oazmi/kitchensink - v0.9.13
    Preparing search index...

    Function prototypeChainOfObject

    • get the prototype chain of an object, with optional slicing options.

      Parameters

      • obj: any

        the object whose prototype chain is to be found.

      • config: PrototypeChainOfObjectConfig = {}

        optional configuration for slicing the full prototype chain.

      Returns object[]

      the sliced prototype chain of the given object.

      import { assertEquals, assertThrows } from "jsr:@std/assert"

      // aliasing our functions for brevity
      const
      fn = prototypeChainOfObject,
      eq = assertEquals

      class A extends Array { }
      class B extends A { }
      class C extends B { }
      class D extends C { }

      const
      a = new A(0),
      b = new B(0),
      c = new C(0),
      d = new D(0)

      eq(fn(d), [D.prototype, C.prototype, B.prototype, A.prototype, Array.prototype, Object.prototype, null])
      eq(fn(b), [B.prototype, A.prototype, Array.prototype, Object.prototype, null])

      // slicing the prototype chain, starting from index 2 till the end
      eq(fn(d, { start: 2 }), [B.prototype, A.prototype, Array.prototype, Object.prototype, null])

      // slicing using a negative index
      eq(fn(d, { start: -2 }), [Object.prototype, null])

      // slicing using an object
      eq(fn(d, { start: B.prototype }), [B.prototype, A.prototype, Array.prototype, Object.prototype, null])

      // when the slicing object is not found, the start index will be assumed to be `0` (default value)
      eq(fn(d, { start: Set.prototype }), [D.prototype, C.prototype, B.prototype, A.prototype, Array.prototype, Object.prototype, null])

      // slicing between the `start` index (inclusive) and the end index
      eq(fn(d, { start: 2, end: 6 }), [B.prototype, A.prototype, Array.prototype, Object.prototype])
      eq(fn(d, { start: 2, end: -1 }), [B.prototype, A.prototype, Array.prototype, Object.prototype])
      eq(fn(d, { start: 2, end: null }), [B.prototype, A.prototype, Array.prototype, Object.prototype])

      // if the end index is not found, the slicing will occur till the end
      eq(fn(d, { end: Set.prototype}), [D.prototype, C.prototype, B.prototype, A.prototype, Array.prototype, Object.prototype, null])

      // slicing using a `delta` argument will let you define how many elements you wish to:
      // - traverse forward from the `start` index
      // - traverse backwards from the `end` index
      eq(fn(d, { start: 2, delta: 3 }), [B.prototype, A.prototype, Array.prototype])
      eq(fn(d, { end: -2, delta: 2 }), [A.prototype, Array.prototype])
      eq(fn(d, { end: null, delta: 4 }), [B.prototype, A.prototype, Array.prototype, Object.prototype])

      eq(fn(d, { start: 1, delta: 1 }), fn(c, { start: 0, delta: 1 }))
      eq(fn(c, { start: 1, delta: 1 }), fn(b, { start: 0, delta: 1 }))
      eq(fn(b, { start: 1, delta: 1 }), fn(a, { start: 0, delta: 1 }))
      eq(fn(a, { start: 1, delta: 1 }), fn([], { start: 0, delta: 1 }))
      eq(fn([], { start: 1, delta: 1 }), fn({}, { start: 0, delta: 1 }))

      // you may also traverse through the inheritance chain of a class, but it will be a good idea to set your `end` point to `Function.prototype`,
      // since all class objects are effectively functions (i.e. their common ancestral prototype if `Function.prototype`).
      eq(fn(D, { start: 0, end: Function.prototype }), [C, B, A, Array])
      eq(fn(D), [C, B, A, Array, Function.prototype, Object.prototype, null])
      eq(fn(class {}), [Function.prototype, Object.prototype, null])
      eq(fn(class extends Object {}), [Object, Function.prototype, Object.prototype, null])
      eq(fn(class extends Map {}), [Map, Function.prototype, Object.prototype, null])

      // you cannot acquire the prototype chain of the `null` object
      assertThrows(() => { fn(null) })