3 ms·
You are right, although this doesn't feel all that exotic to me, even though it might be unique for built-ins, it's essentially the same as what happens when yo
by tomxor 6y ago
You are right, although this doesn't feel all that exotic to me, even though it might be unique for built-ins, it's essentially the same as what happens when you pass variables to functions (you get a copy of the references, i.e they are added to the scope), in this sense a block scoped for loop feels similar to a series of function calls passing and returning a variable.
In fact you could emulate a block scoped for loop with an object with little trouble and without being all that confusing:
const FOR = (s, c, f) => c(s) &&
(f({...s}), FOR(s, c, f))
FOR({i: 0}, s => s.i++ < 8, s => {
setTimeout(() => {
console.log(s.i)
}, 100)
})
This doesn't prove anything, but the fact that blocked for can almost be implemented with in one small function makes me feel like it's not all that magic, rather it's just nice syntax.
[edit]
getting a bit silly now but was seeing how close I could get to built-in syntax... yes this is horrible, never use `with` or `eval` like this.
const EVIL = (f, s) => eval(`
with (s) {
${(f + '').replace(/^.+>/, '')}
}
`)
const FOR = (s, ce, fe, sb, ii) => {
if (EVIL(ce, s)) {
EVIL(sb, {...s})
EVIL(fe, s)
FOR(s, ce, fe, sb, 1)
}
}
FOR ({i: 0}, _=> i < 8, _=> i++, _ => {
setTimeout(() => {
console.log(i)
}, 100)
})
- xg15 6y agoYou have to clone from the previous iteration - because in theory, the block itself could modify the loop variable again and that modification gets lost if you keep cloning from the initial environment. So your function would produce incorrect results for cases like this: for (let i = 0; i < 100; i++) { i += 10; setTimeout(() => console.log(i), 1000); } I think the following should work though: function FOR(env, cond, incr, block) { if (cond(env)) { block(env); const env2 = {...env}; incr(env2); FOR(env2, cond, incr, block); } } FOR({i: 0}, s=>(s.i < 8), s=>s.i++, s=>{ setTimeout(() => { console.log(s.i) }, 100) }); And yeah, I agree, it's not really complicated to implement (as long as you don't care about the waste of memory). It was just an unexpected bit of logic at that point.