All your function are belong to ƒ. (Arrows too.)
Declare your JavaScript functions with a single ƒ character. No more typing out the full eight characters of “function.” And no more awkward-looking arrow functions either. Just crisp, clean, beautiful ƒ notation:
ƒ add( a, b ) a + bAll of the shortcut goodies of arrows. None of the nasties. No more gross “=()=>” snippets muddying up your argument-free lamba functions. Why include parentheses at all? Here’s how ƒ.js does it:
counter.increment = ƒ { this.n ++ }Your JavaScript never felt so clean.
I’ve never enjoyed JavaScript’s arrow function expression syntax. It’s like some weird castling move where the important components switch places for no good reason. Consider the following comparison. Here’a a traditional function expression with assignment:
var add = function( a, b ){ return a + b }And here’s the arrow function version:
var add = ( a, b ) => a + bWhile there are some nice parsing aspects to arrow functions—including the implicit return when the function definition is a single line and uses no curly braces—the form of the definition feels visually shuffled. Why is the => (the component that signals this is a function) placed after the argument parentheses? I get that it’s supposed to look like an arrow (→), to resemble the workflow of transforming some input arguments into an output. I get that someone thought that was clever. But it has never sat well with me. I don’t need that argument-transformation metaphor in my life. The fact that a function is a function at all—that’s the important part. The act of transforming a list of arguments is only secondarily important. Here’s how we can rewrite the above with ƒ.js:
var add = ƒ( a, b ) a + bAnd if you’re open to declaring named functions, it gets even simpler:
ƒ add( a, b ) a + bDoesn’t that read beautifully? You know it does. You know you’re intrigued. Perhaps you’re a little bit frightened—but you still want to know more!
Arrow functions really show their ick when it comes to argument-free function expressions. In these cases the parentheses and “arrows” typographically visualize transforming absolutely nothing at all:
var sayHello = () => console.log( 'Hello' )What on earth is this “=()=>” fragment? When you craft an argument-free lambda, why would you want the “arrow part” to be more typographically significant than the fact that it’s a lambda? (Alonzo Church and John McCarthy are contorting in their digital graves.) We need a strong visual indicator prefix to the function’s argument list and content, not a big ugly “transform arrow” in between the parentheses and content — that visually represents the transformation of nothing. This is crazy. We need the sanity of ƒ.js. See how much cleaner this is?
ƒ sayHello console.log( 'Hello' )I remember JavaScript before arrow functions even existed. (Thank you for your amazing work, Brendan—though every fiber of my being disagrees with your backward stance on homosexuality. It’s never too late to realize you were wrong; to evolve your thinking and come join us in the “boringly straight, clumsy but well intentioned ally” club. Please do.) When arrow functions finally arrived on the scene it took me years to ease my skepticism of this new approach to this binding. (I was accustomed to earlier this hacks. But since then I’ve grown to respect how arrows handle things. Besides, you can always use .bind(…) anyway.) Even though I’ve warmed to the functionality (no pun intended) of arrow functions, I still loathe the look of these two-character typographic blights, as well as their placement within the expression. So much so, that I barely use arrow functions in my own code. But writing out function all the time has grown so tedious…
I’ve taken matters into my own hands. Now I can just type ƒ for “function” as God intended¹. (On a Mac this is accomplished by pressing Option + F.) No more stupid arrows. And no more writing out function either. This is so much cleaner.
This demo app copies the content of the /source folder into a /distro folder, automagically transforming all of your .fjs files into vanilla JavaScript ones with .js extensions. The results are served up at http://localhost:4444.
`npm start`This demo also enables live ƒ.js test-driving right in your JavaScript console:
var fjsCode = `ƒ test console.log( 'Works!' )`
eval( fThis( fjsCode ))
test()Or all in one go:
eval( fThis( `ƒ test console.log( 'Works!' )` )); test()Did you make it this far in the README? Wondering why there’s no ƒ.js Babel plugin? It’s because you haven’t submitted a PR for one yet. (Fork ƒ.js here.)
Let’s have a look at a full battery of example use cases. Declarations. Expressions. Named. Lambdas. Arguments. No arguments. Nestings. Closures. We got it all, baby!
const add = ƒ( a, b ){ return a + b }
console.log( add( 2, 3 ))const tick = ƒ { console.log( 'tick' )}
tick()ƒ named1(){ console.log( this.name )}ƒ named2 { console.log( this.name )}[ 1, 2, 3 ]
.map( ƒ( x ){ return x * 2 })const times = ƒ( n, fn ){ for( let i = 0; i < n; i ++ ) fn( i )}
times( 3, ƒ( i ){ console.log( i )})const msg = ( ƒ( name ){ return `Hello, ${ name }`})( 'F-this' )
console.log( msg )const
format = ƒ({ a = 1, b = 2 } = {}){ return `${ a }:${ b }`},
sum = ƒ( ...xs ){ return xs.reduce( ƒ( s, x ) s + x, 0 )}const counter = {
n: 0,
increment: ƒ { this.n ++ },
get: ƒ { return this.n }
}const pick = ƒ( obj, keys ){
const out = {}
for( const k of keys ){ if( k in obj ){ out[ k ] = obj[ k ]}}
return out
}await ( async ƒ(){ return 42 })()await ( async ƒ { return 67 })()async ƒ doWork { await new Promise( ƒ( r ){ setTimeout( r, 10 )})}¹ I am an atheist.
² Folks who are concerned by my use of var in some of the examples above(instead of const or let) may be ignorant to the joys of function scope, which is of course the standard for function declarations. Plus var lets you redeclare to your heart’s content, which means no errors when repeatedly pasting code snippets directly into your console. Sure, go ahead and use const and let for “interior code.” But for fast REPL pasting, isn’t var friendlier to the paster?