Use a closure:
let getA;
let getB;
let getC;
function initStringFormatter (x) {
let locale = x;
getA = function () { return 'A' + locale }
getB = function () { return 'B' + locale }
getC = function () { return 'C' + locale }
}
initStringFormatter('enUS');
getA();
In theory, closures can provide exactly the same features as object properties/variables/members in OOP. There's an exact one-to-one relation between closures and objects. The only difference is that closures use scope as the mechanism to attach variables to functions whereas objects use bindings to attach variables to methods.
Of course, there's nothing wrong mixing OOP with FP. Even Lisp has an OOP library. So a common javascript idiom is to return an object instead of having the function names as global variables:
function initStringFormatter (locale) { // another trick is to just use
// the argument directly instead of
// creating another variable.
function a () { return 'A' + locale }
function b () { return 'B' + locale }
function c () { return 'C' + locale }
return {
getA: a,
getB: b,
getC: c
}
}
let stringManager = initStringFormatter('enUS');
stringManager.getA();
Indeed. It is common to see FP programmers in javascript use objects this way: simply as namespaces for functions. State management can be done 100% using closures instead of object properties.
Side note: FP is powerful enough that languages like Lisp don't need OOP to be built-in to the language, instead OOP is a design pattern and/or a library - the standard OOP library for Lisp is CLOS: the Common Lisp Object System
The only downside of using closures is that all closures are essentially private (technically they're not private, they're just local variables to the functions - private/public are binding concepts global/local are scope concepts). But if you've done any significant amount of OOP you would recognize this as good practice in the OOP world to not ever give public access to variables. When using closures 100% of access to the variable need to be done via functions - again, in the OOP world this would be the common getter/setter design pattern which is considered good practice.
Note however this is not 100% pure FP. But that's OK. There are other FP languages that are not pure. Javascript still allows enclosed variables to be modified. However the above function is pure FP since the locale variable cannot be modified.
To make javascript 100% pure FP is simple. Simply ban all uses of let and var in your code and always use const. It feels odd at first but you can write any program using only const and function arguments (which are constants by default). Languages like javascript and Go gives you an escape to use variables to manage state based logic in a straightforward manner.
localetogetA,getB, andgetCevery time? You're doing the same thing with OOP too. OOP forces you to writestringManager.getA(),stringManager.getB(), andstringManager.getC(). How is that better than writinggetA(locale),getB(locale), andgetC(locale)?getA,getB, andgetCcan be as complex as required. For example, instead of passing a simple stringlocaleyou can pass a complex object to these functions. I still don't see the “problem” here.