Declare a nodejs const from a variable? - node.js

Is it possible to programmatically declare a nodejs const from a variable (string?)
let myConsts = ["const1","const2","const3"];
myConsts.forEach(function(label){
defineConst(label,"value"); // I need this function
})
defineConst should define a const, something like the PHP "define" function, but for nodejs

No, you can't really do that in Javascript. For a bit, I thought maybe you could hack it with eval() which is pretty much always the wrong way to solve a programming problem, but even eval() won't introduce a new const variable to the current scope. It will introduce a new var variable to the current scope as in this:
// dynamic variable name
let varName = "test";
// create variable in the current scope
eval("var " + varName + " = 4;");
// see if that variable exists and has the expected value
console.log(test);
But, alas you can't do this with const. You can read more about why here: Define const variable using eval().
Whatever programming problem you are trying to solve can likely be solved in a much better way since you really shouldn't be introducing dynamically named local variables. It's much better to use something like a Map object or a regular object with dynamically named properties in order to keep track of values with dynamic names to them.
If you shared the actual programming problem you're trying to solve (rather than your attempted solution), we could advise further on the best code for that particular problem.
Here's an example of the ability to store dynamically named properties on an object:
let base = {};
// dynamic property name (any string value in this variable)
let varName = "test";
// set property value with dynamic property name
base[varName] = "Hello";
// can reference it either way
console.log(base[varName]);
console.log(base.test);
Or, it can be done using a Map object:
let base = new Map();
// dynamic Map element key (any string value in this variable)
let varName = "test";
// set Map element with dynamic key
base.set(varName, "Hello");
// can reference it either way by the key
console.log(base.get(varName));
console.log(base.get("test"));

Related

ExpandoObject - why a Type behaves differently?

One for the gurus, please convince me/us what is going on.
List<ExpandoObject> peopleList = new List<ExpandoObject>();
dynamic expandoObj1 = new ExpandoObject();
expandoObj1.id = 1;
expandoObj1.first = "fred";
expandoObj1.last = "krugger";
peopleList.Add(expandoObj1);
dynamic expandoObj2 = new ExpandoObject();
expandoObj2.id = 2;
expandoObj2.first = "george";
expandoObj2.last = "benson";
peopleList.Add(expandoObj2);
//test access the props
var expObj = expandoObj1;
var name = expObj.first;
var expObj2 = peopleList[0] as dynamic;
var name2 = expObj2.first;
IDictionary<string, object> expObj3 = peopleList[0] as ExpandoObject;
var name3 = expObj3["first"];
var expObj4 = peopleList[0] as ExpandoObject;
//var name4 = expObj4.first; //THIS DOESN'T WORK - ExpandoObject does not contain a definition for 'first' etc...
In all cases, the LEFT-HAND SIDE is a System.Dynamic.ExpandoObject;
Why then, on the 4th case expObj4, i cannot access the property expObj4.first ?
ExpandoObject is a sealed class which stores data in a dictionary. It implements IDynamicMetaObjectProvider interface which provides dynamic behaviour to the classes implementing it. It also implements IDictionary interface which provides dictionary like behaviour to it. It is supposed to be checked and validated at compile time.
dynamic is a type which is not supposed to be checked by the compiler at compile time. It is checked and breaks at runtime. At compile time, a dynamic entity is assumed to support any operation. So, when you say, it is a expandoobject, the field called first does not get appended to object itself.
Check source code of expando object here
https://github.com/Microsoft/referencesource/blob/master/System.Core/Microsoft/Scripting/Actions/ExpandoObject.cs
Think of dynamic behavior like an object. You can put any type there. When you are adding to list, you are adding to list as dynamic, but the inherent type of item being added is ExpandoObject. So, you are able to cast it back to ExpandoObject.
When you say,
expandoObj1.first = "fred";
it is same as saying,
expandoObj1.Add("first", "fred");
When you used
var expObj = expandoObj1;
var name = expObj.first;
you were using expandoObject in dynamic form. So, you were able to access properties directly. When you cast it to ExpandoObject class, you were using actual ExpandoObject class which stores fields in Dictionary, so dot(.) notation does not work.
var expObj4 = peopleList[0] as ExpandoObject;
variable on left hand side is still ExpandoObject, not a dictionary. ExpandoObject exposes its members through collection search.
var name4 = expObj4.Where(t=>t.Key == "first").First().Value;
When you cast it to a dictionary, it works like a dictionary.
IDictionary<string, object> expObj3 = peopleList[0] as ExpandoObject;
var name3 = expObj3["first"];
When you cast it to a dynamic, you can access these keys like they are properties of the class.
Further reference
Dynamically adding properties to an ExpandoObject
This is because the variable expObj4 is declared as ExpandoObject and not as dynamic. This is an important difference.
Try this:
dynamic a = new ExpandoObject();
a.Name = "Test";
This compiles, but the following doesn't:
ExpandoObject a = new ExpandoObject();
a.Name = "Test";
you get this:
CS1061 'ExpandoObject' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'ExpandoObject' could be found
The variables you have that are related to this are:
expandoObj1 - dynamic
expandoObj2 - dynamic
expObj1 - dynamic
expObj2 - dynamic
expObj3 - dictionary, but you use dictionary access here, not dot-access
The magic "let's see if we can access the thing at runtime" code of the compiler only kicks in if the expression or variable is dynamic. ExpandoObject is just a type that supports this.

