javascript running in nodejs v.s. web browser, about variable scope - javascript

In browser, diffrent javascript file share one scope:
a.js:
var a=1; //we add "var", so we not intent it be a global var.
b.js:
console.log(a) //a=1, but b.js can also see this var!
In nodejs:
a.js ....
b.js ....
console.log(a)// b.js cannot see the var, declare by "var" keywork
is there any doc say those difference ?

that is correct. All of the files are loaded in the browser combined but in node.js uses modules per file so basically to combine the files from b.js you need to do
var a=require('a.js');
then your variable will be in a.a
for this to work you need to exports.a=1 in a.js
Be sure to keep in your mind that while javascript is the same language, different programming techniques are used in frontend and backend.

nodejs encapsulates scope per file, sort of like ruby. If you want to share variables you should export them:
file1.js:
exports.a = 5;
file2.js:
exports.b = 6;
main.js:
var file1 = require('./file1.js');
var file2 = require('./file2.js');
console.log(file1.a); // 5
console.log(file2.b); // 6
Anything you export in a file by assigning to export.variablename = yourObject; will be accessible when you include the file from elsewhere: var exportedStuff = require('./file.js') would let you access yourObject at exportedStuff.variablename.
The reason for all of this is to force you to be more organized about how you write your code. As opposed to just slapping global variables around everywhere, it forces you to organize your code into modules, and also gives you the ability to emulate private scoping in an easier way than on the web.
In the web when you omit var, and just have varname = 5 then when variable does not already exist, it's the same as saying window.varname. This is NOT the case in nodejs. In Node if you want to use global you must do global.varname = 5

Related

Node.js run file inside another file

this is my current code
function includeClass(classname, ctx) {
var txt = fs.readFileSync("socket.io/" + classname + ".js");
return txt;
}
//define globals here
var _PLAYERS = {};
var _SPAWNPOINTS = [];
vm.runInThisContext(includeClass("vector"));
vm.runInThisContext(includeClass("class"));
vm.runInThisContext(includeClass("connectionHandler"));
vm.runInThisContext(includeClass("game"));
But that way, class.js file can't access variables from global scope or other files. because now i get errors like, _PLAYERS or require is undefined. I've tried eval() too, but it didn't do anything at all.
How can I run these js scripts in main script so they get interpreted as 1 whole?
https://nodejs.org/api/vm.html#vm_vm_runinthiscontext_code_options:
Running code does not have access to local scope, but does have access to the current global object.
Your _PLAYERS variable is not truly global, it is local to your script. As well as some other variables (like require) which are also in the module scope.
You can try to assign the needed variables to global object, however, I am not well aware what side effects and complications may follow.

Is it possible to 'require' a object in Node.js that can access the importing files global scope?

I've done a fair bit of searching around to see if this is possible. So far, from what I understand, it isn't.
In my main.js file, I have this code:
var commands = require('./commands.js');
It imports an object from commands.js, that is set out in the following manner:
module.exports = {
var1: "something" + somevar,
var2: "something" + someothervar,
...
}
This allows me to access the object commands from within the main.js file as though it was just declaed within main.js itself. However, I run into a problem when I want the exporting commands.js file to be able to access main.js's global variable scope. Say that somevar and someothervar are part of main.js's global scope, when I want to get a value from commands I don't want them to be 'undefined'.
Long story short, I want to treat this imported object exactly as though it was just declared in main.js.
I'm trying to code a chatbot for Discord, and for the sake of tidyness and organization, I wanted to have the list of functions it can use separate from the code that processes them. Is this worth the effort? Is there a better way to do this? I'm also juggling around SQL at the moment, trying to design the most modular/customizable program possible.
This is not possible , when you export a module all the variables would have been resolved .
You will always get the object with all the expressions evaluated when you import
I would suggest make var1 and var2 as functions
module.exports = {
var1: function(someVar){ return "something" + someVar},
var2: function(someothervar) {return "something" + someothervar},
...
}
Now when you import it in main.js ,pass your somevar and someothervar

Package-scoped variable

Is there any way to define a variable to be used only in a package, without exporting it to the client or the server? For example,
//In /packages/fooPackage/foo.js
packageScopedValue = 'foo';
//In /packages/fooPackage/package.js
api.export('packageScopedValue', 'package');
//In /packages/fooPackage/other.js
doStuffWith(packageScopedValue);
Without polluting any other scope?
A package-scoped var is any global that you don't export. If I say foo = "RAAARR" (no var) in pack.js and console.log(foo) in pack2.js, you'll see RAAARR appear. That's because meteor essentially concatenates each js file in the order you give it & then wraps it in an IFFE.
Note that load order does matter!!
api.addFiles(['pack.js', 'pack2.js'], 'client'); //works
api.addFiles(['pack2.js', 'pack.js'], 'client'); //undefined

How to make a variable global from inside a function [duplicate]

