What's the global object within a module in nodejs? - javascript

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.

Related

Altering Global Scope for dynamically loaded module in Node.js

Loading a module from a source dynamically:
var src="HERE GOES MY SOURCE"
var Module = module.constructor;
var m = new Module();
m._compile(src, 'a-path-that-does-not-exist');
Need to achieve following:
Pass some variables/functions so that they can be used inside the src script globally. Can set them in "m.foo", but want the script to use "foo" without using "module.foo". "global.foo" works, but see the point 2.
How to restrict the src script from accessing global scope?
How to restrict the src from loading other modules using require or other means.
How to restrict the src from running async operations?
All, I can think of is to wrap the script in its own function, kind of like nodejs already does for commonJS modules. This is the regular wrapper.
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
If you wrap that user code with your own wrapper and then when you call it to execute it, you can define your own values for require, module and any other semi-global symbols.
If you also put 'use strict'; as the very first line of your wrapper function (before any of the user code), then that will eliminate default assignment to the global object with just something like x = 4 because that will be an error without explicitly defining x first. If you then also make your own global object and pass it as an argument, that can keep anyone from assigning to the real global object. I don't think you can prevent implicit read access to pre-existing globals.
So, your wrapper could look like this:
(function(exports, require, module, __filename, __dirname, global) {
'use strict';
// insert user code here before evaluating it with eval()
// and getting the function which you can then call and pass the desired arguments
});
Then, when you call this function, you pass it the values you want to for all the arguments (something other than the real ones).
Note, it's hard to tell how leak-proof this type of scheme really is. Any real security should likely be run in a resource restricted VM.
Another idea, you could run in a Worker Thread which has it's own virgin set of globals. So, you do all of the above and run it in a Worker Thread.
Addressing your questions in comments:
Does the 'use strict'; need to go inside the wrapper function or outside?
It needs to be the first line of code inside the wrapper function, right before where you insert the user code. The idea is to force that function scope (where the user code lives) inside that wrapper to be in strict mode to limit some of the things it can do.
Could you explain the "I don't think you can prevent implicit read access to pre-existing globals."? If i provide my own object as global, how can the inner script access preexisting globals?
Any code, even strict mode code can access pre-existing globals without the global prefix. While you can prevent the code from creating new globals by shadowing it with your own global in the wrapper function arguments and by forcing it into strict mode, you can't prevent strict mode code from reading existing globals because they can do so without the global prefix. So, if there's a pre-existing global called "foo", then existing code can reference that like:
console.log(foo);
or
foo = 12;
If there is no foo in a closer scope, the interpreter will find the foo on the global object and use that.
Note that strict mode prevents the automatic creation of a new global with something like:
greeting = "happy birthday"
Could you elaborate more no "resource restricted VM"?
I was talking about real hardware/OS level VMs that allow you to fully control what resources a process may use (disk access, sockets, memory, hardware, etc...). It's essentially a virtual computer environment separate from any other VMs on the same system. This is a more rigorous level of control.
WorkerThread is a very interesting concept. will take a look! My understanding was that WorkerThreads provide memory isolation and the only way to share data is by sending messages (effectively creating copies)?
Yes, Worker Threads provide pretty good isolation as they start up a whole new JS engine and have their own globals. They can shared ArrayBuffers in certain ways (if you choose to do that), but normal JS variables are not accessible across thread boundaries. They would normally communicate via messaging (which is automatically synchronized through the event queue), but you could also communicate via sockets if you wanted.

How to get pointer to a local variable in Javascript?

