Hey I was wondering why the following returns undefined:
let variable;
module.exports.initialize = () => {
variable = "123";
};
module.exports.variable = variable;
I simply require the module in file A and then call the initialize function. In file B I require it and console.log the variable but it returns undefined. What am I missing here?
module.exports.variable is a property on the module.exports object. When you initialize your module, you assign the value of variable to that module.exports.variable property and that value is undefined at the time you assign it (because the initialize() function has not yet been called).
So, when your module is done initializing itself, module.exports.variable is undefined.
Then, sometime later someone else calls module.exports.initialize() and that changes the local variable within your module to "123". That does not affect the value of the module.exports.variable property at all. It remains undefined.
In the future, please don't give either a property or a variable the name variable as it makes it very difficult to document or discuss. A different name that doesn't conflict with the English definition of the word variable would simplify discussing this code.
What you can do instead is export an object instead of a plain value.
let myObj = { name: "John"};
module.exports.setName = (name) => {
myObj.name = name;
};
module.exports.sharedObj = myObj;
Then, why you import it somewhere else
const aModule = require('./otherModule');
console.log(aModule.sharedObj); // {name: "John"}
aModule.setName("Bob");
console.log(aModule.sharedObj); // {name: "Bob"}
Because objects in Javascript are assigned by pointer, when you did module.exports.sharedObj = myObj; in the module initialization, it put a pointer to myObj into module.exports.sharedObj so when myObj changes, anyone viewing module.exports.sharedObj will see that change too. This only works this way for objects in Javascript, not for other types of values (strings, numbers, etc...).
In JavaScript there are two types of values: 1) primitive type and 2) reference type. primitive values are always copied by their value and reference types are always copied by their references (not by their values).
Examples of primitive values: undefined, null, boolean, string, number.
Examples of reference types: every types other than primitive types. e.g., Object, array etc. See the snippet below.
Example of Primitive type
let a = 10;
let b = a;
console.log(a);
console.log(b);
b = 20;
console.log(a);
console.log(b);
Example of Reference type
let obj_a = {value: 1}
let obj_b = obj_a;
console.log(obj_a);
console.log(obj_b);
obj_b.value = 20;
console.log(obj_a);
console.log(obj_b);
So when you declare the variable as let variable its value is undefined and when you assign module.exports.variable = variable then you're just setting it's value to undefined.
See the example below.
const myExports = {};
let variable;
function initialize() {
variable = 10;
}
myExports.variable = variable;
console.log(variable);
console.log(myExports.variable);
initialize();
console.log(variable);
console.log(myExports.variable);
But if you were to initialize the the variable with a reference type e.g., an object then module.exports.variable would reflect any change to the properties of your variable variable.
Example:
const myExports = {};
let object = {};
function initialize() {
object.value = 10;
}
myExports.variable = object;
console.log(object);
console.log(myExports.variable);
initialize();
console.log(object);
console.log(myExports.variable);
Hope it make sense.
try initializing the variable in the module.exports.initailize function
module.exports.initialize = () => {
let variable;
variable = "123";
};
module.exports.variable = variable;
Related
I once again stumbled over a behavior in Javascript that I don't understand. I need to update properties of an object as soon as a variable outside of the object is changed. The external variable is referenced in the object properties so I thought all I had to do is to change the variable externally and automatically have the property values changed.
Here's a simplified version of what the code looks like:
var serverPath = "123/";
var GetCurrentProductionApiConfig = {
URL: {
GetStart: serverPath + 'GetCurrentProduction?returnValue=start&',
GetEnd: serverPath + 'GetCurrentProduction?returnValue=end&',
Get: serverPath + 'GetCurrentProduction?returnValue=start&'
}
};
serverPath = "456/";
console.log(GetCurrentProductionApiConfig.URL.GetStart);
This will result in:
123/GetCurrentProduction?returnValue=start&
Is it because the variable has been copied (passed by value) rather than having a pointer on it (passed by reference)? And which way would be the correct one to update the properties?
Everything in JavaScript is pass by value however, it happens that the value of an object is its reference. However, the important thing here is that for primitives, will not get changes when a referenced variable changes:
var a = "world";
var obj = {
b: "hello" + a //evaluated once
}
a = "universe"; //does not modify obj.b which references a
console.log(obj.b); //helloworld
In order to have a dynamically evaluated string, you need to call a function or a method:
var a = "world";
var obj = {
b: function() {
return "hello" + a //evaluated every time the function is executed
}
}
console.log(obj.b()); //helloworld
a = "universe"; //will influence obj.b
console.log(obj.b()); //hellouniverse
However, that looks a bit "dirty" since it forces the caller to know to evaluate the property every time. It can also introduce inconsistency if some properties are plain strings, others functions and it's especially annoying if a property has to change from one to the other - you need to modify every place that calls this code to change, say, obj.c to obj.c().
Instead, using ES6+ you can define a getter for a property that will do the same as before but will hide the function call, so any time you read a property you actually evaluate code to return the result:
var a = "world";
var obj = {
c: "plain property"
}
Object.defineProperty(obj, 'b', {
get: function() {
return "hello" + a //evaluated every time the property is read
}
});
console.log(obj.b); //helloworld
a = "universe"; //will influence obj.b
console.log(obj.b); //hellouniverse
console.log(obj.c); //plain property
var myObj = {
key: "element",
key2: "element2"
}
function stuff(obj) {
var a = obj;
console.log(a);
}
stuff(myObj);
How do I make stuff(myObj) console.log myObj, which is the name of the object? If I were to run this code, it would print that the argument myObj passed into stuff is an object and console.log its keys and elements. I want var a to store and console.log the name of the object instead of its contents, which in this case, is myObj.
You can't. JavaScript passes by value, there is no connection to the variable that was used to pass the object.
Take this example:
var foo = {};
var bar = foo;
window.baz = bar;
stuff(foo);
function stuff(obj) {
var a = obj;
console.log(a);
}
You now have 5 variables / properties which are all "names" for the same object.
If you need an object to have some kind of identifying name, then give it as a property.
var foo = { name: "foo" };
Use for-in loop to iterate through object. a and b are keys of the object which are mapped to id of the elements..
Try this:
var obj = {
a: "A",
b: "B"
};
for (var i in obj) {
$('#' + i).hide();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="a">A</div>
<div id="b">B</div>
<div id="c">C</div>
<div id="d">D</div>
It is possible! You can do something like this:
function stuff(obj) {
var a = Object.keys(window);
a.forEach(function(item, i, a) {
if (window[item] == obj)
{
console.log((item);
}
});
}
There is no (good) way to do that. The myObj variable has a pointer to the object in the memory. When you send myObj as parameter to a function, it will be sent by reference, so the obj parameter of your function will also have the pointer to the object in memory.
At this point the global variable myObj and local variable obj are synonyms for the same object. Modifying the property of one will also affect the other variable.
Theoretically there could be hundreds of variables pointing to the same object, but the object would never have any link back to any of the variables that point to it, so there is no way to retrieve the name of an object. There is no correct or original variable: all variables are identical no matter in what order they were linked to this object.
This said, of course if myObj is a global variable, it would be possible to compare your variable with all properties of the window object and then know which variable it was originally, but that's an awful waste of processing power. And it will only work with global variables.
So this should do the trick for global variable, but I strongly advise against doing this (most of all if it's a big project with lots of global variables). Still, if used during coding for debugging only, which I assume this is all about, it might be of some help:
function getVariableName(x) {
for (var i in window) {
if (window[i] === x) return i;
}
return false;
}
Attention: if you got more than one global variable pointing to this object, there is no way to know which of those variable names you will get back ... javascript does not define a fix order of enumerating properties of an object. The first match will be reported back!
How can you update an entire object, say:
var x = {a:1}
function modify(obj) {
obj = {b:2}
}
modify(x)
console.log(x) // {a:1}
But maintain the reference? I want the object to be modified outside the function.
My specific case is using lodash.pick inside my function:
if (whitelist) {
obj = _.pick(obj, whitelist)
}
I can't seem to find a pick function that modifies the object. Is there a way to do this or do I need to start returning copies of the object?
delete everything from the old object, and then add new properties, key-by-key:
function modify(obj, newObj) {
Object.keys(obj).forEach(function(key) {
delete obj[key];
});
Object.keys(newObj).forEach(function(key) {
obj[key] = newObj[key];
});
}
var x = {a:1}
modify(x, {b:42})
document.write(JSON.stringify(x));
If you're wondering whether it's a good idea in general, the answer is no. Construct a new object, return it from the function and assign - this is a much preferred way.
You can achieve this (not exactly what you want) if you wrap your object and change the modify function like this,
var wrapper = {};
wrapper.x = {a:1};
function modify(obj, key) {
obj[key] = {b:2};
}
modify(wrapper, 'x');
console.log(wrapper.x); // {b:2}
/**
* Method to deep update the values of the source object from new object without changing source object reference
*
* #export
* #param {*} sourceObj
* #param {*} newObj
*/
export function updateObjKeepingRef(sourceObj: any, newObj: any): void {
Object.keys(newObj).forEach(key => {
// if value is object and instance is not Date
if (newObj[key] && typeof newObj[key] === 'object' && sourceObj[key] && !(newObj[key] instanceof Date)) {
updateObjKeepingRef(sourceObj[key], newObj[key]);
} else {
// updating properties
sourceObj[key] = newObj[key];
}
});
}
Why does modify not edit the object referred to by obj?
Because inside modify when you write:
obj = {b:2}
Note that obj is a local variable to the function call of modify. A new object {b:2} is created, and the local variable obj now refers to this new object. Recall that the variable x still refers to the {a:1} object.
If x is a global variable AND if there is no local variable inside the function by the name, then you can do:
var x = {a:1};
function modify() {
x = {b:2}
}
modify();
console.log(x) // {b:2}
Why does the above code work?
When you call modify(), it tries to see if it has a local variable x, since it could not find one, it looks up in the scope chain. The next scope to look for this function call is the global scope, and sure enough, there we have a x variable. Hence this global variable x's value is set now.
I was having this issue. After some research, I opted to convert objectTwo to a JSON string, and then replace objectOne with the parsed version. In other words:
var mObjectOne = { ExampleProperty: 10 };
var mObjectTwo = { ExampleProperty: 15 };
// I wanted mObjectOne to hold the same data as mObjectTwo, but keep a separate reference
var mObjectTwoAsJSON = JSON.stringify(mObjectTwo);
mObjectOne = JSON.parse(mObjectTwoAsJSON);
// Now the references are still different, as desired, but the object data has been updated.
Thanks,
obj = JSON.parse(JSON.stringify(newObj))
I have an object defined outside the function, in a global scope. This object is not passed into the function as an argument, but the function does modify it and return the modified object.
What I wanted to know is, if the function returns a copy of the object, or the original global object?
Also, will passing that object to the function as an argument, make a difference, since objects are passed into functions by reference?
Whenever you're returning an object, you're returning a reference to the object. Likewise, when you're passing an object, you're passing a reference. However, passing an object in as an argument can be different than just changing an object in global scope, as these examples show. This is because the reference to the object is itself passed by value.
If you're changing the members of an object, then whether you pass it in as an argument or just update the global object makes no difference. Either way, you're working with the same object.
Example 1:
var object = {foo:'original'};
function changeObject() {
object.foo = 'changed';
return object;
}
console.log(changeObject()); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}
Example 2:
var object = {foo:'original'};
function changeArgument(object) {
object.foo = 'changed';
return object;
}
console.log(changeArgument(object)); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}
On the other hand, if you're overwriting the object with a new object, the change won't persist if you do it to the argument, but will persist if you do it to the global object. That's because the argument passes the reference to the object by value. Once you replace this value with a reference to a new object, you're not talking about the same object anymore.
Example 3:
var object = {foo:'original'};
function replaceObject() {
object = {foo:'changed'};
return object;
}
console.log(replaceObject()); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}
Example 4:
var object = {foo:'original'};
function replaceArgument(object) {
object = {foo:'changed'};
return object;
}
console.log(replaceArgument(object)); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'original'}
May be late comment, but this is typical challenge in any language.
Objects created on the heap and passed around by reference opposed to primitives(by value).
I think the root of the question is shared instance versus unique one to avoid unwelcome effects.
For example we calling a function to get a template(object) for new user to add to collection or want to clear the form
on cancel event from different modules to start over. It easy to understand and easy to overlook..test cases typically
not covering all usage permutations
The sanity checklist:
Here the shared instance:
var bigo = {
usr: { name: 'steven' },
bigi: function () {
return this.usr;
}
};
var outA = bigo.bigi();
var outB = bigo.bigi();
print(outA.name); // => steven
print(outB.name); // => steven
outA.name = 'ilan'; // change value
print(outA.name); // => ilan
print(outB.name); // => ilan
Non shared instance:
var bigo = {
bigi: function () {
var user = { name: 'steven' };
return user;
}
};
var outA = bigo.bigi();
var outB = bigo.bigi();
print(outA.name); // => steven
print(outB.name); // => steven
outA.name = 'ilan'; // change value
print(outA.name); // => ilan
print(outB.name); // => steven
What I wanted to know is, if the function returns a copy of the object, or the original global object?
Effectively, you only ever deal with references to objects in JavaScript. Even var foo = {} just assigns a reference to a new object to foo.
If the object is outside the function, you don't need to 'return' it. If you modify the object within the function it will update the object itself. Then you can reference the newly updated object in other functions as needed.
From your question this is how I think your code looks (more or less):
var o = {};
function f() {
o.prop = true;
return o;
}
In this case the global variable o references an object.
When you modify o you're modify whatever o references. Hence it modifies the original object.
When you return o you're returning a reference to the original object.
Passing the object to a function results in the reference to the original object being passed. Hence any modifications will affect the original object. For example:
var o = {};
f(o);
console.log(o.prop); // true
function f(o) {
o.prop = true;
}
I have a global variable MyGlobalVar and some code that looks like this:
var MyGlobalVar = null;
function PlayWithMyGlobal() {
MyGlobalVar = new Object();
.... adding properties to MyGlobalVar
MoreFun(MyGlobal);
}
function MoreFun(TheVar) {
is TheVar here a local or just a reference to the global?
}
If I pass the global variable, am I still working with the global?
Thanks.
If I pass the global variable, am I still working with the global?
Thanks.
It depends whether variable you pass is an object or a primitive (number, string, boolean, undefined, null are primitives) value in the first place. Objects are passed by reference and primitives by value.
In your case, you are passing object:
MyGlobalVar = new Object();
And in JS, objects are passed by reference. So you are still working on that variable.
You can confirm it like this:
var MyGlobalVar = null;
function PlayWithMyGlobal() {
MyGlobalVar = new Object();
MoreFun(MyGlobalVar);
}
function MoreFun(TheVar) {
MyGlobalVar.foo = 'I am foo'; // property created here
}
PlayWithMyGlobal();
console.log(MyGlobalVar.foo); // I am foo
If the global variable is an object, then you're still working with the global variable. Otherwise, it's a copy.
As shown and annotated below, your variables point to the same global object.
var MyGlobalVar = null;
function PlayWithMyGlobal() {
MyGlobalVar = new Object(); // <--- Object
MoreFun(MyGlobalVar); // <--- Passing object reference
}
function MoreFun(TheVar) {
TheVar.test = 'Did I modify global?';
alert(TheVar === MyGlobalVar); // true
alert(MyGlobalVar.test); // "Did I modify global?"
}
Yes, you have a local reference to the same object that is referenced globally.
A simple test would be...
console.log(MyGlobalVar === TheVar); // should be true