8

In Javascript, is there any way to import (or require) an object that's not exported by a module from that module?

I realize that this is likely bad practice, but I wonder if it's possible nevertheless. I have a Python background, so I'm confused by the idea that I can import a module but cannot access all of its data elements in Javascript.

Lane Rettig
  • 6,640
  • 5
  • 42
  • 51
  • 1
    Even python has private variables, doesn't it? – Bergi Mar 28 '16 at 14:34
  • Yes but [they're not actually private](http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private) – Lane Rettig Mar 28 '16 at 14:35
  • I meant [actual variables](http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules), not members (like attributes or methods). Aren't those private? – Bergi Mar 28 '16 at 14:43
  • 3
    Btw, are you asking about ES6 modules, CommonJS modules or something else? – Bergi Mar 28 '16 at 14:48
  • It's a general question not specific to one module system (although I guess the answer may depend upon the system). As for Python, I'm not sure, I kinda thought everything was accessible via introspection, but maybe we should post that as a separate Python question ;) – Lane Rettig Mar 28 '16 at 15:22
  • Well the answer might be specific to the module system you're using. In JS, scopes (including the module scope) are private, and there's not really a way to access them (unless you are a debugger). For modules, you might however load the source file, edit it to your liking (adding export declarations, for example), and then execute the changed module that exposed whatever you're interested in. This does of course require access to the module loading facility, which depends on the used module system. – Bergi Mar 28 '16 at 15:53
  • That makes sense. I'm looking for a way to do it without editing the module. I'm using node and mostly ES6-style imports. It sounds like the answer to my question is probably "no" without something really nonstandard such as trying to parse the module source using eval or something. – Lane Rettig Mar 28 '16 at 20:12
  • Yes indeed. You should accept @ssube's answer, I guess. – Bergi Mar 28 '16 at 20:46

1 Answers1

6

Not using the module API. A module exports an object and any code importing the module is given a reference to that object ("reference" in the JS sense).

Section 15.2.3 of the spec covers exports and, very verbosely, shows that the export keyword is used to include some local variable in the module's import/export table. Quite simply, if you don't specify export, the variable is local to the module scope.

This matches the behavior of legacy IIFE modules, which used function scope to hide their local variables, then exported an object to be made public.

An ES6 module like:

export class Foo {
  ...
}

export const bar = new Foo();

after being transpiled will look something like:

(function () {
  function Foo() {
    ...
  }
  var bar = new Foo();
  return {
    Foo: Foo,
    bar: bar
  };
})();

Most articles on JS modules (even the fantastic 2ality module writeup) don't mention what happens to un-exported variables.

For comparison, the CommonJS module standard states that modules have a variable exports and "the module may add its API to as it executes." The CommonJS standard has the only reference I've found so far to only exporting via keyword/object (from module context 2.1):

modules must use the "exports" object as the only means of exporting.

ssube
  • 47,010
  • 7
  • 103
  • 140