I am looking for a fancy way to prevent a closure from inheriting surrounding scrope. For example:

let foo = function(t){

  let x = 'y';

  t.bar = function(){

    console.log(x); // => 'y'

  });

};

there are only two ways I know of preventing sharing scope:

(1) Use shadow variables:

let foo = function(t){

  let x = 'y';

  t.bar = function(x){

    console.log(x); // => '?'

  });

};

(2) Put the function body somewhere else:

  let foo = function(t){

      let x = 'y';

      t.bar = createBar();

    };

My question is - does anyone know of a 3rd way to prevent closures from inheriting scope in JS? Something fancy is fine.

The only thing that I think could possibly work is vm.runInThisContext() in Node.js.

Let's use our imaginations for a second, and imagine JS had a private keyword, which meant the variable was private only to that function's scope, like this:

  let foo = function(t){

      private let x = 'y';  // "private" means inaccessible to enclosed functions

      t.bar = function(){

        console.log(x); // => undefined

      });

    };

and IIFE won't work:

let foo = function(t){

    (function() {
    let x = 'y';
    }());

   console.log(x); // undefined (or error will be thrown)
   // I want x defined here

  t.bar = function(){
    // but I do not want x defined here
    console.log(x); 
  }

  return t;
};
    
There generally isn't much use for "private" variables or variables that aren't accessible in a lower scope etc. that why there really aren't any ways to create such variables. If you want something to not be accessible, enclose it in it's own scope, such as an IIFE etc. – adeneo 4 hours ago
    
Maybe you want an IIFE? – Kyle Richardson 4 hours ago
1  
You can transfer my 1000 bucks to my account in the Caymans -> jsfiddle.net/01fyqp0v – adeneo 4 hours ago
1  
Got it, block scope seems to be the way! – Kyle Richardson 4 hours ago
2  
@AlexanderMills I dunno... I think the OP is kinda IIFE. – Kyle Richardson 4 hours ago

1 Answer 1

You can use block scope

let foo = function(t) {
  {
    // `x` is only defined as `"y"` here
    let x = "y";
  } 
  {
    t.bar = function(x) {
      console.log(x); // `undefined` or `x` passed as parameter
    };
  }
};


const o = {};
foo(o);

o.bar();

1  
well I will be damned – Alexander Mills 4 hours ago
1  
If you're writing a library, then you're probably doing it wrong if you need this to make it work. This is however a good answer, block scope works great with let and const which are of course block scoped. – adeneo 4 hours ago
1  
Block statements by themselves are supported in almost all browsers, and have been a part of JS since the beginning, with and without labels etc. However block scoped variables, aka let and const are only available in newer browsers, and this won't work with a regular var, which is function scoped. – adeneo 4 hours ago
1  
Should be noted that if you wanted it to work in older browsers, with var, we're back to the extra function to create a new scope, most likely an IIFE again, which would look eerily similar to a block statement but with more characters -> jsfiddle.net/adeneo/ydpfaq5w/1 – adeneo 4 hours ago
1  
No they don't use an IIFE internally, then they'd create "function scope", which they don't. Again, blocks have been a part of JS since the beginning, and aren't functions, but they haven't been very useful until block scoped variables became available. – adeneo 4 hours ago