npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

custom-function

v2.0.0

Published

Literally the only sane way, if not the fastest one, to extend the Function class without evaluation

Downloads

3,303

Readme

custom-function

Coverage Status build status

Social Media Photo by Aaron Huber on Unsplash

Literally the only sane way, if not the fastest one, to extend the Function class without evaluation.

// const CustomFunction = require('custom-function');
import CustomFunction from 'custom-function';

class MyFunction extends CustomFunction {
  invoke(...args) {
    return this(...args);
  }
  toString() {
    return '[native code]';
  }
}

const cf = new MyFunction((a, b) => a + b);
cf(1, 2);         // 3
cf.invoke(1, 2);  // 3
cf.toString();    // "[native code]"

Why using a Class?

Object.assign(fn, {...extras}) can augment fn but it cannot have accessors, private fields, super.method(...args) calls, and so on, while with this module, everything possible with classes is possible with functions too.

Object.defineProperties can have accessors and not all enumerable and writable fields, but it still cannot set private fields or allow super.method(...args) calls.

On top of these limitations, adding O(n) features requires more effort than swapping once the prototypal chain, where the original Function.prototype root of the chain will be preserved regardless.

As summary: every solution to date that is not based on native class extends feature is somehow limited, likely slower, surely inferior in terms of DX.

Why only Function?

While writing this I had Function as one problematic constructor that cannot be extended due inevitable code evaluation involved while invoking super() but it's true that this approach/pattern can be used for any constructor that could be problematic if invoked right away, which is why there is a custom-function/factory export too so that anything becomes possible, example:

// const custom = require('custom-function/factory');
import custom from 'custom-function/factory';

// reproduce exactly what this module provides:
const CustomFunction = custom(Function);
class MyFunction extends CustomFunction {}

// go wild with any illegal constructor too
const Div = custom(HTMLDivElement);
class MyDiv extends Div {
  constructor(...childNodes) {
    super(document.createElement('div'));
    this.append(...childNodes);
  }
}

document.body.appendChild(
  new MyDiv(
    new MyDiv('A'),
    new MyDiv('B', 'C')
  )
);

Exports

  • custom-function to extend functions without invoking Function
  • custom-function/factory to extend any class without invoking the extended class constructor
  • custom-function/closure to extend functions in a Closure Compiler friendly way
  • custom-function/closure-factory to extend any class in a Closure Compiler friendly way

Performance

The benchmark test properties added to a callback using this module VS using a predefined descriptors object via Object.defineProperties to compare the most possible perf-tuned define properties approach against this module pattern.

Use npm run bench to test yourself locally, after cloning this repo.

cold run
CustomFunction
  creation: 20.884ms
  metohd: 3.421ms
Object.defineProperties
  creation: 76.917ms
  metohd: 4.838ms

hot run
CustomFunction
  creation: 7.597ms
  metohd: 0.667ms
Object.defineProperties
  creation: 94.064ms
  metohd: 1.359ms