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

    Module binder

    utility functions for creating other general purpose functions that can bind their passed function's functionality to some specific object.

    those are certainly a lot of words thrown in the air with no clarity as to what am I even saying. just as they say, a code block example is worth a thousand assembly instructions. here's the gist of it:

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

    const bind_pushing_to = bindMethodFactory(Array.prototype.push) // equivalent to `bindMethodFactoryByName(Array.prototype, "push")`
    const bind_seek_to = bindMethodFactory(Array.prototype.at, -1) // equivalent to `bindMethodFactoryByName(Array.prototype, "at", -1)`
    const bind_splicing_to = bindMethodFactoryByName(Array.prototype, "splice") // equivalent to `bindMethodFactory(Array.prototype.splice)`
    const bind_clear_to = bindMethodFactoryByName(Array.prototype, "splice", 0) // equivalent to `bindMethodFactory(Array.prototype.splice, 0)`

    const my_array = [1, 2, 3, 4, 5, 6]
    const push_my_array = bind_pushing_to(my_array)
    const seek_my_array = bind_seek_to(my_array)
    const splice_my_array = bind_splicing_to(my_array)
    const clear_my_array = bind_clear_to(my_array) as (deleteCount?: number, ...items: number[]) => number[]

    push_my_array(7, 8, 9)
    assertEquals(my_array, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    assertEquals(seek_my_array(), 9)
    splice_my_array(4, 3)
    assertEquals(my_array, [1, 2, 3, 4, 8, 9])
    clear_my_array()
    assertEquals(my_array, [])

    you may have some amateur level questions about why? would anyone want to do that. here is why:

    • calling a method via property access is slower. so when you call an array arr's push or pop methods a million times, having a bound function for that specific purpose will be quicker by about x1.3 times:
    import { assertLess } from "jsr:@std/assert"
    import { timeIt } from "./timeman.ts"

    // WARNING: JIT is pretty smart, and the test consistiently fails for `i` and `j` > `10_000_000`,
    // this is despite my efforts to make it difficult for the JIT to optimize the slow method, by computing some modulo and only popping when it is zero.
    // thus to be safe, I tuned `i` and `j` down to `100_000` iterations

    let i = 100_000, j = 100_000, sum1 = 0, sum2 = 0
    const
    arr1 = Array(777).fill(0).map(Math.random),
    arr2 = Array(777).fill(0).map(Math.random)

    // slower way:
    const t1 = timeIt(() => {
    while(i--) {
    const new_length = arr1.push(Math.random())
    sum1 += ((new_length + i) % 3 === 0 ? arr1.pop()! : arr1.at(-1)!)
    }
    })

    // faster way (allegedly):
    const
    push_arr2 = Array.prototype.push.bind(arr2),
    pop_arr2 = Array.prototype.pop.bind(arr2),
    seek_arr2 = Array.prototype.at.bind(arr2, -1)
    const t2 = timeIt(() => {
    while(j--) {
    const new_length = push_arr2(Math.random())
    sum2 += ((new_length + i) % 3 === 0 ? pop_arr2()! : seek_arr2()!)
    }
    })

    // assertLess(t2, t1) // TODO: RIP, performance gains have diminished in deno. curse you V8 JIT.
    // I still do think that in non-micro-benchmarks and real life applications (where there are a variety of objects and structures),
    // there still is a bit of performance gain. and lets not forget the benefit of minifiability.

    next, you may be wondering why not destructure the method or assign it to a variable?

    • this cannot be generally done for prototype-bound methods, because it needs the context of who is the caller (and therefor the this of interest). all builtin javascript class methods are prototype-bound. meaning that for every instance of a builtin class no new functions are specifically created for that instance, and instead, the instance holds a reference to the class's prototype object's method, but applies itself as the this when called.
    import { assertEquals, assertThrows } from "jsr:@std/assert"

    const arr = [1, 2, 3, 4, 5, 6]

    // prototype-bound methods need to be called via property access, otherwise they will loose their `this` context when uncoupled from their parent object
    const { push, pop } = arr
    assertThrows(() => push(7, 8, 9)) // `TypeError: Cannot convert undefined or null to object`
    assertThrows(() => pop()) // `TypeError: Cannot convert undefined or null to object`

    const
    push2 = arr.push,
    pop2 = arr.pop
    assertThrows(() => push2(7, 8, 9)) // `TypeError: Cannot convert undefined or null to object`
    assertThrows(() => pop2()) // `TypeError: Cannot convert undefined or null to object`

    // but you can do the binding yourself too to make it work
    const push3 = arr.push.bind(arr) // equivalent to `Array.prototype.push.bind(arr)`
    const pop3 = arr.pop.bind(arr) // equivalent to `Array.prototype.pop.bind(arr)`
    push3(7, 8, 9) // will work
    pop3() // will work

    // or use this submodule to do the same thing:
    // import { bind_array_pop, bind_array_push } from "@oazmi/kitchensink/binder"
    const push4 = bind_array_push(arr)
    const pop4 = bind_array_pop(arr)
    push4(7, 8, 9) // will work
    pop4() // will work
    • finally, property accesses are not easily minifiable (although they do get compressed when gzipped). however, if you bind your method calls to a variable, then it will become minifiable, which is somewhat the primary motivation for this submodule.

    with full automatic typing, you won't be compensating in any way. on the side note, it was figuring out the automatic typing that took me almost 16 hours just to write 3 lines of equivalent javascript code for the main 2 factory functions of this submodule. curse you typescript!

    Type Aliases

    BindableFunction

    Variables

    bind_array_at
    bind_array_concat
    bind_array_copyWithin
    bind_array_entries
    bind_array_every
    bind_array_fill
    bind_array_filter
    bind_array_find
    bind_array_findIndex
    bind_array_findLast
    bind_array_findLastIndex
    bind_array_flat
    bind_array_flatMap
    bind_array_forEach
    bind_array_includes
    bind_array_indexOf
    bind_array_join
    bind_array_keys
    bind_array_lastIndexOf
    bind_array_map
    bind_array_pop
    bind_array_push
    bind_array_reduce
    bind_array_reduceRight
    bind_array_reverse
    bind_array_shift
    bind_array_slice
    bind_array_some
    bind_array_sort
    bind_array_splice
    bind_array_unshift
    bind_array_toLocaleString
    bind_array_toReversed
    bind_array_toSorted
    bind_array_toSpliced
    bind_array_toString
    bind_array_values
    bind_array_with
    bind_array_clear
    bind_stack_seek
    bind_set_add
    bind_set_clear
    bind_set_delete
    bind_set_entries
    bind_set_forEach
    bind_set_has
    bind_set_keys
    bind_set_values
    bind_map_clear
    bind_map_delete
    bind_map_entries
    bind_map_forEach
    bind_map_get
    bind_map_has
    bind_map_keys
    bind_map_set
    bind_map_values
    bind_string_at
    bind_string_charAt
    bind_string_charCodeAt
    bind_string_codePointAt
    bind_string_startsWith
    bind_string_endsWith

    Functions

    bindMethodFactory
    bindMethodFactoryByName
    bindMethodToSelf
    bindMethodToSelfByName