Evaluating Formula In Object for JS - javascript

I have the following object:
var data = {
'buyRate': ['Buy Rate', 0.15, 'enteredData.numberOfTransactions * enteredData.buyRate',
'setupFee': ['Setup Fee', 0.00, 'enteredData.setupFee'],
'numberOfTransactions': ['# of Trans.', 10, 'enteredData.numberOfTransactions']
}
enteredData is another object that pulls values from user inputs. Created after this object but it does exist
What I want to do is use the third position in the array as a formula to calculate a 'Total' which is displayed using a script like this (I run this after the object is created so the object keys are not undefined):
for (var key in data) {
var formula = data[key][2];
// evaluate the formula by some magic
var sum = new Function('return '+formula);
document.getElementBy(key+'Total').value = sum;
}
Because I am working in Google Sites using eval() is not an option for me. I've tried using var sum = new Function('return '+formula); and it's not working for me. I don't get any errors. And console.log displays (no other information):
function anonymous() {
return data.numberOfTransactions * data.buyRate
}
Not sure how else to approach this problem. Would appreciate a push in the correct direction.

If Google disallows eval, I would guess they also disallow running user-supplied code using your Function trick.
However, if this is not the case, you need to slightly change your function. MDN states:
Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called.
You'd therefore need to pass the correct variables, like this:
for (var key in data) {
var formula = data[key][2];
// create function
var my_func = new Function('data', 'return ' + formula);
// pass data explicitely
var sum = my_func(data);
document.getElementBy(key+'Total').value = sum;
}

The answers here helped me but after I figured out that Google Sites also don't allow creating function constructors I approached this a different way that allowed me keep the logic that I wanted.
Below the is the updated object. I simply rewrote my formula as a tiny function that I can call:
var data = {
'buyRate': ['Buy Rate', 0.15, function() {return enteredData.numberOfTransactions * enteredData.buyRate;},
'setupFee': ['Setup Fee', 0.00, function() {return enteredData.setupFee;}],
'numberOfTransactions': ['# of Trans.', 10, function() {return enteredData.numberOfTransactions;}]
}
This will run the formula every time I call it and not when the object is rendered.
My updated For...in loop looks like this:
for (var key in data) {
var sum = data[key][2];
document.getElementBy(key+'Total').value = sum();
}
Hope this will help someone in the future.

Related

How do i simplify a block of code that ParseInt Retrieves from localstorage variables

I have this game which i am designing where i store 1 or 0 values as correct or incorrect answers in the local storage in variables q1 - q6.
Since local storage doesnt store numbers as integers, before my main page loads i parseInt all of my variables to get the integers. Although some of them havent been declared as anything yet so they seem to be NaN or null, so when i try to compute the addition of all of the variables, it gives me NaN unless i use this mess of a code.
if (isNaN(totalpoints)) totalpoints = 0;
if (localStorage.getItem("points") === null){
localStorage.setItem("points", "0");
}
var q0 = parseInt(localStorage.q0);
var q1 = parseInt(localStorage.q1);
var q2 = parseInt(localStorage.q2);
var q3 = parseInt(localStorage.q3);
var q4 = parseInt(localStorage.q4);
var q5 = parseInt(localStorage.q5);
var q6 = parseInt(localStorage.q6);
if (isNaN(q0))q0=0;
if (isNaN(q1))q1=0;
if (isNaN(q2))q2=0;
if (isNaN(q3))q3=0;
if (isNaN(q4))q4=0;
if (isNaN(q5))q5=0;
if (isNaN(q6))q6=0;
var totalpoints = totalpoints + q0 + q1 + q2 + q3 + q4 + q5 + q6;
localStorage.setItem("points", totalpoints);
I am trying to think of a way where i can simplify this code into maybe a few lines using a loop for the variables possibly or something?
Can anyone give me any sense of direction on how i can approach this or help me possibly?
Im just not sure as it seems like i got to parseInt the localstorage variables all individually?
Thanks
Rather than having multiple separate numeric-indexed properties, consider using a single array instead:
const qArr = localStorage.qArr
? JSON.parse(localStorage.qArr)
: new Array(7).fill(0);
Then, instead of assigning to the q variables, assign to an index of the qArr, and to save it, use JSON.stringify:
qArr[3] = 555;
localStorage.qArr = JSON.stringify(qArr);
To add up all the items in the array, you can use reduce:
totalPoints = qArr.reduce((a, b) => a + b, totalPoints);
Since it sounds like this is all in one self-contained script, I'd highly recommend consolidating all the relevant items that need to be stored into a single object too, if at all possible, so as not to pollute localStorage with lots of separate properties that really deserve to be in a single place, rather than spread out, eg:
const dataObj = localStorage.pointsData
? JSON.parse(pointsData)
: {
totalPoints: 0,
qArr: new Array(7).fill(0)
};
Then, do stuff with dataObj.totalPoints and dataObj.qArr, and when you need to save it, do something like:
localStorage.pointsData = JSON.stringify(dataObj);
I would suggest an object.
You can store object as answers in localStorage and update the values.
So suppose answers object is something like this
answers = {
q0: 10,
q2: 20
}
Then it won't matter whether key is present or not, as you can loop through object to get total sum
let total = 0;
for (const key in answers) {
total += answers[key];
}
Of course you have to store that object in localStorage like this
localStorage.setItem('answers', JSON.stringify(answers));
And while getting you have to parse it
const answers = JSON.parse(localStorage.getItem('answers'));
I suggest to replace multiple values with one single array.
So, your saving function could be something like this:
function savePoint(point) {
var points = JSON.parse(localStorage.points || "[]");
points.push(point);
localStorage.points = JSON.stringify(points);
}
And you will calculate the total like this:
function calculateTotal() {
var points = JSON.parse(localStorage.points || "[]");
return points.reduce(function(total, point) {
return total + point;
}, 0);
}
Anyway, I suggest to think about a data model to store the points and using JSON.stringify + JSON.parse to store it in localStorage.
Since you have points q0 - q7 plus the points, there are 8 variables. Now, if we carefully go through your code, things that are common
You fetch a variable from a local storage
You convert it to integer
You check whether it is NaN. If NaN, you set to 0.
Finally, you use the variable to calculate the sum
Okay. So we will try to write a function that does steps 1-3 with
function oneForAll(variableName){
if (localStorage.getItem(variableName) === null){
localStorage.setItem(variableName, "0");
}
var variable = parseInt(localStorage.getItem(variableName));
if (isNaN(variable)) {
variable = 0;
}
return variable
}
I basically used most of your lines so that you can relate to it.
Now, for step 4, we need to use our function to get the total sum. Also, we need a loop.
var listOfVariables = ["points", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7" ]
var totalPoints = 0;
// loop over the list of variables
listOfVariables.forEach(variableName => {
totalPoints += oneForAll(variableName);
});
// finally you set the new calculated total points
localStorage.setItem("points", totalpoints);
Hope this is helpful.

Tensorflow.js Please make sure the operations that use variables are inside the function f passed to minimize()

I have started to use javascript and TensorFlow.js to work on some machine learning projects, I am working on creating a linear regression model, however, I cannot figure out what is causing this error
Can not find a connection between any variable and the result of the loss function y=f(x). Please make sure the operations that use variables are inside the function f passed to minimize()."
I have created two Tensors
globalTensorXs = tf.tensor2d(globaArrayXs); //input data
globalTensorYs = tf.tensor1d(globaArrayYs); //y output
I have created the coefficients/weights as below as an array of tf scalars.
function createWeights(_numWeights)
{
for ( var x = 0; x < _numWeights; x++)
{
globalWeightsTensorArr.push(tf.variable(tf.scalar(Math.random())));
}
}
There is A training function which I pass the x and y Tensors into, it is the call to the optimise.minimize that causes the issue. it does not detect the variable for training, which are stored in globalWeightsTensorArr
async function train(xsTensor, ysTensor, numIterations)
{
/*//////OPTIMISER.MINIMISE/////////////
Minimize takes a function that does two things:
It predicts y values for all the x values using the predict
model function.
It returns the mean squared error loss for those predictions
using the loss function. Minimize then automatically adjusts any
Variables used by thi predict/loss function in order to minimize
the return value (our loss), in this case the variables are in
"globalWeightsTensorArr" which contains the coefficient values
to be altered by the modeld during "numIterations" iterations of
SGD.
*/
for (let iter = 0; iter < numIterations; iter++)
{
optimiser.minimize(function ()
{
return loss(predict(xsTensor), ysTensor);
}, globalWeightsTensorArr);
}
}
// the predict and loss function are here...
//The following code constructs a predict function that takes inputs(X's) //and returns prediction Y: it represents our 'model'. Given an input //'xs' it will try and * predict the appropriate output 'y'.
function predict(_Xs)
{
return tf.tidy(() => {
for ( var x = 0; x < 8; x++)
globalWeightsArr[x] = globalWeightsTensorArr[x].dataSync();
const weightTensor = tf.tensor1d(globalWeightsArr);
const prediction = tf.dot(_Xs, weightTensor);
return prediction;
});
}
//The loss function takes the predictions from the predict function
//and the actual lables and adjusts the weights
//the weights are considered to be any tensor variable that impact the //function We can define a MSE loss function in TensorFlow.js as follows:
function loss(_predictedTensor, _labels)
{
const meanSquareError =_predictedTensor.sub(_labels).square().mean();
return meanSquareError ;
}
can anyone please help explain the problem?
Regards
Aideen
We resolved the issue by changing the way the weights/coefficients were created. Now minimize can detect the variables used by predict, and it adjusts them accordingly. later I will post the entire solution to codepen. still learning!
function createWeights(_numWeights) {
const randomTensor = tf.randomUniform([_numWeights, 1]);
globalWeightsTensorVar = tf.variable(randomTensor);
}
here is the predict function used b
function predictLogical(_Xs) {
return tf.dot(_Xs, globalWeightsTensorVar);
}
The issue is related to tf.variable. One needs to use tf.variable to create the weights that will be updated by the function created by optimiser.minimize().
A variable created by tf.variable is mutable contrary to tf.tensor that is immutable. As a result if one uses tf.tensor to create the weights they could not be updated during the training

What is use of $.map function in javascript?

Note: I just want to to understand what is $.map doing in following code..
I am working on openstack horizon,In one of the javascript file they are using $.map function Please seehorizon.d3linechar.js
My question is how $.map is works, what is $ before map. $.map is associated with javascript or jquery..
$.map(self.series, function(serie) {
serie.color = last_point_color = self.color(serie.name);
$.map(serie.data, function(statistic) {
// need to parse each date
statistic.x = d3.time.format.utc('%Y-%m-%dT%H:%M:%S').parse(statistic.x);
statistic.x = statistic.x.getTime() / 1000;
last_point = statistic;
last_point.color = serie.color;
});
});
Please read the jQuery documentation. Their are many many examples. Our folk is realy trying to help you. But what is the lack of your understanding in the $.map() function?
$ is only the namespace and makes at least the map function work. So forget about it.
map( input, outputFunction ) is iterating through the input which has to be an real array. The outputFunction, usually a self executing function, is able to manipulate the content of each element of the inputed array.
In your example:
$.map(self.series, function(serie) {
self.series is the input and each element of that array will be called as serie in the anonymous or rather self executed function.
serie.color = last_point_color = self.color(serie.name);
Change some color stuff...
$.map(serie.data, function(statistic) {
Next call of the mapping function.
// need to parse each date
statistic.x = d3.time.format.utc('%Y-%m-%dT%H:%M:%S').parse(statistic.x);
Parsing the date to a specific format like discribed in the comment.
statistic.x = statistic.x.getTime() / 1000;
Take the x value parse to a time or maybe to seconds and divide through 1000.
last_point = statistic;
Save element of serie.data to a temporar variable.
last_point.color = serie.color;
Save the color of the of the serie to the element of that serie.
});
});
All in all...
... $.map() iterates through self.series, then iterates through its children and then it looks like it changes the color of every single element to the color of that series.
$ is an alias for the jQuery object.
As for map(), it is an api function in jQuery used to convert the items in an array.
If you look at the source for map, the basic algorithm is to iterate over the passed in elems and obtain a converted value using the callback
function (elems, callback) {
var value, i = 0,
length = elems.length,
ret = [];
for (; i < length; i++) {
//alternatively, for objects, for (i in elems) {
value = callback(elems[i], i);
if (value != null) {
ret.push(value);
}
}
// Flatten any nested arrays
return concat.apply([], ret);
}

Passing array of objects to a js function

i am trying for the first time to implement OOP in javascript and i got stuck on a recursive function when i try to send an array of objects to this function. So, i have the "Pitic" class (pitic means midget in romanian) with some propreties:
function Pitic(piticID) {
this.id = piticID;
this.inaltime = null;
this.greutate = null;
this.genereazaGreutate();
this.genereazaInaltime();
}
I'm now generating some midgets and storing them in the public piticiCollection Array variable. The "genereazaGreutate" and "genereazaInaltime" are function to generate random values for the inaltime and greutate values.
var pitic = new Pitic(idPitic);
piticiCollection.push(pitic);
The problem appears when i try to send the array of midgets to a function because all i get is only the first item of the array.
So, before i call the function, i have piticiCollection array with 4 objects:
midgets are safe and sound http://img443.imageshack.us/img443/484/yr4f.png
And as soon as i call the function with the piticiCollection as a parameter i loose 3 midgets! :(
most of the midgets are gone http://img201.imageshack.us/img201/5808/7od5.png
p.s. please excuse me for my bad english..
[EDIT]
Here is a fiddle of my full code: http://jsfiddle.net/WT7Ud/ I call the function on line 56 and as soon as the debugger hits line 60 i loose array items.
I have solved my problem by creating a copy of the array before using it in the function. Strange :(
function determinaPerechi(somePitici) {
var piticDeComparat, colectieDePiticiCopy;
colectieDePiticiCopy = somePitici;
for (var i = 1; i < colectieDePiticiCopy.length; i++) {
var piticDeComparat2 = null;
piticDeComparat = colectieDePiticiCopy[0];
piticDeComparat2 = colectieDePiticiCopy[i];
if (piticDeComparat.inaltime < piticDeComparat2.inaltime) {
//Perechea poate fi prietena
}
}
//colectieDePiticiCopy.splice(0, 1);
if (colectieDePiticiCopy.length == 0) {
//alert("finish");
return;
}
determinaPerechi(colectieDePiticiCopy);
//test(ttt);
}
Your determinaPerechiPosibile is modifying the original array on this line:
colectieDePitici.splice(1, colectieDePitici.length);
In particular, it is removing all but the first element. You probably should be using slice to non-destructively extract the part of the array you want to recurse on.
As Ted Hopp mentioned, the problem appears to be the line
colectieDePitici.splice(1, colectieDePitici.length);
in combination with this line:
determinaPerechiPosibile(colectieDePiticiCopy);
If those two lines are commented out, the array maintains its original length.

JSON corrupted attributes

I'm having difficulties understanding behavior of Javascript.
Code:
function getPosition(element){
var position = {
x:$(".line div").has(element).index(),
y:$(".line").has(element).index()
};
console.log(position.y);
console.log(position)
return position;
}
Now while calling it from function I'm getting results like this:
0
Object
x: 8
y: 3
What I don't understand is how is it possible to change object attributes when trying to access it via object reference, but not directly.
But when I call same function from console I get this:
0
Object
x: 8
y: 0
This is the same element passed to function. And it seems that it fails always when X or Y is 0(zero), when it's another number it's ok.
Could anyone explain what I'm doing wrong? Or is it somekind of JS bug? O_o
EDIT:
So I finally found out what the problem was. I always thought that I was passing values but unfortunately I was wrong all the time. During some searches on stackoverflow, I found topic about JS values and references.
If anyone is interested and too lazy to read the topic, you can look at this example. It's pretty much self explanatory.
function test(){
var a = 5;
var b = a; //b now has value of 5
console.log("a:"+a+":b:"+b);
b = 4;//a still has value of 5 and b is assinged to 4
console.log("a:"+a+":b:"+b);
var c = {val:1};
var d = c; //d now has reference to c
d.val = 2; //c.val changes because it is a reference
console.log(c);
}
EDIT2:
oh and by the way, how can I mark my question as answered?
console.log delays converting values to string until the application slows down so that logging doesn't slow down the application unnecessarily.
If the console.log(position) is showing a value that is different from that at the time console.log was called its because the position has been modified between the call and the time the console widget decided to format the value for display.
You can see this by trying the following HTML:
<script>
// Emits the JSON form when converted to a string.
var obj = {
x: 1,
toString: function () {
return JSON.stringify(this);
}
};
console.log(obj); // Often {x:2}
console.log("" + obj); // Reliably {x:1}
obj.x = 2;
</script>
Look for code that does something like
obj = getPosition(...);
...
obj.y = <expression that evaluates to zero>
Alternatively, you can force eager formatting by changing
console.log(position)
to
console.log("" + position)
So I finally found out what the problem was. I always thought that I was passing values but unfortunately I was wrong all the time. During some searches on stackoverflow, I found topic about JS values and references.
If anyone is interested and too lazy to read the topic, you can look at this example. It's pretty much self explanatory.
function test(){
var a = 5;
var b = a; //b now has value of 5
console.log("a:"+a+":b:"+b);
b = 4;//a still has value of 5 and b is assinged to 4
console.log("a:"+a+":b:"+b);
var c = {val:1};
var d = c; //d now has reference to c
d.val = 2; //c.val changes because it is a reference
console.log(c);
}

Categories