I have some code like this:
//app.js
var r=require("./second.js");
var a=1;
r.second(a);
console.log(a);
And my second.js looks like this:
//second.js
module.exports.change=function(a){
a=2;
}
Currently console.log(a) only show 1, I did a bit of research saying I can't pass it as a variable because variable is passed as value. I thought about using global.a. However, it doesn't work too because a is stored as a module variable, not a global variable, and I don't want to set it as a global variable.
How do I solve it?
The main answer is that you can't do it exactly as you asked. A variable defined as you have a in app.js is private to the scope of a and only other code within app.js can modify it.
There are a number of other ways you can structure things such that module B can modify something in module A or cause something to be modified in module A.
Global
You can make a global. This is not recommended for a variety of reasons. But you could make it a property of the global object by changing your declaration of a to:
global.a = 1;
Then, in module B, you can directly set:
global.a = 2;
Pass and Return
You can pass a into a function in module B and have that function return a new value that you assign back into a.
const b = require('moduleB');
let a = 1;
a = b.someFunction(a);
console.log(a); // 2
Then, inside of moduleB, you can modify propertys on a directly:
// inside of moduleB
module.exports.someFunction = function(a) {
return ++a;
};
Put value in object and pass reference to object
Rather than storing the value in a simple variable, you can store it as a property of an object an you can then pass a reference to that object. Objects in Javascript are passed by ptr so some other function you pass the object to can modify its properties directly.
const b = require('moduleB');
let a = {someProperty: 1};
b.someFunction(a);
console.log(a.someProperty); // 2
Then, inside of moduleB, you can modify propertys on a directly:
// inside of moduleB
module.exports.someFunction = function(obj) {
obj.someProperty = 2;
};
Initially, there isn't any function that is called second. Your module exposes a function called change. Then when you pass a value to function this value is copied and whatever change you do affects only the copy. So passing the value of a, the change affects only the copy of this value and not the original one. What could you do is to pass an object. This time a copy of the reference to the object is passed. So any change you make is reflected back to the original object (it's like pointers in C and C++).
In terms of code, the changes you should make are the following:
// You could make the method more dynamical passing the value you want a get.
module.exports.change = function(obj, value){
obj.a = value;
}
Last you should call it as:
var r=require("./second.js");
var obj = { a: 1};
r.change(obj,2);
console.log(obj.a);
First way is return in your change function in second.js.
app.js:
var r=require("./second.js");
var a=1;
a = r.change(a);
console.log(a);
second.js:
module.exports.change=function(a){
a=2;
return a;
}
Second way is use object as parameter to pass it by reference:
app.js:
var r=require("./second.js");
var obj={a:1};
r.change(obj);
console.log(obj.a);
second.js:
module.exports.change=function(obj){
obj.a=2;
}
You can use localStorage or sessionStorage for setting and getting your variable.
for node js you can use https://www.npmjs.com/package/localStorage package
//You can set using localStorage.setItem('key','value')
var r = require("./second.js");
var a = 1;
localStorage.setItem('a', 1) /*Window api for setting variable locally
localStorage.setItem('key','value')*/
r.second(a);
console.log(a);
You can get using localStorage.getItem('key')
//second.js
module.exports.change=function(a){
a=localStorage.getItem('a')
}
Related
Is there an option to get a reference to the whole script variables?
lets assume this code:
const a=n=>n+1,
b={};
let c=3
I wonder if I can access all variables by one reference, like this vars:
vars.b //{}
vars[varName]
so that I'll be able to pass it to other sub modules easily instead of creating a manualy associative array with the variables of the script
It is possible only to some limit.
There is globalThis variable acting as a container for all top-level variables.
And also in every function arguments variable is available holding everything passed to function in the current call.
I'm not aware of anything similar for function-/block-scope variables
I think you can assign those variables to a JSON object and then export the JSON object as follows so that you can reference all the variables in other file.
// scripts.js file
let a = n => n+1;
let b = {};
let c = 3;
module.exports = { a, b, c };
// index.js file
const scripts = require('./scripts');
console.log(scripts.a(4));
console.log(scripts.b);
console.log(scripts.c);
No, there's no way to programatically get access to the environment record of a given function/scope/closure. To do something like this, the best way would be to define the variables as part of an object or Map in the first place. Instead of
const a=n=>n+1,
b={};
let c=3
do
const theNamespace = {
a: n=>n+1,
b: {},
c: 3
};
and pass theNamespace around.
Functions are callable objects in javascript so is it possible to redefine a function definition
?
so basically what I am trying to do is:
let a = function(){console.log('first');}
let b = a;
/**
* alter definition of function 'a' something like:
a.redefine(function(){console.log('second');});
*/
b();//should log 'second'
I looked up for javascript function documentation here as well as here but couldn't find any reference on how/where functions definition are actually stored, even tried to inspect a.prototype as well as altering a.prototype.constructor but got nothing.
A workaround on this can be something like:
let functionHolder={
a:function(){console.log('first');}
}
let a = function(){functionHolder.a();}
let b = a;
functionHolder.a=function(){console.log('second');}
b();//would log 'second'
however my ultimate goal is to understand how functions actually work/stored in js and not a workaround just to achieve this.
It's not possible. Once a function has been defined, its "function code" is immutable. The only way for a variable name which references a function to reference different "function code" would be to reassign the variable name to a new function.
Your
functionHolder.a=function(){console.log('second');}
is essentially the same thing - you're reassigning the function that functionHolder.a refers to.
In the specification, when you call a function, you invoke its internal method [[Call]], which eventually leads you to
OrdinaryCallEvaluateBody, which does:
Return the result of EvaluateBody of the parsed code that is F.[[ECMAScriptCode]] passing F and argumentsList as the arguments.
And the ECMAScriptCode internal property is not reassignable - it's only set in FunctionInitialize, when a new function is created (like when you do
<someIdentifier> = function(){console.log('second');}
)
It is possible by turning the b variable into a getter on the window object.
It's not pretty, but it works:
let a = () => "foo";
console.log("a", a());
Object.defineProperty(window, 'b', {
get() { return a; }
});
console.log("b", b());
a = () => "bar";
console.log("b", b());
a is a reference to a function. Call it a "pointer".
b is a copy of that pointer.
When you re-assign a, you're replacing the pointer. If another variable still points to the value behind the old pointer, that value still exists. That's why in your example, b didn't change: b was a pointer to the old function.
That getter is basically a function that's executed without explicitly having to call it, so it always gets the latest result of whatever the getter function does.
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.
I am pretty new in JavaScript and I always used it in something like old procedural way.
Now I am studying how to JavaScript implement the object oriented paradigm and I have some doubt on this example finded on a tutorial.
I have an utility.js file that contain this simple code:
var steveApp = {}; // Object container
steveApp.person = 'Steve'; // Add a person field to the steveApp object
steveApp.logPerson = function() {
console.log(steveApp.person);
}
So I have some doubt about how exaclty works it.
I think that first it define something like an empty object named steveApp by this line:
var steveApp = {}; // Object container
Then I think that the . it is used to add a field to the previous empty object, so I have:
steveApp.person = 'Steve';
that add a valorized person field to the steveApp object.
Finally it do a "strange" thing:
steveApp.logPerson = function() {
console.log(steveApp.person);
}
it seems to me that add a new field (named logPerson) to the steveApp object but this field is not a normal field (an integer, a string or another object) but it is a function that perform a behvavior (write a log in the console).
Then, into another JavaScript, file it do:
steveApp.logPerson();
and the previous function is perfromed. So what it exactly means? It means that in JavaScript a function could be a field of an object or what?
Abd why to call this function (if it is true that it is a field) I have to do:
steveApp.logPerson();
and not call the field name ?:
steveApp.logPerson;
Tnx
Functions are first class objects in JavaScript. They can be treated just like any other kind of data.
You can store them in variables, store them in properties, pass them as function arguments, etc.
Abd why to call this function (if it is true that it is a field) I have to do:
steveApp.logPerson();
Putting (zero_or_more_aguments_here) after something that evaluates as a function is how you call a function. Leaving them off gives you the function itself, not the result of calling it.
steveApp.logPerson(); //calls the function
while
steveApp.logPerson; // returns the function itself (NOT the return value of the function
you can also print it in the console and you will see:
console.log(steveApp.logPerson())
vs
console.log(steveApp.logPerson);
greetings
As mentioned by Quentin & I quote:
Functions are first class objects in JavaScript. They can be treated
just like any other kind of data.
You can store them in variables, store them in properties, pass them
as function arguments, etc.
Another important thing to know is that objects in JS are passed around or called by reference. They are never copied.
var a = {};
var b = {};
a.test = "hello";
b.test // returns undefined
Also
var a = {};
var b = a;
a.test = "hello"
b.test // return "hello"
And
var stooge = {first: "Jerome", second: "Howard"}
var x = stooge;
x.nickname = "curly";
var nick = stooge.nickname;
nick // returns "Curly"
The basics is that JavaScript is not strongly typed, so you could even assign different types to the same variables at different times:
var myVar = true;
myVar = 3.14;
myVar = "now a string";
alert("myVar is now a string with content: " + myVar);
myVar = function (someArg) {
alert("myVar is now a reference to a function, passed argument " + someArg);
return true;
}
myVar();
typeof myVar; // would return "function"
typeof myVar(); // would return "boolean"
As for your object "fields" (usually called properties), indeed they can receive any type that a normal variable would as well. Including a function, since they are "first-class citizen".
var myObject = {
myBool: true,
myNumber: 3.14,
myMethod: function (myArg) {
return myArg;
},
myNull: null
};
And like previously, you can even re-assign them later on…
Your assumptions are correct. But the difference between the below lines are
steveApp.logPerson();
Accessing logPerson property and invokes it as a function using ()
steveApp.logPerson;
It is just accessing the property logPerson, it returns the reference/value if it is used in RHS in an equation.
If you consider programming language like Scala, it is intelligent enough to infer whether it is a function call or not without using () but in JavaScript it is the reference, and if you try to invoke a normal property which is not a function. You will get an error saying logPerson is not a function.
I am trying to create a function which will dynamically set the value of whatever global variable is passed as a parameter. It's not working, and I'm trying to figure out why. Can someone please explain why this doesn't work:
var things = 5;
function setup(variable) {
variable = 7;
}
setup(things);
console.log(things); //should return 7. returns 5 instead. the function had no effect on the global variable
and this also doesn't work:
var things = 5;
function setup(variable) {
window.variable = 7;
}
setup(things);
console.log(things); //should return 7, but returns 5. still not accessing the global variable.
but this does:
var things = 5;
function setup(variable) {
window[variable] = 7;
}
setup("things");
console.log(things); //returns 7
I suspect that what is happening is that the parameter variable is being set as a local variable inside of the function, so any changes are only happening to the local version. But this seems strange because the parameter that's been passed is a global variable. Can someone explain to me what is happening and how to better write this code? Does this require a method (which can then use this to access the original object)?
Thanks!!
Javascript is pass-by-value. (Objects, arrays, and other non-primitives are passed by value-of-reference.) That means that the value of the variable (or reference) is passed to the function, but the function parameter does not become an alias for the actual argument. Thus, you cannot change a variable outside a function without referencing it (as you do in your last example).
See this answer in another thread for more information.
Inside of functions are "variable environments". When the function setup is declared, and the parameter variable set, it creates a local variable in setup's variable environment for variable (the parameter).
So that is why this assignment
function setup(variable) {
variable = 7;
}
Will never change the value sent to variable.
Variables in JavaScript are values. As the variable is passed around, the only thing passed is the value of the variable. However, the value of the variable is assigned to the parameter (again poorly named in this example) variable. When the value of the parameter is assigned to 7, that only changes the local variable, and not the value of the passed variable.
//the value of things is 5
var things = 5;
//the passed value 5 is assigned to variable
function setup(variable) {
//the value of variable is changed to 7 (and nothing is done with 5)
variable = 7;
}
//the value of things is sent to setup
setup(things);
Hopefully this will be a little more enlightening. Consider a situation where setup was actually modifying the value of variable. A good example is when the value has state, such as an array or an object.
//the value of things this time is an object
var things = {};
//the passed value of object is assigned to variable
function setup(variable){
//the value of variable (the object) has a property added named msg with a value of "hello world"
variable.msg = "hello world";
}
//the value of things (an object) is sent to setup
setup(things);
alert(things.msg);//hello world
When variables are passed as arguments to functions, a copy of their value is made and assigned to the name of the argument in the function.
For example:
function foo(a) {
a = 7; // sets the temporary variable(argument) a to 7
}
var bar = 24;
foo(bar); // copies bar's value and passes in the copy to foo
For a function to modify a variable itself, you would have to access it another way. In other languages there are things called pointers that point to a place in memory. This allows you to modify variables directly, as you have where they are located - you can simulate this with JavaScript:
var spam = 3;
var memory = ["bar", 29, "x", foo, false];
function foo(a) {
memory[a] = 7;
}
foo(3);
The above example sets an array called memory and fills it with random gibberish. Then, a function named foo is created that allows for the modification of elements in this memory array.