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"
constbind_pushing_to = bindMethodFactory(Array.prototype.push) // equivalent to `bindMethodFactoryByName(Array.prototype, "push")` constbind_seek_to = bindMethodFactory(Array.prototype.at, -1) // equivalent to `bindMethodFactoryByName(Array.prototype, "at", -1)` constbind_splicing_to = bindMethodFactoryByName(Array.prototype, "splice") // equivalent to `bindMethodFactory(Array.prototype.splice)` constbind_clear_to = bindMethodFactoryByName(Array.prototype, "splice", 0) // equivalent to `bindMethodFactory(Array.prototype.splice, 0)`
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:
// 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 leti = 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)
// 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.
// 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 constpush3 = arr.push.bind(arr) // equivalent to `Array.prototype.push.bind(arr)` constpop3 = 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" constpush4 = bind_array_push(arr) constpop4 = 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!
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:
you may have some amateur level questions about why? would anyone want to do that. here is why:
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:next, you may be wondering why not destructure the method or assign it to a variable?
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!