How to maintain JavaScript function variable states (values) between calls? - javascript

I am looking for getters and setters functionality but cannot rely on __defineGetter__ and __defineSetter__ yet. So how does one maintain a function variable's value between function calls?
I tried the obvious, but myvar is always undefined at the start of the function:
FNS.itemCache = function(val) {
var myvar;
if( !$.isArray(myvar)
myvar = [];
if( val === undefined)
return myvar;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
};
I could always put another FNS._itemCache = [] just above the function, but is there a way to encapsulate the values in the function between calls?

An alternative way to set a private variable is by wrapping the function definition in an anonymous function:
(function(){
var myvar;
FNS.itemCache = function(val) {
if( !$.isArray(myvar))
myvar = [];
if( typeof val == "undefined")
return myvar;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
};
})();
This way, myvar is defined in the scope of FNS.itemCache. Because of the anonymous function wrapper, the variable cannot be modified from elsewhere.

You can store the value on the function by using arguments.callee as a reference to the current function:
FNS.itemCache = function(val) {
if( !$.isArray(arguments.callee._val)
arguments.callee._val = [];
if(val === undefined)
return arguments.callee._val;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
};
However, this will break if the function is stored in a prototype and thus used by more than one object. In this case you have to use a member variable (e.g. this._val).

this is a standard pattern for creating your static variable and for creating private members of an object
FNS.itemCache = (function() {
var myvar;
if( !$.isArray(myvar)
myvar = [];
return function(val) {
if( val === undefined)
return myvar;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
}
})();

Related

Are Variables Initialized inside Function Declaration Always Re-initialized When The Function Execute (Javascript)?

My question is based on two premises: (1) codes are not executed until the function containing them is called and (2) variables are saved in memory.
So, are variables initialized inside function declaration always re-initialized when the function execute?
To demonstrate, if I initialize a variable inside function declaration to a huge object and call that function, then, the huge object will be created, saved, or and processed in memory. If I call or execute that function many times, then the huge object will be created, saved, or and processed everytime the function executes. Then, there will be so many and big processing of that variable (containing that huge object, and if only one). Therefore, this behavior will result in bad effect for performance. I do not know much about this, is this correct?
This is to demonstrate with code:
If I declare global variables, then the process only involve value-changing. But, if I declare local variable like this:
var hugeObj = {
prop1 : function() {...},
prop2 : [...],
prop3 : {...},
};
and I execute the containing function five times, then there will be five "hugeObj" (with different contexts) in memory (and involve more processing).
Can you explain how variables are processed inside function declarations, and will them be created in every execution context?
The answer is yes, each time the function is run it's internal variables are re-initialized and are not reused.
function MyFunc(newValue){
var v;
if(newValue) v = newValue;
return v;
};
console.log(MyFunc()); // undefined
console.log(MyFunc(5)); // 5
console.log(MyFunc()); // undefined
// Therefore we can conclude that the object is re-initialized each time the function is run and its previous variable values are not reused.
If you would like it to not initialize the variable each time, just initialize the variable globally.
var v;
function MyFunc(newValue){
if(newValue) v = newValue;
return v;
};
console.log(MyFunc()); // undefined
console.log(MyFunc(5)); // 5
console.log(MyFunc()); // 5
In addition to the answer of #DustinPoissant, you can declare different scope (local or global) inside a function.
Let's use the same code as the answer:
function MyFunc(newValue){
var v;
if(newValue) v = newValue;
return v;
};
console.log(MyFunc()); // undefined
console.log(MyFunc(5)); // 5
console.log(MyFunc()); // undefined
In this case the scope is the local function, but if you remvoe var keyword, your scope changes to global (yes, v variable will be attached to window object):
function MyFunc(newValue){
if(newValue) v = newValue;
return v;
};
console.log(MyFunc()); // undefined
console.log(MyFunc(5)); // 5
console.log(MyFunc()); // 5
That's the same as write:
function MyFunc(newValue){
if(newValue) window.v = newValue;
return window.v;
};
console.log(MyFunc()); // undefined
console.log(MyFunc(5)); // 5
console.log(MyFunc()); // 5
Because one of the variables is stored externally, run both, one will maintain its values, the one with the variable initialised within the function is overwritten.
var array = ["1","2","3","4","5"];
function MyFunc()
{
var current = "0";
console.log("Iteration");
for(var i = 0; i < array.length; i++)
{
current += array[i];
console.log(current);
}
};
console.log(MyFunc());
console.log(MyFunc());
var array = ["1","2","3","4","5"];
var current = "0";
function MyFunc()
{
console.log("Iteration");
for(var i = 0; i < array.length; i++)
{
current += array[i];
console.log(current);
}
};
console.log(MyFunc());
console.log(MyFunc());
Variables are named memory, it all depend on the scope of the variable(Local or Global) Variables inside a functions are called local variables, every time this function is called the variables are re initialized, which means at every call to the function the value of the variable is expected to change.
public void myFunction(int val1, String val2)
{
int a = val1;
String b = val2;
System.out.println(val2 +" "+val1);
}
a and b in the above are local variable that will be affected base on the parameters passed to it by the method/function calls
so the value of a variables in a function will always change

Replace object value without replacing reference

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))

Function scope is lost in returned methods when strigifying/parsing js objects with JSON

I have such a bit crazy example, but it looks like a good exercise for those who are experts in javascript function scopes:
(function (global) {
// our module number one
var body = function () {
var someVar = 'some test text';
return {
method: function () {
return someVar; // this will undefined when call this method in second module
}
};
};
var f = new Function([' return (', body, ')();'].join(''));
global.r = f();
})(window);
(function (global) {
// our module two
var body = function () {
// dep variable is injected on the fly with `new Function`
dep.method(); // will throw `Reference Error: someVar is not defined`
};
// helper to propertly transform functions in JSON.stringify
function transformFuncs (key, val) {
if (typeof val === 'function') {
return val.toString().replace(/(\t|\n|\r)/gm, '').replace(/("|')/gm, '\\"');
}
return val;
}
// injecting our first module inside
var vars = ['var ', 'dep', ' = JSON.parse(\'', JSON.stringify(global.r, transformFuncs), '\', function (key, value) { if (value && typeof value === "string" && value.substr(0,8) == "function") { var startBody = value.indexOf("{") + 1; var endBody = value.lastIndexOf("}"); var startArgs = value.indexOf("(") + 1; var endArgs = value.indexOf(")"); return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody)); } return value; });'].join('');
// as variable
var f2 = new Function([vars, ' return (', body, ')();'].join(''));
global.r2 = f2();
})(window);
If you'll run this code somewhere you'll see an exception thrown ReferenceError: someVar is not defined.
So basically what's happening here - we create some module and then trying to inject it inside another one as variable. Function that is used in JSON.parse to correctly get stringified functions looks like this (if you're curious):
function (key, value) {
if (value && typeof value === "string" && value.substr(0,8) == "function") {
var startBody = value.indexOf("{") + 1;
var endBody = value.lastIndexOf("}");
var startArgs = value.indexOf("(") + 1;
var endArgs = value.indexOf(")");
return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody));
}
return value;
}
So.. the question is it possible to workaround such scope behavior? As I understand global.r is assigned with f result in one scope, but resulted object with method function is not saving the variable instance because while JSON parsing another scope is created for that function.
Any ideas?
P.S. Please don't ask why I need this :) just think about possible solutions. The main idea is to somehow inject module number one (look top body var) as variable inside second module (body var of second function) saving the original scope of methods that are returned.
Thanks!
is it possible to workaround such scope behavior?
No. Scopes are inaccessible from outside, and they are necessarily lost on serialisation of a function. You can only stringify "pure" functions like body that do not reference any free variables.
That's also the reason why the JSON format does not include functions.
The main idea is to somehow inject module number one as variable inside second module saving the original scope of methods that are returned.
Inject the reference, not a string. Dependency injection is no magic, all kinds of module loaders for JavaScript do it.

