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

papp-polyfill

v1.1.0

Published

A polyfill for Function.prototype.papp

Downloads

4

Readme

ECMAScript Proposal: Function.prototype.papp

This proposal introduces papp and pappRight – concise ways of using partial application for functions that require no immediate this parameter. It is backwards-compatible, and is immediately useful with most any JavaScript function today.

Try it out!

npm install --save papp-polyfill

Then require it once (in your code, as early as possible):

require('papp-polyfill')

Introduction

Partial application is possible in JavaScript via Function.prototype.bind:

function add (x, y) { return x + y; }

var addTen = add.bind(null, 10);
addTen(20) //=> 30

However, bind is undesirable for three reasons:

  1. Sometimes you don't care about the value of this, yet you still must provide bind's first argument
  2. Sometimes you do care about the value of this, but don't want to commit to a specific value yet.
  3. ~~Using bind is significantly slower than using a plain closure (!)~~ (this has been fixed in V8, and wasn't an issue in other engines for quite a while)

Function.prototype.papp solves both these issues in a simple, elegant, and noise-free manner. Here is an illustrative example:

function add (x, y, z) { return x + y + z; }

var addTen = add.papp(3, 7);
addTen(5) //=> 15

// AS OPPOSED TO:
// var addTen = add.bind(null, 3, 7)
// OR:
// var addTen = (x) => add(3, 7, x)

var addThenIncrement = add.papp(1);
addThenIncrement(10, 6) //=> 17

// AS OPPOSED TO:
// var addThenIncrement = add.bind(null, 1)
// OR:
// var addThenIncrement = (a, b) => add(1, a, b)

Accepting papp into the ES standard will allow JS runtimes to implement a more performant version of bind that is dedicated to partial application.

Ignoring this

For functions that don't use the keyword this, papp helps with brevity:

function add (x, y) { return x + y; }

var addTen = add.papp(10);
addTen(20) //=> 30

Deferring Function Binding

If a function does use the keyword this, papp allows you to partially apply arguments without committing to a this value:

function greet (target) {
  return `${this.name} greets ${target}`;
}

var greetNewcomer = greet.papp('the newcomer');
greetNewcomer.call({ name: 'Alice' }) //=> 'Alice greets the newcomer'

Practical Examples

These examples are pulled from real-world use cases of partial application.

HTTP API Output Whitelisting

Player.whitelist = {
  basic: pluck.papp(['name', 'score']),
  admin: pluck.papp(['name', 'score', 'email']),
};

function pluck (attrs, obj) {
  var result = {};
  attrs.forEach( name => result[name] = obj[name] );
  return result;
}

// Example use (in practice, alice would come from a database):
var alice = { name: 'Alice', score: 100, email: '[email protected]', password_hash: '...' };

Player.whitelist.basic(alice) //=> { name: 'Alice', score: 100 }

Player.whitelist.admin(alice) //=> { name: 'Alice', score: 100, email: '[email protected]' }

Constructing User-friendly APIs

function createClient (host) {
  return {
    get:  makeRequest.papp(host, 'GET'),
    post: makeRequest.papp(host, 'POST'),
    put:  makeRequest.papp(host, 'PUT'),
    del:  makeRequest.papp(host, 'DELETE'),
  };
}

var client = createClient('https://api.example.com');
client.get('/users');
client.post('/comments', { content: "papp is great!" });

function makeRequest (host, method, url, data, options) {
  // ... Make request, return a promise ...
}

// AS OPPOSED TO:
// function createClient (host) {
//   return {
//     get:  (url, data, options) => makeRequest(host, 'GET', url, data, options),
//     post: (url, data, options) => makeRequest(host, 'POST', url, data, options),
//     put:  (url, data, options) => makeRequest(host, 'PUT', url, data, options),
//     del:  (url, data, options) => makeRequest(host, 'DELETE', url, data, options),
//   }
// }

Other Examples

These examples illustrate concepts you can use in your own applications.

Mapping with Arrays

var chapters = ["The Beginning", "Climax", "Resolution"];

var numberedChapters = chapters.map( toListItem.papp('My Book') )
//=> ["My Book / 1. The Beginning", "My Book / 2. Climax", "My Book / 3. Resolution"]

// AS OPPOSED TO:
// var numberedChapters = chapters.map( (chapter, i) => toListItem('My Book', chapter, i) )

function toListItem (prefix, item, i) {
  return `${prefix} / ${i + 1}. ${item}`
}

Polyfill

ES6:

Function.prototype.papp = function (...args) {
  var fn = this;
  return function (...moreArgs) {
    fn.apply(this, args.concat(moreArgs));
  };
};

ES5:

Function.prototype.papp = function () {
  var slice = Array.prototype.slice;
  var fn = this;
  var args = slice.call(arguments);
  return function () {
    return fn.apply(this, args.concat(slice.call(arguments)));
  };
};