Hi guys I am writing some code using the object literal pattern, I have function that returns a value:
'currentLocation': function() {
var cL = 0;
return cL;
},
I then need to update the variable 'cL' from another function like this:
teamStatus.currentLocation() = teamStatus.currentLocation() + teamStatus.scrollDistance();
This part is part of another function - however I get an error back stating: invalid assignment left-hand side
I am guessing I can not update the variable in this way, could anyone suggest a better method or point me in the right direction.
Any help would be greatly appreciated.
Going to add more code to highlight what I am trying to do:
'currentLocation': function() {
var cL = 0;
return cL;
},
'increaseTable': function() {
if (teamStatus.currentLocation() <= teamStatus.teamStatusTableHeight() ) {
teamStatus.currentLocation = teamStatus.currentLocation() + teamStatus.scrollDistance();
$("#tableTrackActual").animate({scrollTop: (teamStatus.currentLocation)});
$("#tableMembers").animate({scrollTop: (teamStatus.currentLocation) });
//console.log(teamStatus.currentLocation());
teamStatus.buttonRevealer();
}
}
As you can see increaseTable should update the value of currentLocation - help this sheds more light on what I am trying to achieve.
You're writing teamStatus.currentLocation() =, which calls the function teamStatus.currentLocation and tries to assign to the return value. That isn't valid. You want just teamStatus.currentLocation = — no function call.
The variable inside your function is completely private to that function (and any functions defined within it). If you need to create a number of functions that share a set of private variables, you can do that with a closure. For instance:
var Thing = (function() {
var thingWideData;
function getData() {
return thingWideData;
}
function setData(newData) {
thingWideData = newData;
}
return {
getData: getData,
setData: setData
};
})();
What that does is create a Thing object which has getData and setData functions available for it, which get and set the completely private thingWideData variable contained by the anonymous closure. More about this pattern here and here, although the latter of those is more about private methods than private data.
What your code produces is:
0 = 0 + <some number>
Which variable do you want to update? cL? You are declaring it in the function, you cannot assign a value to it from outside. Depending on the rest of your code, you might be better off with getters and setters:
var object = {
_cL = 0,
get currentLocation() {
return this._cL;
},
set currentLocation(value) {
this._cL = value;
}
}
then you can do:
teamStatus.currentLocation = teamStatus.currentLocation + teamStatus.scrollDistance();
Update:
Regarding IE: If currentLocation should actually be just a number, it might be sufficient to just declare it as property:
var obj = {
currentLocation: 0
}
Related
I have this code:
var createAllAreSelectedClickedHandler = function(selectablesArrayGetter) {
return function() {
var array = selectablesArrayGetter();
var desiredState = array.every(function(selectable) { return selectable.selected; }) ? false : true;
array.forEach(function(selectable) {
selectable.selected = desiredState;
});
};
};
Followed by this one:
function PromoViewModel() { this.registrations = [...] }
PromoViewModel.prototype.allEventsSelectedClickedHandler = createAllAreSelectedClickedHandler(function() { return this.registrations; }));
I can't manage to set the correct value of this. The "this" value when the function is created points to Window so I can't do .bind(this). I've tried doing .bind(PromoViewModel.prototype) but it lacks all the precious instance fields set inside the constructor.
I know I could simply set this.allEventsSelectedClickedHandler in the constructor function, but I'm trying to separate the methods creation from the variables.
The problem is the call selectablesArrayGetter(); which determines the this value for the callback.
You will need to "pass" the this value that the method (i.e. the closure you are returning) is invoked on, using call:
var array = selectablesArrayGetter.call(this);
I'd recommend defining your PromoViewModel.prototype.allEventsSelectedClickedHandler method as follows:
PromoViewModel.prototype.allEventsSelectedClickedHandler = function() {
var _array = this.registrations;
var desiredState = _array.every(function(selectable) { return selectable.selected; }) ? false : true;
_array.forEach(function(selectable) {
selectable.selected = desiredState;
});
};
the function that you're passing as callback uses this, but doesn't have the PromoViewModel context. You can ensure the method has the proper context by binding this to a variable.
function PromoViewModel()
{
var me = this;
this.registrations = [...];
this.allEventsSelectedClickedHandler = createAllAreSelectedClickedHandler(function() {
return me.registrations;
});
}
Working fiddle: http://jsfiddle.net/michaschwab/coegnL5j/9/ also has Bergi's answer in there (commented out) to show that that works just as well.
Ok here is what I did.
In the prototype definition instead of directly associating it to createAllAreSelectedClickedHandler function, I actually define a function that returns the createAllAreSelectedClickedHandler function. By doing this, I can define a variable (in this case protoScope) that maps this context when defined.
When doing that, if you put a break-point in the createAllAreSelectedClickedHandler function you will see that the selectablesArrayGetter value is correct (the acutal registrations array).
PromoViewModel.prototype.allEventsSelectedClickedHandler = function (){
var protoScope = this;
return createAllAreSelectedClickedHandler(function() {
return protoScope.registrations;
});
}
I'm trying to use eval() to evalute a mathematical string with variables and functions
ex: algo = "1+len+customfunction(6)"
So i have data for len and the function for customFunction.
They are obviously declared in different scope.
I tried with something like
process = function(vars, algo) {
return (function() {
algo = algo.toLowerCase();
return eval(algo);
}).call(vars);
};
I need to provide required functions and variables to eval. Items are in different scopes, how do i do that ?
Now I'm a bit lost and confused, is this even possible ?
I think using eval('var'+vName+'='+value) would be ok for vars but not suitable for functions.
EDIT: btw eval can be replaced with (new Function(algo))()
http://moduscreate.com/javascript-performance-tips-tricks/
i would move the required data to an object, which hold all required items. access is possible with any given string. this solution does not requires eval()
var data = {
customfunction: function (x) {
return Math.PI * x * x;
},
len: 5
};
var variable = 'len';
if (data[variable]) {
// do something
;
}
var fn = 'customFunction';
function evaluate(vars, algo) {
if (data[algo.toLowerCase()]) { //
return data[algo.toLowerCase()].call(vars);
} else {
// fallback
}
}
var process = evaluate(vars, algo);
OK here is what i've found :
we can't provide a context for eval
eval('1+1') can be replaced by ((new Function('1+1'))() and it's way faster
eval have different scopes, can't use eval('var a = 1'); eval('alert(a)');
So, i'v managed to :
create a string to initiate all vars : vars += 'var '+key+'='+JSON.stringify(value)+';'
replace at runtime my algo string functions with their full path :
var algo = 'f(x)+5*2', x = 5;
window.object.functions.x = function(a) { return a*2; };
So at runtime i replace x( with object.functions.x(
the code executed by eval finally is eval('object.functions.x(5)+5*2'); and output is 20 of course :)
It seems to work.
So, I have a large object called con in that object, I have many variables, numbered sort of like an excel sheet, b19, b20, b21, etc.
I am trying to return a value from each one, but when I do a console log, It logs the entire function, not just the return.
Here's how the object is set up:
var con = {
b13: function(){
return 12600.535*Math.sqrt((con.b14+459.4)/459.4)
},
b14: function(){
return 20;
}
}
$(document).ready(function(){
console.log(con.b13);
});
This outputs this into the console:
function(){
return 12600.535*Math.sqrt((con.b14+459.4)/459.4)
}
So how do I format this so that it outputs the actual number in the equation?
You need to make b13 and b14 properties with a getter function:
var con = {};
Object.defineProperty(con, "b13", {
get: function() {
return 12600.535*Math.sqrt((con.b14+459.4)/459.4);
}
});
Object.defineProperty(con, "b14", {
get: function() { return 20; }
});
This will cause con.b13 and con.b14 to call the given functions, returning whatever the functions return.
Try console.log(con.b13()); . You are logging the function definition not executing it.
you don't define the properties as functions...
var con = {
b13: 239487,
b12: 923748
};
edit: if some properties need to be functions you have to call them e.g. con.b14(), not con.b14 as a property
You can simply use es5 getters/setters.
var con = {
get b13() {
return 12600.535*Math.sqrt((con.b14+459.4)/459.4);
},
get b14() {
return 20;
}
};
The problem is that your object's properties are functions, but you are trying to call them as if they were values.
For example, if you wanted correctly log con.b13's value to the console, you would need to change the command to:
console.log(con.b13());
What this does is get what con.b13 returns rather than what it is.
If you don't want to go through the hassle of adding a () next to every reference, you can modify the object and define getters like this:
var con = {
get b13() {
return 12600.535 * Math.sqrt((con.b14 + 459.4) / 459.4)
},
get b14() {
return 20;
}
}
If you define the object like this, your original command console.log(con.b13) will work as intended.
I am trying to organize my code using the revealing module pattern.
I have a very basic question about how to set up a setter method.
$(document).ready(function() {
var designs = (function() {
var curRow,
setCurRow = function(val) {
curRow = val;
},
initTable = function() {
setCurRow(0);
};
return {
curRow : curRow,
setCurRow : setCurRow,
initTable : initTable
}
}) ();
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.curRow);
});
The problem is that i dont get the someNewVal in the console output, I get undefined instead! I have a feeling I am doing something pretty silly here.
You can also solve this in another way by understanding the scopes of the variables and functions involved.
When you return your object constructor { curRow: curRow ... }, that just initializes the object member named curRow to the value of the variable curRow in the scope of the anonymous function; it doesn't create any persistent connection between them.
Once the anonymous function returns, calling designs.setCurRow is updating the curRow variable in that scope exactly as you expect, but that variable is now totally inaccessible to the outside world -- there is no connection between it and the curRow member of designs.
You can solve this by making the setCurRow method operate on this.curRow, as in the other solutions. In that case you don't need to make curRow a variable in the original scope, since it's entirely unused. The other solution is to add a 'getter' method to your current one:
var designs = (function() {
var curRow,
setCurRow = function(val) {
curRow = val;
},
getCurRow = function() {
return curRow;
},
initTable = function() {
setCurRow(0);
};
return {
getCurRow : getCurRow,
setCurRow : setCurRow,
initTable : initTable
};
}) ();
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.getCurRow());
Because getCurRow and setCurRow are functions that are closed in the scope containing the variable varRow, they can reach back into that scope and access and change variables that are only accessible within it.
In this case making curRow a member of the object you return is probably simpler, but the other way is useful too since you can use it to create effectively private members and methods.
Looks like you want an object, not a module:
$(document).ready(function() {
var designs = {
setCurRow: function(val) {
this.curRow = val;
},
initTable: function() {
this.setCurRow(0);
},
curRow: 0
};
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.curRow);
});
The problem is that setCurRow sets the value of the variable curRow after designs.curRow has already been set. Consider something like this:
var a = 1;
b = a; // sets b = a = 1
b = 2; // sets b = 2; leaves a = 1
Your code is doing the same thing, but with object-properties and setter methods to make it look complicated. :-)
As ruakh pointed out, you never re-assign curRow on the returned object, so it is always the default value. Change it to:
setCurRow = function(val) {
this.curRow = curRow = val;
},
And everything should work*.
* At least mostly - you won't be able to use call and apply on setCurRow (or pass it to setTimeout or setInterval without binding it first to your object (designs), since this is bound at call time in JavaScript.
I'm attempting to create a function lookup in Javascript essentially mapping a data type to a function that does something for that data type. Right now I have something similar to:
var Namespace = Namespace || {};
Namespace.MyObj = function () {
var stringFunc = function(someData) {
//Do some string stuff with someData
};
var intFunc = function(someData) {
//Do some int stuff with someData
};
var myLookUp = {
'string': stringFunc,
'int' : intFunc
};
return {
PublicMethod: function (dataType, someData) {
myLookUp[dataType](someData);
}
};
} ();
When I invoke Namespace.MyObj.PublicMethod(dataType, someData) I get an error that myLookUp is not defined. I'm assuming I'm not going about setting up the function lookup object correctly, but not sure how to do so. Thanks for any help.
The problem might simply be incorrect case
myLookup[dataType](someData);
should be (notice the capital U)
myLookUp[dataType](someData);
Just looked at my post after I wrote it up, stupid oversight, I'm declaring the properties as strings, instead of just properties.
....
var myLookUp = {
string: stringFunc,
int: intFunc
};
....
Fixes the issue.
Some additional follow up, in my actual code dataType is the result of a jQuery select. Don't know why or if this would be browser dependant (I'm using FireFox), but using double quotes around the property definition works, single quotes does not, and no quotes works as well. :-\