In a regular script a function can be invoked by string name as window["myFunc"]().
Is there an equivalent in a JS script of type="module" at the "top level", apart from declaring an object and assigning a method to it?
Thank you.
No - one of the main benefits of modules is to allow code that avoids that sort of global pollution. The top level of a module works similarly to an IIFE - the module can see everything that's global, but nothing can see what's declared inside the module, except that, also:
Modules can import from other modules
Modules can export to other modules
While you technically can do something like
window.foo = 'foo';
inside a module, writing scripts that use that route defeats the purpose of using a module system at all. Explicit dependencies make code more maintainable.
No, there isn’t an equivalent. Even in a non-module, let, const, and class declarations don’t become properties of the global object or any other object.
(This is a good thing, though! Explicit is better than implicit.)
Related
In implementing the Python module mechanism on top of ES6 modules for the Transcrypt Python to JavaScript compiler, I am faced with the following problem:
There are a large number of standard functions imported from the Python runtime module, like e.g. the Python input function (implemented in JS), which can be made available using named imports (since they shouldn't have to be prefixed with anything in the user code, so input rather than __runtime__.input, to be consistent with Python).
In Python it's allowed to rebind named imports. So I define another function input, which will override the one from the runtime. But if I do so in JS, I get an error:
Identifier 'input' has already been declared
It seems that all imported names are regarded as JS consts, so non-rebindable according to this article. I can think of several clever workarounds, like importing under an alias and then assigning to a module global var rather than const, but like to keep things simple, so my question is:
Am I right that JS named imports are consts, so non-rebindable (and if so, just curious, anyone knows WHY)? Where can I find details on this?
Is there a simple way to circumvent that and still put them in the global namespace of the importing module, but override them at will?
As per the language specification, imported bindings are immutable bindings, so they cannot be changed. The identifiers are reserved as the module gets parsed because of how ES6 modules work: Unlike in Python, imports are not statements that are included as they are executed; instead, all a module’s imports are basically collected during the early compilation and then resolved before the module starts executing.
This makes ES6 modules kind of unsuitable as an implementation for Python’s import system.
As a general way, to avoid losing those names, you can simply give the imported bindings different names. For example an from foo import bar, baz may be compiled to the following:
import { bar as _foo__bar, baz as _foo__baz } from 'foo';
let bar = _foo__bar;
let baz = _foo__baz;
That will only reserve some special names while keeping the bar and baz identifiers mutable.
Another way, which would probably also help you to solve possible import semantics differences would be to simply create a closure:
import { bar, baz } from 'foo';
(function (bar, baz) {
// …
})(bar, baz);
Or even add some other lookup mechanism in between.
Btw. Python’s import is very similar to Node’s require, so it might be worth looking into all those solutions that made Node’s module system work in the browser.
I've just started learning gulp, and I've been seeing a lot of people using global.isProd
Example of a gulp file:
'use strict';
global.isProd = false;
require('./gulp');
I just want to understand what is global and what is global.isProd or if you can tell me where I can find this information.
global is how you access true global variables in node.js.
So, global.isProd = false; is assigning a globally reachable property named isProd an initial value.
In node.js, the top level scope in a module (e.g. a var xxx declared at the top level of a module) is not actually the global scope. This is different than Javascript in the browser. The top level in a module is local to the module as a module is actually declared within a function scope that node.js sets up for each module.
So, to actually reach the global scope in node.js, it defines the symbol global that works somewhat like the window symbol in a browser. If you want a globally accessible variable in node.js, you make it a property of the global symbol.
Here's what the node.js doc has to say about global.
The usual practice in nodejs is to avoid globals when practical because it prevents global naming conflicts and letting modules store their own state generally makes code more modular and more reusable. Since module references are cached, you can usually get access to a common resource by simply referencing a property of a module or by calling a method in that module and just let the module itself take care of storing the common resource in its own module variables without using globals. So, the cached module handles tend to make it simpler to get access to singleton resources via a given module.
global is just a variable in the module's scope. It's similar to window in the browser, except global's scope covers the module only.
isProd is simply a "global variable" (again, only in the module) that tells your gulp file "Hey! This is NOT production." It's nothing special by the way, probably just used in your script.
a.js
import "b.js"
var globalVar = 3;
b.js
alert(globalVar);
It's worked. How is this possible?
Variables in the global scope in JavaScript are just that: global. There is no distinction between which file the variable was declared in, if it was declared in the global scope.
As #FelixKling mentioned in the comment there is a proposal to add modules to JavaScript in a future version which would function similar to namespaces (or packages) in other languages.
That is a very good example of why it is a very good idea to avoid using global variables.
Here is a common practice in JavaScript:
(function($) {
...code...
})(jQuery);
I understand the wrapper function (it prevents pollution of the global namespace), but many libraries (like jQuery, Underscore, etc.) already define short names ($ and _, respectively) at global scope for me to use. I wonder what the advantage to this approach is. Just to rename jQuery to something shorter? Prevent me from overwriting $? Make it easier to swap in another library later? I guess none of these seem really convincing to me.
Furthermore, I have also seen this:
(function(_) {
...code...
})(_);
Nothing is even renamed here. I have even seen:
(function(global) {
...code...
})(this); // or window, perhaps
What is wrong with just using window directly?
So here's what I'm asking:
Does this practice have a name?
What are the advantages to this practice?
Should I always pass in libraries I'm using rather than use them directly?
Should I pass in this or window as a reference to global scope?
Does this practice have a name?
The syntax is referred to as a self-executing anonymous function. I'm not aware of any special name for passing global objects to the function.
What are the advantages to this practice?
As you've noted, var scoping variables within the function will
help de-clutter the global namepace.
The jQuery example is typically used in plugins so that the plugin can make use of $ while remaining compatible with $.noConflict() (docs)
(function($) {
...code...
})(jQuery);
In general, passing global or reserved objects (like window, document) as parameters can help reduce the size of your script after minification:
(function(window, document) {
// A JS minifier can now minify the all occurrences of `window` and
// `document` within this function.
})(window, document);
Should I always pass in libraries I'm using rather than use them directly?
Should I pass in this or window as a reference to global scope?
Only if minification or conflicting library variable names are a concern.
What are the advantages to this practice?
If the variable ('_', '$', etc) is later overwritten by some other code, your code will continue to work as expected. It will use the value passed in when the wrapper function was invoked.
Should I always pass in libraries I'm using rather than use them directly?
No, but if you have any concerns about the above, it's probably a good practice. Also, if you look up AMD loaders such as Require.js, you will find this a familiar technique, as they do something similar to define the requirements for your module.
Should I pass in this or window as a reference to global scope?
this has the advantage that the code will run where ever there is a global scope. For instance, if you code might possibly run on a Node.js server, there is no window.
I know in node, every module gets an local scope and variable defined within one module won't escape to the global unless explicitly exported.
What I want to know is when I declare a variable in one module file as the following, what's the global object this variable defined on?
var obj = {};
// In browser, this is defined on window.obj
// How about in the node?
There is one statement that global is the object used as the local global scope, however the following test code fails:
a = 1
console.log global.a
// undefined
So what is the global variable for a module?
There is in fact a global object in node; it's simply called global. You can assign properties to it and access those properties just like any other object, and you can do it across modules. However, directly accessing it (global.foo=bar in one module, baz=global.foo in another) is the only way to access it. Unqualified variable names never automatically resolve to its properties the way that, say, an unqualified variable name in a browser environment would resolve to window.somethingOrOther. In node, every module is conceptually wrapped inside an immediate function call, so unqualified names represent local variables and have module-level scope.
edit again I'm just about ready to conclude that, in a Node module, you can't get a reference to the global object. You really shouldn't need to; that's kind-of the whole point of the module mechanism, I think. You import what you need and export what you choose.
Whether there even is a global object in Node is an interesting question, I guess. I know that in Rhino, there definitely is; there's no implicit wrapper function around code fed to Rhino from the Java container. Via the Java ScriptEngine mechanism (and presumably from Mozilla APIs in "naked" Rhino) there are ways of pushing symbols into the global context to make them visible to JavaScript as global object properties.
wow this got complicated well things seem to be on the move in the Node.js world. What I wrote above was true for Node 0.6.2, but in the 0.9.0-pre build I just did there is indeed an object called "global" that behaves more or less like the global object in a browser.
The stuff below applies to browsers and Rhino and other contexts like that
You can use this in the global context. If you need a name, you can give it one.
var global = this;
var obj = "Hi!";
global.obj = "Bye"; // sets "obj"
A (somewhat) common idiom is to wrap your code in a function, to protect the global namespace.
(function( global ) {
// everything
})( this );
Caveat: I'm not a Node person so there may be some emerging idiom in that culture.
edit — it occurs to me that if Node really does wrap code from files it evaluates in a function, and it doesn't pass this into it from the global context, then there's no way to "find" it, I don't think. If you use "use strict" (and you should), it doesn't matter, because you can't really mess with the global context anyway.