4

Is there a way to import all methods into scope without the necessity of a qualifier? Other languages (like Elm) allow this.

The ES6 spec allows:

import {map, where} from 'underscore'; //unqualified imports by name only
import * as _ from 'underscore'; //with qualifier

but not this:

import * from 'underscore';
Mario
  • 6,572
  • 3
  • 42
  • 74
  • Not sure I get what you're asking here, `*` is an operator, not a method, and as such it can't be invoked with bracket notation or imported anywhere etc ? – adeneo Aug 05 '14 at 14:35
  • The key line is `var map = _.map, ...`. If underscore were an ES6 module, how would I import all its methods into local scope (as variables) so that I didn't need the `_` prefix? Notice that later I use `map(filter(...` and not `_.map(_.filter(...`. – Mario Aug 05 '14 at 14:37
  • 1
    I don't think you can, even if you give `this` the value of `_` you would still have to call `this.filter` as it's still an object with properties. The only way I can think of to do that is to copy each method to the window object. I don't know if ES6 has anything that can do this, I really can't think of anything ? – adeneo Aug 05 '14 at 14:42
  • 1
    In the current draft spec there is no way to do this. However, it is [under discussion](http://esdiscuss.org/topic/moduleimport). Although importing all exports will result in those exports being properties of an object so it won't allow you to use them in the way you hope. – James Allardice Aug 05 '14 at 14:43
  • http://jsfiddle.net/LwbL7/ – adeneo Aug 05 '14 at 14:44
  • Oh. I agree. That's the problem. I was hoping it could somehow be overcome in ES6. If I'm building a library that primarily uses underscore, I should be able to use underscore's methods without always using the underscore prefix. – Mario Aug 05 '14 at 14:45
  • @Mario - Could the developer have constraints on how to format their IIFE? Such as injecting and binding context? – Travis J Aug 05 '14 at 14:46
  • @adeneo -- your jsfiddle unfortunately pollutes the global namespace. What I don't understand is why I can call methods on the global namespace in a way that effectively uses a `with` block, but I cannot accomplish the same in local scope without `with`. – Mario Aug 05 '14 at 14:47
  • That's because global methods are "special", if you wrap it in a IIFE and bind with an empty object or something similar, you still can't call it directly, you can only do that with methods attached to window, see this -> **http://jsfiddle.net/LwbL7/1/** – adeneo Aug 05 '14 at 14:48
  • @JamesAllardice -- that's exactly what I was asking for. I hope the discussions lead to the adoption of this feature. Many languages do it. I see no reason JavaScript should avoid it. – Mario Aug 05 '14 at 14:50

2 Answers2

2

I could not think of a good way to do this without trashing the global namespace. However, if the window object is going to be trashed, might as well do it to someone else's.

That someone else, is iframe. I think this is an interesting approach, and if there are any potential pitfalls please leave a comment and I will try to address them.

Basically what is going to happen is an iframe is going to be created. It will have a script element whose content will be the anonymous function passed. Its scope will be entirely sandboxed, aside from any global variables passed in (and their correlating setters if values need to be returned).

using
function
Type: Function( {settings} )
Allows the use of a localized environment

settings
Type: PlainObject
A set of key/value pairs that configure the environment. There is no error handling at the moment.

  • lib
    Type: PlainObject
    This argument should be the library used in the localized global environment.

  • fn
    Type: Function
    This will be anonymous function which executes under the local environment.

  • global
    Type: PlainObject
    The global argument will allow for communication if required between the localized environment and the outside context. Using a key value pair, the key will be the name made available in the localized environment. The value will either be used (in which case the outside environment's value should be used), or the value will be a setter (in which case the outside environment's value will be updated at the end of the function execution). This is a loosely designed implementation and can be adapted for more situations if desired.

jsFiddle Demo

definition of the using function

function using(args){
 var lib = args.lib;
 var callback = args.fn;
 var global = args.global;
 var iframe = document.createElement('iframe');
 document.body.appendChild(iframe);
 iframe.contentWindow.exec = function() {
    for(var fn in lib){
     this[fn] = lib[fn];     
    }
    for(var val in global){
     this[val] = global[val];
    }
    var scr = document.createElement("script");
    scr.innerHTML = "("+callback+")()";
    iframe.contentWindow.document.body.appendChild(scr);
 };
 iframe.contentWindow.exec();
 for(var val in global){
  if(global[val] instanceof Function)
   global[val](iframe.contentWindow[val]);
 }
 iframe.parentNode.removeChild(iframe);
}

code used in demo

var stooges;
var list = document.querySelectorAll(".hello");//just a set of 5 divs classed as hello with w,o,r,l,d in them respectively

using({
 lib: _,
 global: {
     "stooges":function(val){ stooges = val; },
     "list":list
 },
 fn: function(){
  function toUpperCase(x){
   return x.toUpperCase();
  }
  function minSize(len){
   return function(str){
    return str.length >= len; 
   }
  }
  stooges = map(filter(["Larry", "Curly", "Moe"], minSize(4)), toUpperCase);
  each(list,function(el){console.log(el.innerHTML);});
 }
});
console.log(stooges);
Travis J
  • 81,153
  • 41
  • 202
  • 273
1

From my findings: No, there is no current or planned way of importing variables into local scope.

Mario
  • 6,572
  • 3
  • 42
  • 74