Let say I know that a variable is called "myVar", it is declared in a self calling function
(function (){
var myVar=0;
setInterval(function(){
console.log(myVar++);
}, 3000);
})();
But I don't know where this function is called, and don't want to reverse engineer tons of JS. I want to find a reference to this variable so I can display it in console something like window.rootObject.subObject.myVar . I tried to make a function that does recursive seek for key from the window object, but it does a stackoverflow, certainly because of circular references (an object contain reference to its containing object).
Is there any simple way to find where is this object ?
Edit : the original question was about finding a var in global space having just its name, without knowing if it was descendent of window object or stored in EnvironementRecord. The sample code I provided was misleading, so I edited the question and accepted an answer to make it usefull.
myVar in your updated example doesn't "belong" to any object you can get a reference to. In specification terms, it belongs to the EnvironmentRecord for the variable environment of the execution context for the call to the anonymous function, but there's no way for you to get a direct access to that object (which may or may not literally exist at runtime at all, depending on how the JavaScript engine being used is implemented).
You seem to believe that all objects (even specification-only objects like environment records) are in a tree and are acessible following a path of references from some root object and so are "discoverable" somehow in code. That's understandable, but it's not the case. Certainly the JavaScript engine has trees like that for garbage collection purposes (for objects that actually get created at runtime), but no, there's no root from which everything can be discovered that you can access in code.
Locally scoped variables really are locally scoped. They are not accessible outside that scope at all. They are not properties that can be accessed through the window object.
If you want to debug code using the variable, set a breakpoint (e.g. by adding a debugger statement) inside the function to which the variable is scoped.

What is global.isProd?

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.

`this` in global scope in ECMAScript 6

I've tried looking in the ES6 draft myself, but I'm not sure where to look:
Can someone tell me if this in ES6 necessarily refers to the global object? Also, will this object have same members as the global scope?
If you could answer for ES5 that would be helpful as well.
I know this in global scope refers to the global object in the browser and in most other ES environments, like Node. I just want to know if that's the defined behavior by the spec or if that's extended behavior that implementers have added (and if this behavior will continue in ES6 implementations). In addition, is the global object always the same thing as the global scope? Or are there distinctions?
Update - Why I want to know: I am basically trying to figure out how to get the global object reliably in ES5 & 6. I can't rely on window because that's specific to the browser, nor can I rely on global because that's specific to environments like Node. I know this in Node can refer to module in module scope, but I think it still refers to global in global scope. I want a cross-environment ES5 & 6 compliant way to get the global object (if possible). It seems like in all the environments I know of this in global scope does that, but I want to know if it's part of the actual spec (and so reliable across any environment that I may not be familiar with).
I also need to know if the global scope and the global object are the same thing by the spec. In other words will all variables in global scope be the same as globalobject.variable_name?
Update 2 - What I'm trying to do:
I have developed some ES6 shims for ES5 environments. I want to know the best way to (1) check to see if the ES6 built-ins already exist so that they can be used when possible instead of my shims, and (2) add my shims to the global scope if the built-ins do not already exist.
Currently I'm following this pattern:
(function() {
// Indirect eval to run in global scope.
// (We get whatever "this" is in global scope, hoping that it's the global object...
// Whether this line does what I want it to is the crux of my question.)
var global = (0, eval)('this');
// If Symbol does not already exist in global scope,
if (!global.Symbol)
// Then add Symbol to global scope.
global.Symbol = (function() {
// ...
// Return my Symbol shim
})();
})();
There are some other possibilities for (1), but at the end of the day I need a way to add something to global scope without using var in global scope (because that would override the built-ins before I can check for them, due to var hoisting [at least in the naive case, perhaps I could indirect eval a var statement as well?]). I want my code to be able to run in strict mode, so that compounds the problem.
I have discovered that, by the ES5 spec, indirect eval executes code in global scope. So I am at least able to do that. My questions are if I get this in global scope, (1) Will checking the properties of that object let me know if a built-in already exists in global scope? and (2) Will adding properties to that object allow me to add variables to global scope?
Yes, this in global scope will continue to refer to the global object in ES6. (Generally, ES6 is supposed to be fully backwards compatible, i.e. any code that was guaranteed to work in ES5 should also work in ES6).
The notion of "global scope", however, will no longer be identical with the global object in ES6. It introduces new declaration forms that are lexically scoped (let, const, class, module, and a few more). The conclusion at the last meeting was that none of these will appear as properties of the global object. There is a variety of technical and methodological reasons for that, but the bottom line is that it is best to avoid using the global object directly altogether (this has always been true, but is even more so in ES6).
Is there something specific you need the global object for?
Mostly yes.
Passing this in any non-object (or non-set this) will refer to the global object:
(function( global ){ /* do stuff! */ }(this));
This behavior is intended to stay in ES6 (for understandable backward compatibility issues). And that's how most of multiplatform (Browser/Node) plugins I know of are accessing the global object. For example: https://github.com/documentcloud/underscore/blob/master/underscore.js#L12
Although, it's true that plugin on the server only access this as being module (which is exported). But, that's what you want in node. Your global space isn't cleaned up ever (except if done manually, or on server restart). So it's shared between all client connections; assigning anything to the global space is really not a good idea.
The only notable difference in how this is handled between javascript "version" is in strict mode, where it will throw an error is if null or undefined is passed to call or apply or bind (in the position of the this value). In un-strict mode, this was only coerced to the global object.
"use strict";
foo.apply(null); // Throw error
Hope this help!

