Consider the following problem: I want to create an array of functions, each function just prints its index in that array. In Python, it can be done easily with
funcs = []
for i in range(5):
funcs.append(lambda i=i: print(i))
funcs[2]()
# 2
Here we use default argument values as a way to do currying (if I understand the term right).
Prior to ES6, there were no default argument values in Javascript, so currying had to be done in different way. Now we have them and I tried to translate Python to Javascript literally:
funcs = []
for (var i=0; i<5; i++) {
funcs.push(function (i=i) {console.log(i)})
}
# this part pass OK
funcs[2]()
ReferenceError: i is not defined
at Array.<anonymous> (evalmachine.<anonymous>:3:27)
at evalmachine.<anonymous>:1:9
at ContextifyScript.Script.runInThisContext (vm.js:26:33)
at Object.exports.runInThisContext (vm.js:79:17)
at run ([eval]:608:19)
at onRunRequest ([eval]:379:22)
at onMessage ([eval]:347:17)
at emitTwo (events.js:106:13)
at process.emit (events.js:191:7)
at process.nextTick (internal/child_process.js:752:12)
Why it fails? What's the difference between Python and Javascript ways to pass default values?
(Okay, I know that I can use let
here instead of var
, I'm just studying Javascript after several years with Python and trying to understand it underhoods.)
Both Javascript and Python using late-binding in closures. However, using a default argument is a hack that let's you simulate early binding in Python, and that works because default parameters are evaluated at function definition time in Python. However, in Javascript default arguments, according to the docs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
Here is one of the solutions used in Python that can be applied to this problem in Javascript. I've transliterated into Javascript the best I could. Essentially, define another anonymous function that returns your original, and apply it at the same time. This is very messy to my eyes, and in Python, I always go with the default-argument:
In Python:
I think it is clear that you should use
.bind
in Javascript, as elucidated in other answers, and not this clunky solution.