Sunday, January 12, 2014

Improved map() & reduce() ?

In a previous post JavaScript function F () I presented the function F () which allows you to create functions from simple String expressions.

F() makes using JavaScript map() and other "functors"  more concise, allowing you to replace:
  [1,2,3].map(function (x){return x * 10});
with:
  [1,2,3].map(F('x * 10'));

But I and some commentators felt the above still looked a bit cryptic for common use.  Having to know what F() means is an extra mental load for readers of this code, as is the extra set of parentheses needed.  And F() needs to be more or less cryptic, because it is supposed to be a shorthand after all.

So,  here might be a better solution (but see the caveat at the end of this post):

1. Go to section titled "Polyfill" at MDN's Array.prototype.map. It gives the code to implement map() on older browsers which don't support that natively.

2. Read and be aware of the license(s) provided under which you can use their code, linked to at the bottom of their page.

3. Copy their code as instructed to your own script.

4. Replace the beginning of their code :

  if (!Array.prototype.map)
  { Array.prototype.map = function(fun /*, thisArg */)
  ...
  
with this:

  function F (aString)
  { return new Function("x", "y", "z", "w", "return " + aString);
  }

  Array.prototype.map 
  = function (funARG)
  {  var fun = funARG;
     if (typeof fun == "string")
     { fun = F(fun);
     }
   ...

The above replaces the native implementation of map() if it did exist with our enhanced version of MDN's polyfill. If it didn't, it creates the method map() for the Array prototype.

You can now replace:
  [1,2,3].map(F('x * 10'));

with the more simple:
  [1,2,3].map('x * 10');

You can do a similar enhancement to their reduce() -code, available on the same site. Then you can write:
  [1,2,3].reduce('x + y');  

Documentation of map() and reduce() and their polyfills can be found at  https://developer.mozilla.org/. Interestingly, I think the above makes the case that using a polyfill is sometimes better than having the native implementation (which theoretically can differ between browsers as well).

In general I think the point is that using functional expressions like map() should make programming simpler, not more verbose and complicated. It would be great if ECMA at some point added a shorthand syntax for anonymous functions to the JavaScript standard.  But, it can in fact be argued that the solution above is good just because it does not require any new syntax, just an 'overloaded' semantics for map() and other functors.


UPDATE / CAVEAT:  In fact I can not  recommend this solution for general use.  Depending on your application and the JavaScript libraries it uses, the solution above might break your application.. The reason is that when you add a method to the prototype of Array, it means that when looping over an array, that added property will on some browsers become one of the properties being looped over. That might break some existing code not only in your application but also in the libraries you use.  So, for me at least it is back to using the  function F(). Avoid adding your own methods to JavaScript built-in prototypes, at least things you can iterate over!


© 2014 Panu Viljamaa. This work is licensed under a Creative Commons Attribution 4.0 International License

No comments:

Post a Comment