Skip to content

Latest commit

 

History

History
53 lines (42 loc) · 1.78 KB

loop-closures.md

File metadata and controls

53 lines (42 loc) · 1.78 KB

Loop closures

A loop closure that captures a block scoped loop variable can't be transpiled only with variable renaming.

Let's take the following example:

const arr = [];
for (let x = 0; x < 10; x++) {
    let y = x;
    arr.push(function() { return y; });
}

defs with default options gives you an error:

line 4: loop-variable y is captured by a loop-closure. Tried "loopClosures": "iife" in defs-config.json?

This is because With ES6 semantics y is bound fresh per loop iteration, so each closure captures a separate instance of y, unlike if y would have been a var.

You can now either choose to rewrite it manually (in usual pre-ES6 style), with an IIFE or bind or similar. For example:

for (let x = 0; x < 10; x++) {
    const arr = [];
    (function(y) {
        arr.push(function() { return y; });
    })(x);
}

And that runs just fine and defs stops complaining. Alternatively, you can ask defs to create the IIFE for you by adding "loopClosures": "iife" to your defs-config.json. Run on the original example, defs transpiles that without complaining to:

var arr = [];
for (var x = 0; x < 10; x++) {(function(){
    var y = x;
    arr.push(function() { return y; });
}).call(this);}

Not all loop closures can be transpiled into IIFE's. If the loop body (which contains the loop closure) also contains a return, yield, break, continue, arguments or var, then defs will detect that and give you an error (because an IIFE would likely change the loop body semantics). If so either rewrite the loop body so it doesn't use any of these or insert an IIFE manually (knowing what you're doing).

defs does not support transforming loops containing loop closures in any other way than with IIFE's, including try-catch statements.