What are some of the problems of "Implied Global variables"?

JavaScript: The Good Parts defines these kinds of declarations as bad:
foo = value;
The book says "JavaScript’s policy of making forgotten variables global creates
bugs that can be very difficult to find."
What are some of the problems of these implied global variables other than the usual dangers of typical global variables?
As discussed in the comments on this answer, setting certain values can have unexpected consequences.
In Javascript, this is more likely because setting a global variable actually means setting a property of the window object. For instance:
function foo (input) {
top = 45;
return top * input;
}
foo(5);
This returns NaN because you can't set window.top and multiplying a window object doesn't work. Changing it to var top = 45 works.
Other values that you can't change include document. Furthermore, there are other global variables that, when set, do exciting things. For instance, setting window.status updates the browser's status bar value and window.location goes to a new location.
Finally, if you update some values, you may lose some functionality. If, for instance, you set window.frames to a string, for instance, you can't use window.frames[0] to access a frame.
Global variable make it very difficult to isolate your code, and to reuse it in new contexts.
Point #1:
If you have a Javascript object that relies on a global var. you will not be able to create several instances of this object within your app because each instance will change the value of the global thereby overwriting data the was previously written by the another instance.
(Unless of course this variable holds a value that is common to all instances - but more often than not you'll discover that such an assumption is wrong).
Point #2:
Globals make it hard to take existing pieces of code and reuse them in new apps. Suppose you have a set of functions defined in one file and you want to use them in some other file (in another app). So you extract them to a new file and have that file included in the new app. If these function rely on a global your 2nd app will fail at runtime because the global variable is not there. The dependency on globals is not visible in the code so forgetting these variables (when moving functions to new files) is a likely danger.
They're global variables, so yes, all of the "usual dangers" apply. The main thing that distinguishes them from global variables in other languages is that:
You don't explicitly declare them in a global scope. If you mistakenly omit var in a variable declaration, you've accidentally declared a global variable. JavaScript makes it a little too easy to unintentionally declare global variables; contrast this with Scheme, which raises an error if a variable is not defined in the global scope.
Global variables, at least in the browser, are aliased by window[variable_name]. This is potentially worrisome. For example, some of your code might access window['foo'] (with the intention of accessing a global variable). Then, if you accidentally type foo instead of var foo elsewhere in the program, you have declared a reference to window['foo'], which you meant to keep separate.
One issue is that you may be trampling on already defined variables and not know it, causing weird side effects in other parts of the code that can be a bear to track down.
Another is that it is just sloppy code. You should not be creating variable with more scope than they need since at the very least it keeps more variables in memory and at worst it can create data scenarios you didn't intend.
The bottom line is that when you do that you don't know for sure that you are not messing up other functions that use a global variable of the same name. Sometimes it isn't even your fault, a lazy programmer of another plugin left something global that was meant to have scope inside of a function. So it is a very practical safeguard for writing better and less buggy code.
The problems of typical global variables is that they are, well, global - there is no scope to enclose them, and any code that you are executing / interacting with (such as a library that you call down the road) could modify the variable without a warning.
However, these problems are compounded in Javascript by two things:
You can define a global variable anywhere - the only requirement for that is to forget the var keyword.
It is extremely easy to define a global variable when you had no intent to do so. That is the problem that "implied" globals have over "typical" globals - you will create them without even knowing you did.
In a reasonably-designed language that includes truly global variables (ok, so not that reasonably-designed), you would have a limited handful of places to define globals, and it would require a special keyword to do so.

Categories