JS closures and recursion - javascript

For example I have this function with a closure:
function getData() {
var status = 0;
var func = function() {
status++
alert(status);
}
return func;
}
Its works correctly and the variable "status" is visible within the closure function.
But if I transfer the closure code into the separate function the closure variable "status" isn't available:
function getData() {
var status = 0;
var func = function() {
myFunction();
}
return func;
}
function myFunction() {
status++
alert(status);
}
Yes, I can send this variable to the function and then return the changed value. But what if I need recursion in "myFunction"?
function getData() {
var status = 0;
var a = function() {
myFunction(status);
}
return a;
}
function myFunction(status) {
if (status == 0) {
status = 1;
// After calling this function again "status" will reset to 0,
// but I want to save current value (status = 1).
data();
}
return status++;
}
var data = getData();
data();
How can I get one instance of my variable "status" for all calls to the closure function.
Thanks!

Firstly, that doesn't work because JS has lexical scopes, not dynamic scopes. More info on Wikipedia
Secondly, if you want to pass in a variable to a function, and allow that function to mutate it, you need to send something that's an instanceof Object.
0 instanceof Object
false
"" instanceof Object
false
[] instanceof Object
true
({}) instanceof Object
true
(function(){}) instanceof Object
true
You can wrap your number into an object and pass it.
Modified example:
function getData() {
var o = {
status: 0
};
var a = function () {
myFunction(o);
}
return a;
}
function myFunction(o) {
console.log(o);
if (o.status == 0) {
o.status = 1;
// After calling this function again "status" will reset to 0,
// but I want to save current value (status = 1).
data();
}
return o.status++;
}
var data = getData();
data();
Output:
Object {status: 0}
Object {status: 1}
http://jsfiddle.net/Dogbert/Tw7nh/

You could replace this line:
myFunction(status);
with:
status = myFunction(status);
or:
JSFIDDLE: http://jsfiddle.net/KHZRr/
function Data(){
var status = 0;
var a = {
getData : function(){
if( status == 0 ){
status = 1;
return "FIRST, status = " + status;
}else{
return "NOT FIRST, status = " + status;
}
}
}
return a;
}
var data = Data();
alert( data.getData() );
alert( data.getData() );
alert( data.getData() );
Is this what you are looking for?

If I transfer the closure code into the separate function the closure variable "status" isn't available.
True, and that won't change due to JavaScript's scoping rules.
Yes, I can send this variable to the function and then return the changed value. But what if I need recursion in "myFunction"?
Nothing changes. You can use recursion from inside the closure as well.
function getData() {
var status = 0;
function data() {
if (status++ == 0) {
// do anything you want
// including recursive calls to `data()`
}
return status;
}
return data;
}
getData()();

Related

javascript OO how to update self parameters with some JSON variable

