Call Apply

Function.prototype.call / .apply / .bind: invoke a first-class function value with an explicit argument list, and — for a function with a `this: T` parameter — an explicit receiver. Runs the same under Node.js.

const add = (a: number, b: number): number => a + b;

// .call forwards its trailing arguments one by one.
console.log("call:", add.call(null, 3, 4));

// .apply forwards the elements of a (literal) array.
console.log("apply:", add.apply(null, [5, 6]));

// A named function works as a first-class value too.
function greet(name: string): string {
  return "kalimera, " + name;
}
console.log(greet.call(null, "kosme"));

// .apply also accepts a runtime array, spread into a rest parameter.
const total = (...ns: number[]): number => {
  let t = 0;
  for (const n of ns) t = t + n;
  return t;
};
const nums = [10, 20, 30];
console.log("apply(rest):", total.apply(null, nums));

// .bind returns a partially-applied function.
const multiply = (a: number, b: number): number => a * b;
const double = multiply.bind(null, 2);
console.log("bind:", double(21));

// Useful for a callback that a helper invokes indirectly.
function runTwice(fn: (n: number) => void): void {
  fn(1);
  fn(2);
}
const show = (n: number): void => { console.log("n =", n); };
runTwice((n: number) => show.call(null, n));

// A `this: T` parameter types the receiver, which .call/.apply/.bind supply
// and a method call passes.
interface Counter { count: number }
function bump(this: Counter, by: number): number {
  this.count += by;
  return this.count;
}
const counter: Counter = { count: 0 };
console.log("this via call:", bump.call(counter, 5), bump.apply(counter, [2]));
const bumpCounter = bump.bind(counter);
console.log("this via bind:", bumpCounter(3), counter.count);

// A callback typed with `this` gets the receiver the caller passes, as a
// Node options object's `read()` gets its stream.
class Source {
  items: string[] = [];
  private read?: (this: Source, n: number) => void;
  constructor(opts: { read?: (this: Source, n: number) => void }) { this.read = opts.read; }
  pull(n: number): string[] {
    if (this.read) this.read.call(this, n);
    return this.items;
  }
}
const src = new Source({ read(n) { for (let i = 0; i < n; i++) this.items.push("item" + i); } });
console.log("callback this:", src.pull(3).join(","));
View source on GitHubexamples/function_expressions/call_apply.ts