1. Summary
I can’t find, what is the correct way to use functions inside loops (or what to replace it with) in CoffeeScript 2 in 2024.
Should I use one of the variations I’ve given below, or CoffeeScript has a better solution?
2. MCVE
I need to run a function inside a loop. The global function setTimeout() in my MCVE solely for example to make the MCVE simple. In real projects I use other functions.
Example array:
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"]
I want to get this console output:
Kira is Goddess!
Kira is Ideal!
Kira is Perfection!
3. Not helped
3.1. “for…of” loop
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"]
for kiraСharacteristic from kiraСharacteristicsArray
setTimeout (->
console.log "Kira is #{kiraСharacteristic}!"
), 0
Compiled JavaScript:
var kiraСharacteristicsArray, kiraСharacteristic;
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"];
for (kiraСharacteristic of kiraСharacteristicsArray) {
setTimeout((function() {
return console.log(`Kira is ${kiraСharacteristic}!`);
}), 0);
}
Result:
Kira is Perfection!
Kira is Perfection!
Kira is Perfection!
Simple ECMAScript solution doesn’t work in CoffeeScript:
- CoffeeScript haven’t
constandlet. - Unfortunately, CoffeeScript compiles solely to
var, not toconstandlet. - I haven’t found an ESLint plugin or any other tool that would correctly replace
varwithconstandletin JavaScript files.
3.2. Closure
As @Alex Wayne described in his answer:
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"]
for kiraСharacteristic from kiraСharacteristicsArray
do(kiraСharacteristic) ->
setTimeout (->
console.log "Kira is #{kiraСharacteristic}!"
), 0
Compiled JavaScript:
var kiraСharacteristicsArray, kiraСharacteristic;
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"];
for (kiraСharacteristic of kiraСharacteristicsArray) {
(function(kiraСharacteristic) {
return setTimeout((function() {
return console.log(`Kira is ${kiraСharacteristic}!`);
}), 0);
})(kiraСharacteristic);
}
I get expected console output, but ESLint return no-shadow error:
6:13 error 'kiraСharacteristic' is already declared in the upper scope on line 1 column 16 no-shadow
3.3. “forEach()” method
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"]
kiraСharacteristicsArray.forEach (kiraСharacteristic) ->
setTimeout (->
console.log "Kira #{kiraСharacteristic}!"
), 0
Compiled JavaScript:
var kiraСharacteristicsArray;
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"];
kiraСharacteristicsArray.forEach(function(kiraСharacteristic) {
return setTimeout((function() {
return console.log(`Kira ${kiraСharacteristic}!`);
}), 0);
});
I get expected console output, but Unicorn return no-array-for-each error:
5:11 error Use
for…ofinstead of.forEach(…)unicorn/no-array-for-each
3.4. “continue” statement
I fixed JavaScript above use ESLint, Unicorn and prefer-arrow-function plugin use eslint --fix CLI command:
var kiraСharacteristicsArray;
kiraСharacteristicsArray = ["Goddess", "Ideal", "Perfection"];
for (const kiraСharacteristic of kiraСharacteristicsArray) {
setTimeout((() => console.log(`Kira ${kiraСharacteristic}!`)), 0); continue;
}
I get expected console output, but ESLint return no-continue error:
6:64 error Unexpected use of continue statement no-continue
4. Don’t offer
Please, don’t offer:
“Use JavaScirpt, CoffeeScript is bad”.
“Don’t use functions inside loops. Read JSHint’s warning”. Yes, JSHint return
warning W083, when I use a function inside loop:jshint: warning W083 - Functions declared within loops referencing an outer scoped variable may lead to confusing semantics. (console)
But it seems to me that
loopfuncJSHint’s option is obsolete and doesn’t take into account the ECMAScript featuresconstandlet.“Use Civet instead of CoffeeScript” Yes, I know that Civet supports
constandlet, see my MCVE written on Civet. But my question about CoffeeScript.