I need a few global variables that I need in all .js files.
For example, consider the following 4 files:
global.js
js1.js
js2.js
js3.js
Is there a way that I can declare 3 global variables in global.js and access them in any of the other 3 .js files considering I load all the above 4 files into a HTML document?
Can someone please tell me if this is possible or is there a work around to achieve this?
Just define your variables in global.js outside a function scope:
// global.js
var global1 = "I'm a global!";
var global2 = "So am I!";
// other js-file
function testGlobal () {
alert(global1);
}
To make sure that this works you have to include/link to global.js before you try to access any variables defined in that file:
<html>
<head>
<!-- Include global.js first -->
<script src="/YOUR_PATH/global.js" type="text/javascript"></script>
<!-- Now we can reference variables, objects, functions etc.
defined in global.js -->
<script src="/YOUR_PATH/otherJsFile.js" type="text/javascript"></script>
</head>
[...]
</html>
You could, of course, link in the script tags just before the closing <body>-tag if you do not want the load of js-files to interrupt the initial page load.
The recommended approach is:
window.greeting = "Hello World!"
You can then access it within any function:
function foo() {
alert(greeting); // Hello World!
alert(window["greeting"]); // Hello World!
alert(window.greeting); // Hello World! (recommended)
}
This approach is preferred for two reasons.
The intent is explicit. The use of the var keyword can easily lead to declaring global vars that were intended to be local or vice versa. This sort of variable scoping is a point of confusion for a lot of Javascript developers. So as a general rule, I make sure all variable declarations are preceded with the keyword var or the prefix window.
You standardize this syntax for reading the variables this way as well which means that a locally scoped var doesn't clobber the global var or vice versa. For example what happens here is ambiguous:
greeting = "Aloha";
function foo() {
greeting = "Hello"; // overrides global!
}
function bar(greeting) {
alert(greeting);
}
foo();
bar("Howdy"); // does it alert "Hello" or "Howdy" ?
However, this is much cleaner and less error prone (you don't really need to remember all the variable scoping rules):
function foo() {
window.greeting = "Hello";
}
function bar(greeting) {
alert(greeting);
}
foo();
bar("Howdy"); // alerts "Howdy"
Have you tried it?
If you do:
var HI = 'Hello World';
In global.js. And then do:
alert(HI);
In js1.js it will alert it fine. You just have to include global.js prior to the rest in the HTML document.
The only catch is that you have to declare it in the window's scope (not inside any functions).
You could just nix the var part and create them that way, but it's not good practice.
As mentioned above, there are issues with using the top-most scope in your script file. Here is another issue: The script file might be run from a context that is not the global context in some run-time environment.
It has been proposed to assign the global to window directly. But that is also run-time dependent and does not work in Node etc. It goes to show that portable global variable management needs some careful consideration and extra effort. Maybe they will fix it in future ECMS versions!
For now, I would recommend something like this to support proper global management for all run-time environments:
/**
* Exports the given object into the global context.
*/
var exportGlobal = function(name, object) {
if (typeof(global) !== "undefined") {
// Node.js
global[name] = object;
}
else if (typeof(window) !== "undefined") {
// JS with GUI (usually browser)
window[name] = object;
}
else {
throw new Error("Unkown run-time environment. Currently only browsers and Node.js are supported.");
}
};
// export exportGlobal itself
exportGlobal("exportGlobal", exportGlobal);
// create a new global namespace
exportGlobal("someothernamespace", {});
It's a bit more typing, but it makes your global variable management future-proof.
Disclaimer: Part of this idea came to me when looking at previous versions of stacktrace.js.
I reckon, one can also use Webpack or other tools to get more reliable and less hackish detection of the run-time environment.
Yes you can access them. You should declare them in 'public space' (outside any functions) as:
var globalvar1 = 'value';
You can access them later on, also in other files.

why does this object declaration work in node.js and how to declare a static variable?

i have seen this code :
var myNet = require ("net");
and in some function:
function foo (x,y) {
var myNewNet = new myNet();
myNewNet.createServer(x,y);
}
why does the code above create a new object? what is the mechanism stands behind that?
one more question, how do i create a static var in node.js, for example a id number that has to be unique.
i came with this option for static variable:
var id =0;
and put it on the global scope, is it ok?
The require statement basically is like an import; it takes an external library and makes it available in your code.
If you ever look in an external module, you will notice that it's just normal node.js js code. It has EXPORT statements in it. Those statements are what gets made available when you require something. Check out http://howtonode.org/creating-custom-modules
There is a GLOBAL keyword in node.js you can use to make something global
GLOBAL.IP_ADDRESS = "..."
As #Raynos says, it's not usually a good idea to do that, so another options is to export a constant from a module, so you can create a module and do
exports.STATIC_CONSTANT = "";
and then once you import the module you can do
var mod = require('mymodule');
mod.STATIC_CONSTANT;
EDIT, to answer you comment, the line
var myNet = require("net")
causes myNet to be whatever the net module exports. It must be exporting a function, so
var newNet = new myNet()
creates a new instance of the net object. From there
myNewNet.createServer()
is just invoking a method on the object you just created.

Categories