How can I access variable C?
test = function(){
a = 1;
b = 2;
c = a+b;
return c
}
console.log(c)
Returns:
Uncaught ReferenceError: c is not defined
EDIT: Please disregard above question
To elaborate more on this. I am new to JavaScript and am stuck on a block of code that I can't get to work. I tried to simplify the problem I was having but I think that may have backfired...
Here is the full code that I am having trouble with. I need to access the variables inside of getAPIData.onload, But am getting "undefined"
What is the best way to access these values?
getData();
function getData(){
var activeMachines = [41, 44, 45]
var dict = {};
let data = activeMachines.reduce((obj, machineID) => {
var getAPIData = new XMLHttpRequest();
var url = 'http://127.0.0.1:8000/processes/apidata/' + machineID + '/';
getAPIData.open('GET', url);
getAPIData.send();
getAPIData.onload = function(){
var APIData = JSON.parse(getAPIData.responseText);
dict['temp' + machineID] = APIData[0].tempData;
dict['humid' + machineID] = APIData[0].humidData;
timeValue = String((APIData[0].dateTime));
dict['time' + machineID] = new Date(timeValue);
}
temp = dict['temp'+ machineID];
humidity = dict['humid'+ machineID];
time = dict['time'+ machineID];
obj['machine_'+ machineID] = {temp, humidity, time}
return obj
}, {})
console.log(data);
}
This returns the data dictionary, but all of the values are undefined.
Any help is appreciated.
I will read more into JavaScript scope as others have suggested.
c is a global variable that is created by calling the anonymous function assigned to the global variable test. However, you never call the anonymous function assigned to test, therefore the variable never gets created.
So, the obvious solution is to just call the anonymous function assigned to test:
test();
console.log(c);
// 3
However, this is a really bad idea. Global variables are evil, evil, evil. They tie together disparate parts of your program into a giant tangled mess: since they are accessible from everywhere, you have to assume that they may be accessed from everywhere. And changing them in one place may change the behavior of some completely unrelated code in a completely different part of your code.
Actually, it is even worse: since they are global, changing them in one place may not only change the behavior of some completely unrelated code in a completely different part of your code, it may even change the behavior of some completely unrelated code in a completely separate part of someone else's code!
The only way to avoid this, would be to invent unique names for every global variable, otherwise they are going to clash. In fact, you would need to invent a unique name for every global variable that was ever written, is written, and will be written by every programmer in the universe for all eternity!
But actually, there is no need for global variables here at all, since you actually return the value of c in your anonymous function. You can make those variables local to your function and simply use the return value. In fact, you don't even need variables at all, since you never "vary" them, you can make them constants instead.
Note: in modern ECMAScript, you should always prefer consts (unless you have a very good reason to use a let) and never use var or even worse (like you are doing here) implicit global variable definition. So, your code, in modern ECMAScript, should look like this:
const test = function () {
const a = 1,
b = 2,
c = a + b;
return c;
}
console.log(test());
Also, since you don't give your function a name and don't rely on dynamic scoping of this, you can use arrow function literal syntax:
const test = () => {
const a = 1,
b = 2,
c = a + b;
return c;
}
console.log(test());
or just give your function a name:
function test() {
const a = 1,
b = 2,
c = a + b;
return c;
}
console.log(test());
the variables A B and C are of use locally within the function, but it returns the value of C, with just calling the function returns the value, as it says - charlietfl console.log(test()), you can call it that way or:
var c = test ();
alert(c) or console.log (c);
Now you can use the name varibale "c" outside the function.
Related
The actual function I provided in this example is not the problem. I just want to know how to save the values of variables after using them as parameters in functions. I was trying to make a very simple function that switches the value of two variables. I know how to do this without a function but wanted to generalize the solution with a function.
I tried writing the following code,
let a = 3;
let b = 4;
const switchItems = (c,d) => {
var temp = c;
c = d;
d = temp;
}
switchItems(a,b);
I expected a to be 4 and b to be 3 but the variables stay the same as they were before the function.
I don't care how to do this with the specific swap function I used, I just want to know how to change a global variable inside a function without referencing it.
You can't.
Javascript's calling semantics mean that the function receives a copy of the reference; if you change it, you're only changing the internal reference. The exception is that you can change values stored in an outer scope (such as the global scope.) But then the values you pass to it are irrelevant.
What you can do, if you like, is to return a swapped copy of the parameter array:
let [b, a] = swap(a, b);
But there's no reason to create such a function, since this is less simple than
let [b, a] = [a, b];
Update
From the question edit:
I just want to know how to change a global variable inside a function without referencing it.
It depends upon what you mean by "change" here. You can assign it a new reference, but only if you have its name, and the parameters are then irrelevant. If you want to change its internals, that's simple:
const foo = {bar: 42}
function baz(x) {
x.bar += 1;
}
baz(foo);
foo //=> {bar: 42}
But it seems you want something more than that, and that's not available.
Consider this code
'use strict';
var factory = () => script => eval(script);
var closure = factory();
closure('var v = 0');
var val = closure('typeof v');
console.log(val);
This is my attempt to achieve it. I want to create a closure and then to allow users to create a new local variable in that closure. Is that even possible?
I somewhere read that "native function 'eval' can even create a new variable in the local execution context.". So, why doesn't it work in my example? My guess is that it is because the function finished executin and number of variables after function ends cannot be changed, but I am not sure.
My example script creates a closure and tries to declare and initialize new variable v in that closure and assign number 0 to it. I expected that the result of typeof v should be number, but it is actually undefined.
So, I have two questions:
Why doesn't it creates the variable v as expected
How to actually achieve that (what would be the working example)?
Well it is locally scoped, but a bit too local
var factory = () =>{
return script =>{
//this is the scope. you cant access any variables outside of this.
eval(script);
};
//you want to eval here, which is impossible
};
You could do very hacky scope stuff to work around this ( store all variables in context):
var factory = (context={}) => script =>{ with(context){ return eval(script); }};
You need to initialize all local variables on creation:
var exec=factory({v:0, b:undefined});// note that you need to set a value explicitly {v,b} wont worm
and then it works as expected:
console.log(
exec("v"),//0
exec("v=2"),//2
exec("v"),//2
typeof v //undefined
);
http://jsbin.com/xibozurizi/edit?console
If you dont want to go that deep, the only thing you could do would be concatenating the strings:
var factory = code => concat => (eval(code),res=eval(concat),code+=concat,res);
// or shorter / more buggy
var factory = code => concat => eval(code+=";"+concat);
var exec=factory("var a=1;");
console.log(
exec("a;"),//1
exec("var b=a+1"),
exec("b"),//2
tyepof a, typeof b //undefined
);
http://jsbin.com/midawahobi/edit?console
The upper code will run the strings multiple times, which is may not wanted. Another approach:
var factory=code=>({
code,
run(c){
return eval(this.code+";"+c);
},
add(c){ this.code+=";"+c}
});
So you can do
var exec=factory("var a='hello'");
exec.run("alert(a)")//alerts hello
exec.add("var b=a+' world'");
console.log(exec.code,exec.run("b"));//hello world, the upper alert isnt run again
http://jsbin.com/lihezuwaxo/edit?console
note that evaling is always a bad idea...
Your call to eval() does create a new variable, and it does so in the local execution context of the call. That context is inside that function, so it doesn't effect the context outside, where you call closure().
Generally eval() is to be strictly avoided. It makes optimization hard (or impossible) so functions that use it will be ignored by the optimizer. There are some rare circumstances in which it's useful, but declaring a new local variable doesn't seem like one of them.
You can do like that
var factory = () => script => eval(script);
var closure = factory();
var v;
closure('v=20')
I feel weird about this question.
Somehow I feel the answer should be quite obvious. Yet it isn't.
In Java Script, considering that inside another object's scope I can directly access a variable in any surrounding scope and mutate the crap out of it. Why would I choose to pass those variable as arguments to a function instead of referencing directly? What's the best practice? When would one choose to pass something as arguments instead of using the direct reference method? Is it just a matter of if I want a reference to the actual var or just its value, analogous to the kind of system employed in the C-family of languages?
For example:
Why would I do this:
var foo= 1;
var bar = function(foo) {
return foo + 2;
}
Instead of:
var foo = 1;
var bar = function() {
return foo + 2;
}
This makes a bit sense:
var bar = function(foo) {
return foo + 2;
}
foo = bar(42); // foo = 44
The use depends on the type of problem you want to solve
The global range variables are dealt with when the value can be reused in other operations
let Person = (() => {
let Person = function() {
this.name = null;
}
/**
* You can also occupy private variables so that you
* can not access them externally to your logic
*/
let privateVariable = null;
Person.prototype = {
setName: (name) => {
this.name = name;
}, getName: () => {
return this.name;
}
}
return Person;
})();
// Use:
person = new Person();
person.setName('Alan');
console.log(person.getName()); // log: Alan
On the other hand there are when you occupy variables of local scope
The local range variables are dealt with when you will not occupy that value in subsequent operations. It is a very common use in libraries
let Library = (() => {
/*
* When dealing with this type of programming all the logic
* of your program falls into the functions but when
* you use an anonymous function like this
* you can define variables to support you
*
**/
let CONSTANT = 2;
return {
operation1: (param1) => {
return param1 * 2;
},
operation2: (param1) => {
return param1 * CONSTANT;
}
}
})();
// Use:
let result = Library.operation1(42);
console.log(result); // 84
I hope this works for you, regards
I can directly access a variable in any surrounding scope and mutate the crap out of it.
Yes, and that's one of the things one wants to protect against.
Why would I choose to pass those variable as arguments to a function instead of referencing directly?
Reusability, basically. By passing the value explicitly, one can a) also pass other values than that of the variable in scope b) easily refactor the code by putting the function declaration in a different scope, without having to rewrite it.
Also, dependency injection: even when you expect the variable to be a constant that you want to reference, making it a parameter allows injecting mocks etc.
What's the best practice?
To choose wisely :-) The above advantages of putting everything in parameters are met by the disadvantage of having everything in parameters - long parameter lists and having to pass everything around have quite some overhead. So when you don't absolutely need to reuse the function, and don't need to inject any other values (e.g. in case of a given constant), there's no reason to do it.
Let's say we have a function that looks like this:
const fn = () => x;
This function should return the value of x where x is available in the global scope. Initially this is undefined but if we define x:
const x = 42;
Then we can expect fn to return 42.
Now let's say we wanted to render fn as a string. In JavaScript we have toString for this purpose. However let's also say we wanted to eventually execute fn in a new context (i.e. using eval) and so any global references it uses should be internalized either before or during our call to toString.
How can we make x a local variable whose value reflects the global value of x at the time we convert fn to a string? Assume we cannot know x is named x. That said we can assume the variables are contained in the same module.
If you want lock certain variables while converting function to string, you have to pass that variables along the stringified function.
It could be implemented like this (written with types -- typescript notation)
const prepareForEval =
(fn: Function, variablesToLock: { [varName: string]: any }): string => {
const stringifiedVariables = Object.keys(variablesToLock)
.map(varName => `var ${varName}=${JSON.stringify(variablesToLock[varName])};`);
return stringifiedVariables.join("") + fn.toString();
}
Then use it like this
const stringifiedFunction = prepareForEval(someFunction, { x: x, y: y })
// you can even simplify declaration of object, in ES6 you simply write
const stringifiedFunction = prepareForEval(someFunction, { x, y })
// all variables you write into curly braces will be stringified
// and therefor "locked" in time you call prepareForEval()
Any eval will declare stringified variables and funtion in place, where it was executed. This could be problem, you might redeclare some variable to new, unknown value, you must know the name of stringified function to be able to call it or it can produce an error, if you redeclare already declared const variable.
To overcome that issue, you shall implement the stringified function as immediatelly executed anonymous function with its own scope, like
const prepareForEval =
(fn: Function, variablesToLock: { [varName: string]: any }): string => {
const stringifiedVariables = Object.keys(variablesToLock)
.map(varName => `var ${varName}=${JSON.stringify(variablesToLock[varName])};`);
return `
var ${fn.name} = (function() {
${stringifiedVariables.join("")}
return ${fn.toString()};
)();
`;
}
this modification will declare function and variables in separate scope and then it will assign that function to fn.name constant. The variables will not polute the scope, where you eval, it will just declare new fn.name variable and this new variable will be set to deserialized function.
We cannot know x is named x. This is the central piece of this puzzle and is therefore bolded in the original question. While it would be nice if we had a simpler solution, it does seem a proper answer here comes down to implementing some kind of parser or AST traversal.
Why is this necessary? While we can make the assumption that x lives in a module as a global (it's necessarily shared between functions), we cannot assume it has a known name. So then we need some way of extracting x (or all globals really) from our module and then providing it as context when we eventually eval.
N.B.: providing known variables as context is trivial. Several answers here seem to assume that's a difficult problem but in fact it's quite easy to do with eval; simply prepend the context as a string.
So then what's the correct answer here? If we were to use an AST (Acorn may be a viable starting point, for instance) we could examine the module and programmatically extract all the globals therein. This includes x or any other variable that might be shared between our functions; we can even inspect the functions to determine which variables are necessary for their execution.
Again the hope in asking this question originally was to distill a simpler solution or uncover prior art that might be adapted to fit our needs. Ultimately my answer and the answer I'm accepting comes down to the nontrivial task of parsing and extracting globals from a JavaScript module; there doesn't appear to be a simple way. I think this is a fair answer if not a practical one for us to implement today. (We will however address this later as our project grows.)
You can use OR operator || to concatenate current value of x to fn.toString() call
const fn = () => x;
const x = 42;
const _fn = `${fn.toString()} || ${x}`;
console.log(_fn, eval(_fn)());
Global variables can be made local (private) with closures. w3Schools
function myFunction() {
var a = 4;
return a * a;
}
Thanks to guest271314, I now see what you want.
This is his code, just little improved:
const stringifiedFn = `
(function() {
const _a = (${fn.toString()})();
return _a !== undefined ? _a : ${JSON.stringify(fn())};
})();
`;
this code will execute fn in context, where you eval, and if fn in that context returns undefined, it returns the output of fn in context, where it was stringified.
All credit goes to guest271314
do you mean this? only answer can post code, so I use answer
var x = 42
function fn() {
return x
}
(() => {
var x = 56
var localFn = eval('"use strict";(' + fn.toString()+')')
console.log(localFn)
console.log(localFn())
})()
why rename to localFn, if you use var fn=xx in this scope the outer fn never exists!
in nodejs? refer nodejs vm
passing context? you can not save js context unless you maintain your own scope like angularjs
If you're already "going there" by using eval() to execute fn() in the new context, then why not define the function itself using eval()?
eval('const fn = () => ' + x + ';')
I am now in the process of removing most globals from my code by enclosing everything in a function, turning the globals into "pseudo globals," that are all accessible from anywhere inside that function block.
(function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
(technically this is only for my "release version", where I append all my files together into a single file and surround them with the above....my dev version still has typically one global per js file)
This all works great except for one thing...there is one important place where I need to access some of these "globals" by string name. Previously, I could have done this:
var name = "g";
alert (window[name]);
and it did the same as
alert(g);
Now -- from inside the block -- I would like to do the same, on my pseudo-globals. But I can't, since they are no longer members of any parent object ("window"), even though are in scope.
Any way to access them by string?
Thanks...
Basically no, as answered indirectly by this question: Javascript equivalent of Python's locals()?
Your only real option would be to use eval, which is usually not a good or even safe idea, as described in this question: Why is using the JavaScript eval function a bad idea?
If the string name of those variables really and truly is defined in a safe way (e.g. not through user-input or anything), then I would recommend just using eval. Just be sure to think really long and hard about this and whether there is not perhaps a better way to do this.
You can name the function you are using to wrap the entire code.
Then set the "global" variable as a member of that function (remember functions are objects in JavaScript).
Then, you can access the variable exactly as you did before....just use the name of the function instead of "window".
It would look something like this:
var myApp = new (function myApp(){
this.g = "world";
//in the same scope
alert ( "Hello " + this["g"]);
})();
//outside
alert ( "Hello " + myApp["g"]);
if you want to access something in a global scope, you have to put something out there. in your case it's probably an object which references your closed off function.
var obj1 = new (function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
you can add a method or property as a getter for g. if the value of g isn't constant you might do like
this.getG = function() { return g; };
you can work from there to access items by name, like
alert( obj1["getG"]() );
alert( window["obj1"]["getG"]() );