Haxe - use string as variable name with DynamicAccess

I am trying to use a string ('npcName') as a variable name. So far I have tried casting dialogMap into a DynamicAccess object, but it gives me the error 'Invalid array access' when I try this:
var npcName:String = 'TestNPC';
var casted = (cast Registry.dialogMap:haxe.DynamicAccess<Dynamic>);
var tempname = casted[root.npcName[0].message];
trace(tempname);
'dialogMap' is an empty map which I want to fill like so:
Registry.dialogMap['message'] = root.npcName[0].message;
How can I use npcName, a string, in the above line of code? Is there a way to transform the string into something usable? Any help would be appreciated.
The haxe.DynamicAccess doesn't have array access (like map[key]), but is an abstract type for working with anonymous structures that are intended to hold collections of objects by the string key. It is designed to work with map.get(key) and map.set(key). It is basically a nicer wrapper around Reflect.field and Reflect.setField and does some safety checks with Reflect.hasField.
var variable = "my_key";
var value = 123;
var dynamicMap = new haxe.DynamicAccess<Dynamic>();
dynamicMap.set(variable, value);
I'm noticing you are doing very much cast and dynamic, so untyped code, which is a bit of contradiction in a typed language. What is the actual type of dialogMap?
Not sure you are aware of it but, Haxe has its own maps, which are fully typed, so you don't need casts.
var map = new Map<String, Int>();
map[variable] = value;
I think this article helps understanding how to work with dynamic (untyped) objects.
Tip; for testing such small functionalities you can doodle around on the try.haxe site : http://try.haxe.org/#4B84E
Hope this helps, otherwise here is some relevant documentation:
http://api.haxe.org/haxe/DynamicAccess.html
https://haxe.org/manual/std-reflection.html
https://haxe.org/manual/types-dynamic.html
http://code.haxe.org/category/beginner/string-variable-reflection.html

How can I see my node.js variables already initiated?

I'm pretty new to node.js and I was wondering: seeing as the scope of any variable created is set to a sort of global scope, is there any way of listing out what variable names have already been initiated?
node.js variables are generally not global. The default is that any variable declared at the top level of a module is only in the module scope and does not conflict or interfere with any other modules.
Only variables explicitly assigned to the global object are actually available globally.
global.myVar = "foo";
All others are contained within a smaller scope - module scope or a function scope within a module.
So, if you have a module like this:
var x = 3;
module.exports = function() {
return x;
}
Then, the variable x is not a global variable at all. It is contained with the scope of this module. It would not conflict with a variable in any other module of the same name.
Because top level variables in a module are actually local variables within a module function wrapper and Javascript does not provide any means of iterating the local variables within a function scope, there is no way to iterate all top level variables within a module scope.
If you wanted to be able to iterate all variables in some context, then you can use a different format and put them as properties on an object.
var obj = {};
obj.x = 3;
obj.y = 5;
// list all enumerable properties of obj
for (var prop in obj) {
console.log("property: " + prop + " = ", + obj[prop]);
}
FYI, you can also use a debugger like node-inspector to view all variables declared within any given scope. You set a breakpoint in that scope and then look at the local variables present at that breakpoint.

Error while adding data to ExpandoObject like dictionary

I am trying to understand c# dynamic. I have an ExpandoObject instance assigned to dynamic variable.
I understand ExpandoObject is implementing IDictionary. But the below assignment fails.
dynamic obj = new ExpandoObject();
obj["Test"] = "TestValue";
Console.WriteLine(obj.Test);
Can someone tell me where i am going wrong?
obj.Test="TestValue";
However the above statement seems to be working fine.
To do that, you need to cast the ExpandoObject to IDictionary<string, object>.
This is normal Expando usage:
obj.Test = "TestValue";
This is string-literal (or string variable) usage:
var d = (IDictionary<string, object>)obj;
d["Test"] = "TestValue";
string s = "Test";
d[s] = "TestValue";
If the interface implementation is explicit, you need to cast to a reference of the interface in order to access the members. I'm guessing this is what has happened here.

NodeJS converting string to variable

I am trying to update the contents of a variable in nodejs with the use of a string.
In client side javascript this was done with the use of window[variable] however since there is no "window" in nodejs. I tried using "this" and "module", however all im getting is an empty object. need help thanks
Code Snippet:
var myVariable = 'Hello';
var exchangeVariable = 'myVariable';
this[exchangeVariable] = 'Hello World';
/*
myVariable should equal to 'Hello World!'
*/
Thanks!
Here's some background before I answer your question directly:
In JavaScript, objects can be either indexed by the dot notation (someObj.property) or by indexing them as you do in your example (someObj["property"])
In the browser, window is the global context that the browser evaluates your code within. Node uses a variable called global.
So, if you want to reference a variable you've defined globally:
> var someGlobalVar = "hi";
> var myLookupKey = "someGlobalVar";
> global[myLookupKey]
'hi'
However, this is generally considered very bad practice (in Node and the browser). There are a myriad of reasons for this, but I'm focusing on just one:
In Node, modules (each required file) should be treated as if they do not share global state (and in some cases, they cannot share state). I encourage you to read through the modules section of the node documentation if you are trying to share state across files.
You could create your own variables hash or array and assign the variable yourself.
var myVariable = "Hello";
var varArray = new Array()
varArray["exchangeVariable"] = myVariable;

Resources