I am trying to understand this keyword. but the problem is with the node environment. I am getting the expected behavior in Chrome Developer tool but the same code isn't working fine in the node environment.
When we create a var in the global context, it is supposed to be inside the global (node) or window (browser) but in node environment, it doesn't get attached to document.
I am just testing a simple 3 lines of code which works totally fine in chrome.
This is for Node environment
var color = 'red';
console.log(this.color);
console.log(global.color)
and this is for Browser which works fine
var color = 'red';
console.log(this.color);
console.log(window.color)
For the node environment, I am receiving undefined which is not expected.
Here's a software development rule: don't rely on variables sticking on this, global, or module-related objects. Scope can vary and lead to unexpected behavior and bugs. Use explicit (this|global|module.exports).varName bindings.
But if you just want to understand how things work in Node:
Code is wrapped into an IIFE when executed, setting the this value to module.exports (not global).
Access to global is persistent across modules, so if you write global.foo='foo' in a module then require it in bar.js, global.foo will be set to 'foo' in bar.js. It is discouraged to directly use global for most use cases - stick to exports and require.
According to the specs, var is not supposed to make things stick to global: there are some exceptions (see below), but you should not rely on that when writing code
Related questions:
Do let statements create properties on the global object?
Meaning of “this” in node.js modules and functions
Related
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.
I am aware of how "this" works in a browser context , and how its value changes in different scenarios like when using arrow functions how the function is invoked.
I printed out "this" in different scenarios for node js (express js, to be more specific), and it is containing a lot more data - including path names etc
My question is :
1. are the rules concerning 'this' exactly the same for node.js ?
2. could any one explain the node.js 'this' object properties or point me to a simple article.
Thank you!
There are no different rules for this in a browser vs. node.js. The rules are set by the ECMAScript standards and both the browser's Javascript implementation and the one in node.js follow the same ECMAScript standards.
What you are probably looking at is a "default" value for this in some particular context. In a browser, you are probably looking at a default value for this that may be the window object. In node.js, if you see filenames, you may be looking at a module handle as the default value for this or the global object.
To help you more specifically, we would need to see the code around where you were examining the value of this in each environment and also know whether you were running in strict mode or not.
In most cases, this is not used with just a default value, but rather a specific object that the this value is set to. For example, if you are calling something like:
obj.method();
Then, inside the implementation of method, the Javascript interpreter will set the value of this to obj. This is a part of the object oriented nature of Javascript.
This this object is whatever the global object is in that context. In node that is the process object.
I observed a difference between this in a module when running on node (tests) and a browser (production).
in tests:
the following type of code worked fine when run by tests:
export function A()
{
}
export function B()
{
// NOTE: DON'T DO THIS. prepending "this." is not needed and might break.
this.A();
}
But on production it would throw:
TypeError: Cannot read property 'A' of undefined
However this is NOT a difference between node + browser/webview but rather a difference between production code (production build of bundle.js via webpack v4) and code running in tests.
With a debug build of bundle.js this would point to the module (so an object containing exported module symbols)
eg:
{
A : [Function: A]
B : [Function: B]
}
Whereas in a release build of bundle.js this returns undefined
This difference of behaviour is caused by webpacks concatenateModules optimization.
I'm building an modular app and have a configuration file to include different modules depending on user preferences.
Normally I'd do something like
var fs = require('fs');
but I'm taking the required modules from an array, so for each require I have a script object that looks like this
{
name:'fs',
file:'fs',
isGlobal:true
}
then I'm dynamically requesting the module with
window[script.name] = require(script.file);
this works fine if I check for window.fs. However, other modules that rely on fs will call just fs.
I know window.fs and fs should both resolve, but in node-webkit, they aren't.
I'm trying to figure out a way to include the var name as a global directly.
Of course, I can't use var script.name = require(script.file); as that would set the script.name value, not a global variable.
Any suggestions on this?
You can refer to global in cross env way:
var global = new Function("return this")();
global.fs = require('fs');
Then at any point you can refer to fs module via simple global fs variable, and in browser environment global would be window.
Still, you should reconsider your approach. As above is very poor way to work with CJS style. One of the beauties of CJS is that it allows you not to rely on global scope, and you go against that, which raise issues.
Other thing, it's a bad practice to resolve paths passed to require dynamically. In modules that we'll have soon with ES6 it won't be possible, you should always use plain strings, and it's good practice to follow with CJS as well. It would be more future bulletproof if you generate script that injects plain strings to requires.
Note: it's been a few versions since I've last used node-webkit, but I think the below is still accurate. I tend to abbreviate node-webkit to nw, if that's okay. :)
I know window.fs and fs should both resolve, but in node-webkit, they aren't.
In nw, global is the global object, while each nw window has it's own window object (unless you fork nw). This may be a lil bit confusing, since using the nw devtools to create a global will actually create a property on window as expected, so it's not unreasonable to assume you can create globals the same way as in a browser. However, that's really just a side-effect of the devtools running in nw's window context.
However, code running in nw's module context does not even have access to window but can, of course, access global normally.
This is documented here. The first three paragraphs specifically deal with your issue. In short, you'll want to be sure which context your code is running in.
Node's globals meanwhile have a (brief) description here.
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.
In Node.js, if I load a module which contains code in module-scope like:
this["foo"] = function() { console.log("foo"); }
...then I appear to get a globally available function that I can call just by saying foo() from any code using the module. It can be seen as one of the printed items with Object.getOwnPropertyNames(this).
However, if I put the following in module scope instead:
function foo() { console.log("foo"); }
...then it produces a function which can similarly be called within that module as foo(), but is invisible outside of it (e.g. does not show up as one of the items with Object.getOwnPropertyNames(this)).
I gather this is a change in runtime behavior from what's done in browsers. A browser seems to poke everything into global scope by default (and for years people have had to consciously avoid this by wrapping things up in anonymous functions/etc.)
My question is whether NodeJs has some secret way of interacting with these declarations outside of the module in which they are declared BESIDES using exports.(...) = (...). Can they be enumerated somehow, or are they garbage collected as soon as they are declared if they're not called by a module export? If I knew what the name of such a function was going to be in advance of loading a module...could I tell Node.js to "capture it" when it was defined?
I'm not expecting any such capabilities to be well-documented...but perhaps there's a debugger feature or other system call. One of the best pointers would be to the specific code in the Node.js project where this kind of declaration is handled, to see if there are any loopholes.
Note: In researching a little into V8 I saw that a "function definition" doesn't get added to the context. It's put into an "activation object" of the "execution context", and cannot be programmatically accessed. If you want some "light reading" I found:
http://coachwei.sys-con.com/node/676031/mobile
http://perfectionkills.com/understanding-delete/
if you fill in exports.foo = foo; at the end of your file it will be available in other files in node, assuming that you do var myFile = require('myFile.js') with the file name and you call the function via myFile.foo(); You can even rename the function for outside use in exports and set whatever you want to call the package when you use require.
BTW you can enumerate these functions just like you do on any JSON object (ie for k in ...)
This is impossible in node without more advanced reflection tools like the debugger.
The only way to do this would be to use __parent__ which was removed due to security issues and other things (hard to optimize, not standard to begin with) . When you run the script those variables become closed under the module. You can not access them elsewhere without explicitly exporting them.
This is not a bug, it's by design. It's just how node works. see this closely related question.
If this sort of reflection was available without tools like the debugger it would have been extremely hard to optimize the source code (at least the way v8 works) , meaning the answer to your question is no. Sorry.