Lets say I have a javascript object with the the following
var Settings = function () {
this.timelimit = 0;
this.locked = false;
this.expires = null;
this.age = null;
};
And then I set some get/set functions like:
Settings.prototype = {
getAllAges: function () {
return self.age;
},
getTimeLimit: function () {
return self.timelimit;
},
load: function() {
data_from_local_storage = LoadLocalStorage();
}
}
In data_from_local_storage I have JSON variables that match the above variables (timelimit, locked etc .. )
Issue is, the object var settings_ref = Settings() have all these 4 variables - but also have these 3 functions assigned in settings_ref - due to this OO behavior I need to write inside the load() function:
this.timelimit = data_from_local_storage.timelimit
this.age = data_from_local_storage.age
this.locked = data_from_local_storage.locked
Because if I'll write
this = data_from_local_storage it will destroy my object.
So how can I avoid writing all these variables one-by-one ?
w/o a for loop inside a function
in this example are just 4 but there are much much more and I cannot write it everywhere everytime
I'm looking for some .update() function like in Python or something ..
Any quick shortcut that someone know ?
You can use Object.assign() in ES2015:
load: function() {
Object.assign(this, LoadLocalStorage());
}
It's apparently not supported yet in IE, but there's a polyfill on the MDN page:
if (typeof Object.assign != 'function') {
(function () {
Object.assign = function (target) {
'use strict';
// We must check against these specific cases.
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var output = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source !== undefined && source !== null) {
for (var nextKey in source) {
if (source.hasOwnProperty(nextKey)) {
output[nextKey] = source[nextKey];
}
}
}
}
return output;
};
})();
}
(Personally I would use Object.defineProperty() to add the method, but that's verbatim from MDN.)
(edit though I guess if you don't have Object.assign() you may not have Object.defineProperty() either :)
If you store the data inside another object literal, it makes persisting things to localstorage and back a lot easier.. Here is an example..
//pretend local storage loader
function LoadLocalStorage() {
return {
timelimit: 100,
locked: true,
expires: new Date(),
age:40
}
}
var Settings = function () {
this.data = {
timelimit: 0,
locked: false,
expires: null,
age:null
}
};
Settings.prototype = {
getAllAges: function () {
return this.data.age;
},
getTimeLimit: function () {
return this.data.timelimit;
},
load: function() {
this.data = LoadLocalStorage();
}
}
var settings = new Settings;
console.log('Age before our load');
console.log(settings.getAllAges());
settings.load();
console.log('Age after our load');
console.log(settings.getAllAges());

Make Javascript local variable to global for recursive loops

I have a recursive function which has a local variable.
It calls itself on specific condition.
The local variable needs to be updated, but every call it creates a new local variable specific to the current function scope.
How can i reach the local variable for access all recursive loop and not to create a new one?
Something like __Callee.varname?
The code is:
var addAttribute = function(object,elem)
{
var attributes = [];
// only attribute without values
if ( object instanceof Array )
{
for ( var value in object )
{
attributes.push(object[value]);
}
}
// attribute with values
else if ( object instanceof Object )
{
for ( var key in object )
{
if ( object[key] instanceof Array )
{
addAttribute(object[key],elem);
}
else
{
attributes.push(key+'=\''+object[key]+'\'');
}
}
}
// Only one attribute
else if ( typeof object === 'string' )
{
attributes.push('\''+object+'\'');
}
// Invalid parameter
else
{
console.log('Invalid parameter: '+typeof object);
}
console.log('<'+elem+' '+attributes.join(' ').toString()+' />');
}
I do not want to make variable to global because of using this name in other functions and global scope already.
Use a closure
function fn() {
function recursiveFunction() {
// do something with x
recursiveFunction();
}
var x = 0;
recursiveFunction();
}
The usual thing is to pass it into the function, possibly optionally:
var addAttribute = function(object,elem, attributes) {
attributes = attributes || [];
// ....
Then when calling it recursively, pass in the third argument:
addAttribute(object[key], value, attributes);
Here's a much simplified example demonstrating:
function foo(num, array) {
array = array || [];
array.push(num);
console.log("Pushed " + num + ", array = " + JSON.stringify(array));
if (num < 5) {
foo(num + 1, array);
}
}
foo(1);

Advantages of treating function as an object

Recently I came across a simple Command pattern implementation in JavaScript that uses function as an object instead of pure object to define functionality:
var CommandManager = (function() {
function CommandManager() {}
CommandManager.executed = [];
CommandManager.unexecuted = [];
CommandManager.execute = function execute(cmd) {
cmd.execute();
CommandManager.executed.push(cmd);
};
CommandManager.undo = function undo() {
var cmd1 = CommandManager.executed.pop();
if (cmd1 !== undefined){
if (cmd1.unexecute !== undefined){
cmd1.unexecute();
}
CommandManager.unexecuted.push(cmd1);
}
};
CommandManager.redo = function redo() {
var cmd2 = CommandManager.unexecuted.pop();
if (cmd2 === undefined){
cmd2 = CommandManager.executed.pop();
CommandManager.executed.push(cmd2);
CommandManager.executed.push(cmd2);
}
if (cmd2 !== undefined){
cmd2.execute();
CommandManager.executed.push(cmd2);
}
};
return CommandManager;
})();
and the usage:
CommandManager.execute({
execute: function(){
// do something
},
unexecute: function(){
// undo something
}
});
//call unexecute of prev. command
CommandManager.undo();
//call execute of prev. command
CommandManager.redo();
My question would be, is there any advantages in defining CommandManager function this way, instead of directly defining properties on object literal and assigning it back to var CommandManager
The only use for that would be that you have a function that does absolutely nothing:
CommandManager(); // does nothing, returns undefined
Other than that, you can just as well write the code as an object literal and use this to avoid it being dependant on its own name:
var CommandManager = {
executed: [],
unexecuted: [],
execute: function execute(cmd) {
cmd.execute();
this.executed.push(cmd);
},
undo: function undo() {
var cmd1 = this.executed.pop();
if (cmd1 !== undefined){
if (cmd1.unexecute !== undefined){
cmd1.unexecute();
}
this.unexecuted.push(cmd1);
}
},
redo: function redo() {
var cmd2 = this.unexecuted.pop();
if (cmd2 === undefined){
cmd2 = this.executed.pop();
this.executed.push(cmd2);
this.executed.push(cmd2);
}
if (cmd2 !== undefined){
cmd2.execute();
this.executed.push(cmd2);
}
}
}

calling object properties in N levels javascript

I'm using mongodb and ajax calls to retrieve data. When it turns to javascript object, the properties that I use to generate html sometimes don't exist.
Look at this call:
$.ajax({
url: 'api/v1/mention/'+id,
type: "GET",
dataType: "json",
data : {login : "demo"},
success: function(mention) {
display_mention_text(mention.texto);
}
});
In this case i'm calling mention.texto, but could be mention.picture or any properties. Sometimes it is undefined and crashes the app.
This method calls a property from a object and if its undefined , return an empty string.
Some examples for calling this method(the first one is an object, the other are properties):
get_property(mention,"text")
get_property(mention,"user","name")
get_property(mention,"picture")
The method is defined as follows:
function get_property(obj){
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
if (checkNested(obj,args)) {
//what should I do here?
} else{
//the property is undefined and returns ""
"";
};
}
//check if a object has N levels of propertys
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++) {
if (!obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
In the first method get_property, if the property do exist, how do I call that??
I would have the object and his propertys as an array like:
object
params = ["user","name"]
but I can't call like following:
object.["user","name"]
Replace the if statement in the get_property function with the for loop from the checkNested function. Then instead of returning true or false, return the value found or "".
function get_property(obj){
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
// Here's your 'for' loop. The 'if' statement is gone.
for (var i = 0; i < args.length; i++) {
if (!obj.hasOwnProperty(args[i])) {
return ""; // I changed the value of this 'return' statement
}
obj = obj[args[i]];
}
return obj; // I change the value of this 'return' statement
}
Again, all I did was copy paste your own code from one function to the other, and change the values of the return statements.
You can achieve your goal by this way (no need of checkNested function):
//Parameters {obj, prop1, prop2, ... propN}
function get_property(){
var args = Array.prototype.slice.call(arguments),
obj = args.shift(),
prop = args.shift();
if( obj.hasOwnProperty(prop) ){
if( args.length > 0 ){
//Calling 'get_property' with {obj[prop1], prop2, ... propN} , and so on
return get_property.apply(get_property, [obj[prop]].concat(args));
}else{
return obj[prop];
}
}else{
return "";
}
}​
Usage:
var o = {
"a" : {
"b" : 5
}
};
console.log( get_property(o,"c") ); // ""
console.log( get_property(o,"a","b") ); // 5
console.log( get_property(o,"a") ); // {"b":5}
You're just looking for a simple recursive function.
function get_property(obj, prop) {
if (obj[prop]) {
return obj[prop];
}
else {
var end;
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
end = get_property(obj[p], prop);
}
}
if (!end) {
// If we're there, it means there's no property in any nested level
return;
}
else {
return end;
}
}
}
Edit: looks like I misinterpreted your question. See #Engineer's answer instead. Keeping this answer in case someone looks like for something like this.
You're overcomplicating things. If you know the tree of your object, just call:
obj['user']['name'];
If you're expecting undefined properties (and really, that means there's something else wrong):
var prop;
try {
prop = obj.user.name;
}
catch (e) {
prop = null;
}

How can I call any function in a chain of functions, without the chaining?

Sorry if my question wasn't clear enough. I'll put my code here...
var chain = {
'fn_1' : {
//fn_1 code here
chain.fn_2();},
'fn_2' : {
//fn_2 code here
chain.fn_3();}
...and so on
}
Let's say if i wana call chain.fn_1(), is there a way I can do that without calling chain.fn_2()?
What I can think of right now is a flag, but that would be alot of excess flags probably for each function. Do you guys have any ideas?
If the series of functions each call the next one you're correct, you'd need to have some sort of flag. In all likelihood, what would be best would be to modify your functions so that they return the reference to the object. Then you could chain like so:
var chain = {
'fn_1': function () {
// do something here.
return this;
},
'fn_2': function () {
// do something here.
return this;
},
'fn_3': function () {
// do something here.
return this;
}
};
// call the full chain:
chain.fn_1().fn_2().fn_3();
// call only the middle.
chain.fn_2();
g.d.d.c's answer is best, but if you can't modify the object for some reason, you could do this:
var _oldFn2 = chain.fn_2
chain.fn_2 = function() { return; };
chain.fn_1();
chain.fn_2 = _oldFn2;
var chain = {
fn : ['fn1', 'fn2', 'fn3'],
call : function(name) {
var i = 0, pos = -1, l = this.fn.length;
for(i = 0; i < l; i += 1) {
if(this.fn[i] == name) {
pos = i;
}
if(pos !== -1) {
this[this.fn[i]]();
}
}
},
fn1 : function() {
alert('fn1');
},
fn2 : function() {
alert('fn2');
},
};
chain.call('fn1'); //chain
chain.fn1(); //single

Categories

Resources