Why isn't this function recreated

As you can see in the example below, I'm trying to wrap every function defined in obj so it gets to be able to be called with anotherObj as this, and then add that wrapper as a property to anotherObj.
Note: isFunction
var isFunction = function(x) {
return typeof(x) == "function";
}
for (prop in obj) {
if (isFunction(obj[prop])) {
var fn = obj[prop];
anotherObj[prop] = function() {
fn.call(anotherObj);
};
}
}
For some reason weird to me, every property now stored in anotherObj, references only the last property of the iteration.
However, if I use an external function like below, the references are ok.
var contextFn = function(fn, context){
return function() {
fn.call(context);
};
};
...
for (prop in obj) {
...
anotherObj[prop] = contextFn(fn, anotherObj);
...
}
Why is this happening? Is there something obvious I'm missing?
The (not-so-)obvious thing you're missing is that in your first loop, the variable "fn" is not local to the statement block it's declared in. Thus, it's shared by all the functions you're creating.
Your solution is in fact the correct one. By using a separate function, you're making copies of the values to be used in creating the actual wrapper functions, so that each wrapper will have it's own private copy of "fn".

JavaScript - How/Can I set an object reference to null from a function?

I'm wondering if this is even possible. Basically I have a couple objects that I pass to a function, and under certain conditions I want that function to set the object to null.
Ex.
var o = {'val' : 0};
f = function(v)
{
v = null;
};
f(o); // Would like this to set 'o' to null
Unfortunately it seems I can only set the function's argument to null. After calling the function 'o' will still refer to an object.
So, is it even possible to do this? And if so, how?
If you want to change the value of o when f(o) is called, you have two options:
1) You can have f(o) return a new value for o and assign that to o like this:
var o = {'val' : 0};
o = f(o);
// o == null
Inside of f(), you return a new value for o.
function f(v) {
if (whatever) {
return(null);
}
}
2) You put o into another object and pass a reference to that container object into f().
function f(v) {
if (whatever) {
v.o = null;
}
}
var c = {};
c.o = {'val' : 0};
f(c);
// c.o == null;
The javascript language does not have true pointers like in C/C++ that let you pass a pointer to a variable and then reach back through that pointer to change the value of that variable from within the function. Instead, you have to do it one of these other two ways. Objects and arrays are passed by reference so you can reach back into the original object from the function.
JavaScript always passes function arguments "by value". Which means a function can't change what the variable outside the function points to.
However, when you pass an object to a function the "value" that is passed is a reference to the actual object, not a copy of the object. So although you can't set the outside variable to null or to another object you can modify the contents of that object. Which means you can do something like this:
var containerObj = {'o' : {'val' : 0} };
f = function(v) {
v.o = null;
};
f(containerObj.o); // This property would be set to null successfully.
Obviously creating a bunch of container objects just so you can pass them to functions isn't very pretty, but it is one way to do it.
But I'd recommend going with James Montagne's suggestion of having the function return an object or null and assigning the result back to your variable.
Not sure exactly the real use of this, but if you restructured a bit, you could do this:
var o = {'val' : 0};
var f = function(v)
{
if(something){
return null;
}else{
return v;
}
};
o = f(o);
I came here with the same problem. Although the wrapper answer works, it's ugly, and my function is asynchronous, so I can't return a null value.
The reason I wanted o to be null is that later I use if (o) //do something, which might be why OP and others want to set it as null. As such, my solution, although not an answer to the exact question, was
var o = {'val' : 0};
f = function(v) {
v.isNull = true;
}
if (!o.isNull) // do something
The easiest way of doing it would be to create a global variable called NULL and set it to null
var NULL = null
Then you can set an existing variable to NULL without modifying the original object.
var NULL = null;
var original = {};
var ptr = original;
ptr = NULL;
console.log("original is not null = " + (original!==null));
console.log("ptr is null = " + (ptr===null));

Categories

Resources