Převedení metod na samostatné funkce v  JavaScriptu

Jen krátký tip na převedení metod (funkcí v prototype) na samostané funkce v JS pomocí Proxy (MDN).


Myšlenka stojí na možnosti použití Function.prototype.call()Function.prototype.bind().

1
2
3
4
5
6
7
8
9
const arr= "ABCDEF".split("");//jen vytvoření pole
//#1
arr.forEach(conslole.log);
//#2
const forEach1= Array.prototype.forEach;
forEach1.call(arr, console.log);
//#3
const forEach= Function.prototype.call.bind(Array.prototype.forEach);
forEach(arr, console.log)

Ekvivalentí volání metody forEach (body #1–#3). Ve #3 využijeme .bind pro možnost volání bez .call (šlo by také použít obalení funkcí).

Pro zobecnění a zautomatizování lze pomocí Proxy vytvořit pomocné jmenné prostory či pomocnou funkci:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const utils= (function(proxy){
  return {
    Array: new Proxy(Array.prototype, proxy),
    String: new Proxy(String.prototype, proxy),
    console: new Proxy(console, { get(target,name){ return target[name].bind(target); } })
  };
})({
  get(target,name){ return Function.prototype.call.bind(target[name]); }
});

const { map }= utils.Array;
const { charCodeAt }= utils.String;
const { log }= utils.console;

log(map(["A"], a=> charCodeAt(a, 0)));

Použití jako jmenné prostory (tj. vytvoření knihovny)

1
2
3
4
5
6
7
8
9
const toFunctional= object=> object.prototype ?
  new Proxy(object.prototype, { get(target,name){ return Function.prototype.call.bind(target[name]); } }) :
  new Proxy(object, { get(target, name){ return target[name].bind(target); } });

const { map }= toFunctional(Array);
const { charCodeAt }= toFunctional(String);
const { log }= toFunctional(console);

log(map(["A"], a=> charCodeAt(a, 0)));

Převádění na funkce pomocí toFunctional

Důležité je mít na paměti, že takovéto použití má důsledky mimojiné v hlášení chyb – první argument takovýchto funkcí je this, takže například při zavolání map(["A"]) dostaneme chybu „Uncaught TypeError: missing argument 0 when calling function Array.prototype.map”.

Dále některé takto vytvořené funkce nejsou „funkcionální” (Pure function) – například Array.prototype.splice().

Pro funkcionální přístup potřebujeme některé další nástroje, jako například „pipe” funkci (viz dále). Jako lépe předpřipravené ucelené řešení lze použít nějakou knihovnu jako emphori/stark: Minimal and incredibly lightweight functional programming for JavaScript.

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * @param {...function} functions
 * @returns {(mixed: any)=> any}
 * @example
 * console.log(pipe(
 *  a=> a+1,
 *  a=> a*2
 * )(0));//= 2
 */
const pipe= (...functions)=>
  Array.prototype.reduce.bind(functions,
    (acc, currFunction)=> currFunction(acc));

Příklad definice „pipe” funkce.