Why does this addition result in NaN? [closed] - javascript

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I try to add prices to find the total, but console.log prints either NaN or just a repetition of the number :
This is my JavaScript code:
var qt_articles = new Array();
var tab_prix = new Array();
function print_nb_article(article, nb){
$('#top_ten_nb_'+article).text(nb);
var prix = $('#top_ten_nb_'+article+'_prix').val();
var prix_tt = $('.prix_'+article).text(prix*nb);
if (prix_tt > 0) tab_prix.push(prix_tt);
for(i=0; i<tab_prix.length; i++){
prix_global += parseFloat(tab_prix[i]);
console.log(prix_global);
}
}
$('#plus_veste').click(function() {
veste++;
print_nb_article('veste', veste);
return false;
});
My HTML:
<span id="prix_global">0</span>
Where is the problem?

Because you don't initialize prix_global. Add
var prix_global = 0;
In some browsers, it would be initialized to the element due to the id (but never to the parsed content of the span...). If you try to add to the initial value of the span, do
var prix_global = parseFloat(document.getElementById('prix_global').innerHTML);
... computations...
document.getElementById('prix_global').innerHTML = prix_global;
More generally, pay attention to the initialization of your variables (see also veste) and their parsing (you're lucky with prix*nb).

I see several issues, highlighted with comments:
var qt_articles = new Array();
var tab_prix = new Array();
function print_nb_article(article, nb) {
$('#top_ten_nb_' + article).text(nb);
var prix = $('#top_ten_nb_' + article + '_prix').val();
// Note 1: Below, `prix_tt` will be a jQuery object, not a string or number.
// You might want to set `prix_tt`, *then* set it as the text of the element.
var prix_tt = $('.prix_' + article).text(prix * nb);
// Note 2: So this comparison will compare `"[object Object]"` to `"0"`,
// and get `false`. This'll get fixed if you fix the above.
if (prix_tt > 0) tab_prix.push(prix_tt);
for (i = 0; i < tab_prix.length; i++) {
// Note 3: If the push *had* happened, here you'd be retrieving
// the object and trying to parse `"[object Object]"` as a number.
// This would also get fixed by the above.
// Note 4: You're not setting `prix_global` to `0` before the loop,
// so either it's `undefined` or you're going to get the wrong total
prix_global += parseFloat(tab_prix[i]);
console.log(prix_global);
}
// Note 5: Do you ever do anything with `prix_global`??
}
$('#plus_veste').click(function () {
veste++;
print_nb_article('veste', veste);
return false;
});
Also note that your'e not declaring i anywhere (the variable you use for your loop), so you're almost certainly falling prey to The Horror of Implicit Globals. That also applies to veste unless it's declared somewhere you haven't shown (and possibly others).
So to fix it:
Probably change the code under Note 1 to:
var prix_tt = prix * nb;
$('.prix_' + article).text(prix_tt);
Declare your variables in the innermost scope where you need them.
Set prix_global to 0 prior to the loop.
Do something with prix_global when you're done calculating it.
Other things I would do:
Get rid of the globals. You almost certainly don't need them.
Use [], not new Array(), to create arrays.

Related

The last two line of code unable two understand [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
function makeArmy () {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function() {
console.log(i);
};
shooters.push(shooter);
i++
}
return shooters;
}
let army = makeArmy();
army[0]();
army[5]();
i didnt understand this what-why this need for output
army[0]();
army[5]();
i know [0 and 5 are index numbers]
im not understaning why this army is calling two times and why we need to call this for output?
The army is an array of closures. Each closure print's the content of the variable i. But at the time that you execute the closure (e.g. when calling army[5]()) the while loop did already finish and thus i will always be 10. That is, because i was declared using the var keyword and thus the scope of i is the makeArmy() function. This is why army[0]() and army[5]() both print 10.
The code below is what you aim for:
Now i is passed into a let variable x and because the let keyword is used instead of var, the scope of x now is the individual shooter closure for that particular i-th iteration instead of the makeArmy function.
function makeArmy () {
var shooters = [] // <-- use var here
var i = 0 // <-- because they're simple variables
while (i < 10) {
let x = i // <-- use let here to make x a block-scoped local variable that is bound to the closure
const shooter = function() { // <-- use const here because you never change the shooter thus it's a simple constant
console.log(x)
}
shooters.push(shooter)
i++
}
return shooters
}
More details, explainations and simple examples can be found here.

Don't Repeat Yourself [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Would like to know if there is a better way to write this small block of code keeping DRY in mind. I see the similarities in the functions of course, but I am not sure how to shorten it. Also, I would like to know how much of a difference the shortening would make if any. Thank you, Jason
var adminAlert = {
alert: function() {
var sumAlert = sumSupport = sumCashout = sumPhone = 0;
$.getJSON("alertFeed.JSON", function(data) {
$.each(data.alertData, function(i, allAlerts) {
sumAlert += parseFloat(allAlerts.value);
sumSupport += parseFloat(allAlerts.support);
sumCashout += parseFloat(allAlerts.cashout);
sumPhone += parseFloat(allAlerts.phone);
$(".alertPoints").html(sumAlert);
$(".support-requests").html(sumSupport);
$(".cashout-giftcards").html(sumCashout);
$(".phone-verification").html(sumPhone);
});
});
}
};
The version undernearth is more DRY. Basically, to make your code DRY, you:
Identify repeated stuff. In your case it was parseFloat(allAlerts.foobar) and $(".blablabla").html(foobar);
Identify what is different between those repetitions. In your case you used a series of 4 keys within the allAlerts object: 'value', 'support', 'cashout' and 'phone'. Each of those 4 keys correspond to a CSS selector, e.g. cashout corresponds to ".cashout-giftcards";
Take what you identified in step 2 and put it into a declarative map. In your case:
{
'value': 'alertPoints',
'support': 'support-requests',
'cashout': 'cashout-giftcards',
'phone': 'phone-verification'
}
4. Replace what you identified in step 1 with a more unified / abstract code using the map you created in step 3. In your case, the four lines like sumCashout += parseFloat(allAlerts.cashout); can be replaced with only one line like sum[k] = parseFloat(allAlerts[k])
var
// To avoid repeatedly doing stuff like $(".alertPoints").html(sumAlert),
// we'll declare a concise map defining what will be updated by what:
map = {
'value': 'alertPoints', // later we will use this to update $(".alertPoints") with what comes from allAlerts.value
'support': 'support-requests', // later we will use this to update $(".support-requests") with what comes from allAlerts.support
'cashout': 'cashout-giftcards',
'phone': 'phone-verification'
},
adminAlert = {
alert: function(){
var
// Let's define an object that will hold the sums for us
sum = {},
// And also a variable to iterate our map;
k;
$.getJSON("alertFeed.JSON", function(data) {
$.each(data.alertData, function(i, allAlerts) {
// So we have 4 things to sum and update.
// They all are defined in our map.
// Lets go through the map and get things done:
for (k in map) {
// The value of k will be "value", "support" etc...
if (!(k in sum)) {
// In case the `sum` object does not yet have a key equal to the value of `k`, we initiate it.
// This is to have a start value of 0 to start adding to it:
sum[k] = 0;
}
// This is effectively the same as
// sumAlert += parseFloat(allAlerts.value) etc. etc.
// but written in unified manner to cover all the four cases.
// So when say `k` equals to `cashout`, this
// will be the same as `sum.cashout += parseFloat(allAlerts.cashout)`
sum[k] += parseFloat(allAlerts[k]);
// Again, a unified version of
// $(".alertPoints").html(sumAlert) etc. etc.
$('.' + map[k]).html(sum[k]);
}
});
});
}
};
In terms of difference — it is just easier to maintain / fix / debug / extend etc. Performance will probably be about the same.

String control in loops

I have a big question.
I have many Strings in my Programm and want to check these Strings on there values.
I wrote a Loop for it, but insted of the Definition of an String he is creating a new value. It's basicly really difficult to discribe, also because i am basicly German.
But i can give you my current code, so maybee you will see what I mean:
{
var Loch1G = $('#m1-Rundenanalyse-Datum').val(); //In the strings just the number is changing
var Loch2G = $('#m1-Rundenanalyse-Turnier').val();
x=1
while (x <= 2) {
if ("Loch" + x + "G" == ""){ //Next String is genrated (x=x+1)
alert("Eingabe war leer");
}
x=x+1
}
}
How can I solve this?
I'd suggest using an array to store the values you want to check:
var lochs = [];
lochs.push($('#m1-Rundenanalyse-Datum').val());
lochs.push($('#m1-Rundenanalyse-Turnier').val());
for (var i = 0, len = lochs.length; i < len; i++){
if (lochs[i] == ''){
alert("Eingabe war leer");
}
}
JS Fiddle demos: passes (no alert), fails (alert)
This suggestion is based on my presumption that you're trying to create the names of the vars you want to check, which won't work, whereas this approach lets you store all values (however many) in the same array and then iterate over that array to find any values that are equal to an empty string.
If you really want to stick with your current approach, you could do the following:
{
window.Loch1G = $('#m1-Rundenanalyse-Datum').val(); //In the strings just the number is changing
window.Loch2G = $('#m1-Rundenanalyse-Turnier').val();
var x=1;
while (x <= 2) {
if (window["Loch" + x + "G"] == ""){ //Next String is genrated (x=x+1)
alert("Eingabe war leer");
}
x=x+1;
}
}
But I can't think why you'd want to; plus the use of global variables is poor practice as it explicitly makes those variables available to every closure within the document, which allows them to be easily, and accidentally, overwritten.
In a reasonably up-to-date browser, that implements Array.prototype.every, you could dispense with the explicit iteration:
var lochs = [];
lochs.push($('#m1-Rundenanalyse-Datum').val());
lochs.push($('#m1-Rundenanalyse-Turnier').val());
if (!lochs.every(function(a){ return a !== ''; })) {
alert("Eingabe war leer");
}
JS Fiddle demos: passes (no alert), fails (alerts).

Do functions not wait for a finish in execution of line before they go on to the next line [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I am used to programming in python and am trying to learn javascript. I want the application to work on chrome so dont care to make it cross-browser. I also want to write it without using jquery or another library - since I am just learning javascript.
My general problem is that very often the function calls seem like they are "skipped". I am using firebug and dont see any errors on the console. So If I have two calls calls right after each other in a function
mydict_user_values = return_dict_of_user_names()
alert("I HAVE USER VALUES " + mydict_user_values.length)
// This next line gets called sometimes before the previous line so the values in the table filled in by next line are blank even though the dictionary above has the correct length
fill_user_name_values_into_table(mydict_user_values)
I am used to python and dont understand whats going on. Sorry for an abstract question , but there is something fundamental about javascript that I am not getting.
edited: -6 points in one day. I am quite shocked!. I know there are some serious newbie errors in my code: Which I have put here in all its newbie badness.
https://github.com/harijay/gridzilla_web
My Typical functions:
function return_dict_of_user_names()
{
var my_new_dict
var my_user_names = document.getElementsByClassName("my_users");
for (var i = 0; i <= my_user_names.length ; i++){
var a_num = document.getElementById("user_number_" + i).value
var a_name = document.getElementById("user_name_" + i).value
my_new_dict[i] = [a_num,a_name]
}
return my_new_dict
}
I then have other javascript functions that take these values and populate another part of the same page.
function fill_user_names_into_div(mydict){
var my_username_dict = mydict;
//Javascript code to fill in the values by lines like
my_fillable_elements = document.getElementsByClassName("user_table_fancy_entry")
for (var i = 0 ; i <= my_fillable_elements.length ; i++){
document.getElementById("usertable_user_number_" + i).value = my_username_dict[1][1]
}
Javascript statements are executed synchronously. I think you have some javascript errors that is probably halting execution in some places. You should be looking in an javascript error console or a debug console to see where you have javascript errors. For example, in this function:
function return_dict_of_user_names()
{
var my_new_dict
var my_user_names = document.getElementsByClassName("my_users");
for (var i = 0; i <= my_user_names.length ; i++){
var a_num = document.getElementById("user_number_" + i).value
var a_name = document.getElementById("user_name_" + i).value
my_new_dict[i] = [a_num,a_name]
}
return my_new_dict
}
You have to initialize my_new_dict to an array before using it as such like this:
function return_dict_of_user_names()
{
var my_new_dict = []; // initialize to empty array
var my_user_names = document.getElementsByClassName("my_users");
for (var i = 0; i < my_user_names.length ; i++) {
var temp = [];
temp.push(document.getElementById("user_number_" + i).value);
temp.push(document.getElementById("user_name_" + i).value);
my_new_dict.push(temp);
}
return my_new_dict;
}
Also, javascript statements should end with a semicolon and I'd recommend using .push() to add an item onto the end of an array.

alternatives for excessive for() looping in javascript

Situation
I'm currently writing a javascript widget that displays a random quote into a html element. the quotes are stored in a javascript array as well as how many times they've been displayed into the html element. A quote to be displayed cannot be the same quote as was previously displayed. Furthermore the chance for a quote to be selected is based on it's previous occurences in the html element. ( less occurrences should result in a higher chance compared to the other quotes to be selected for display.
Current solution
I've currently made it work ( with my severely lacking javascript knowledge ) by using a lot of looping through various arrays. while this currently works ( !! ) I find this solution rather expensive for what I want to achieve.
What I'm looking for
Alternative methods of removing an array element from an array, currently looping through the entire array to find the element I want removed and copy all other elements into a new array
Alternative method of calculating and selecting a element from an array based on it's occurence
Anything else you notice I should / could do different while still enforcing the stated business rules under Situation
The Code
var quoteElement = $("div#Quotes > q"),
quotes = [[" AAAAAAAAAAAA ", 1],
[" BBBBBBBBBBBB ", 1],
[" CCCCCCCCCCCC ", 1],
[" DDDDDDDDDDDD ", 1]],
fadeTimer = 600,
displayNewQuote = function () {
var currentQuote = quoteElement.text();
var eligibleQuotes = new Array();
var exclusionFound = false;
for (var i = 0; i < quotes.length; i++) {
var iteratedQuote = quotes[i];
if (exclusionFound === false) {
if (currentQuote == iteratedQuote[0].toString())
exclusionFound = true;
else
eligibleQuotes.push(iteratedQuote);
} else
eligibleQuotes.push(iteratedQuote);
}
eligibleQuotes.sort( function (current, next) {
return current[1] - next[1];
} );
var calculatePoint = eligibleQuotes[0][1];
var occurenceRelation = new Array();
var relationSum = 0;
for (var i = 0; i < eligibleQuotes.length; i++) {
if (i == 0)
occurenceRelation[i] = 1 / ((calculatePoint / calculatePoint) + (calculatePoint / eligibleQuotes[i+1][1]));
else
occurenceRelation[i] = occurenceRelation[0] * (calculatePoint / eligibleQuotes[i][1]);
relationSum = relationSum + (occurenceRelation[i] * 100);
}
var generatedNumber = Math.floor(relationSum * Math.random());
var newQuote;
for (var i = 0; i < occurenceRelation.length; i++) {
if (occurenceRelation[i] <= generatedNumber) {
newQuote = eligibleQuotes[i][0].toString();
i = occurenceRelation.length;
}
}
for (var i = 0; i < quotes.length; i++) {
var iteratedQuote = quotes[i][0].toString();
if (iteratedQuote == newQuote) {
quotes[i][1]++;
i = quotes.length;
}
}
quoteElement.stop(true, true)
.fadeOut(fadeTimer);
setTimeout( function () {
quoteElement.html(newQuote)
.fadeIn(fadeTimer);
}, fadeTimer);
}
if (quotes.length > 1)
setInterval(displayNewQuote, 10000);
Alternatives considered
Always chose the array element with the lowest occurence.
Decided against this as this would / could possibly reveal a too obvious pattern in the animation
combine several for loops to reduce the workload
Decided against this as this would make the code to esoteric, I'd probably wouldn't understand the code anymore next week
jsFiddle reference
http://jsfiddle.net/P5rk3/
Update
Rewrote my function with the techniques mentioned, while I fear that these techniques still loop through the entire array to find it's requirements, at least my code looks cleaner : )
References used after reading the answers here:
http://www.tutorialspoint.com/javascript/array_map.htm
http://www.tutorialspoint.com/javascript/array_filter.htm
http://api.jquery.com/jQuery.each/
I suggest array functions that are mostly supported (and easily added if not):
[].splice(index, howManyToDelete); // you can alternatively add extra parameters to slot into the place of deletion
[].indexOf(elementToSearchFor);
[].filter(function(){});
Other useful functions include forEach and map.
I agree that combining all the work into one giant loop is ugly (and not always possible), and you gain little by doing it, so readability is definitely the winner. Although you shouldn't need too many loops with these array functions.
The answer that you want:
Create an integer array that stores the number of uses of every quote. Also, a global variable Tot with the total number of quotes already used (i.e., the sum of that integer array). Find also Mean, as Tot / number of quotes.
Chose a random number between 0 and Tot - 1.
For each quote, add Mean * 2 - the number of uses(*1). When you get that that value has exceeded the random number generated, select that quote.
In case that quote is the one currently displayed, either select the next or the previous quote or just repeat the process.
The real answer:
Use a random quote, at the very maximum repeat if the quote is duplicated. The data usages are going to be lost when the user reloads/leaves the page. And, no matter how cleverly have you chosen them, most users do not care.
(*1) Check for limits, i.e. that the first or last quota will be eligible with this formula.
Alternative methods of removing an array element from an array
With ES5's Array.filter() method:
Array.prototype.without = function(v) {
return this.filter(function(x) {
return v !== x;
});
};
given an array a, a.without(v) will return a copy of a without the element v in it.
less occurrences should result in a higher chance compared to the other quotes to be selected for display
You shouldn't mess with chance - as my mathematician other-half says, "chance doesn't have a memory".
What you're suggesting is akin to the idea that numbers in the lottery that haven't come up yet must be "overdue" and therefore more likely to appear. It simply isn't true.
You can write functions that explicitly define what you're trying to do with the loop.
Your first loop is a filter.
Your second loop is a map + some side effect.
I don't know about the other loops, they're weird :P
A filter is something like:
function filter(array, condition) {
var i = 0, new_array = [];
for (; i < array.length; i += 1) {
if (condition(array[i], i)) {
new_array.push(array[i]);
}
}
return new_array;
}
var numbers = [1,2,3,4,5,6,7,8,9];
var even_numbers = filter(numbers, function (number, index) {
return number % 2 === 0;
});
alert(even_numbers); // [2,4,6,8]
You can't avoid the loop, but you can add more semantics to the code by making a function that explains what you're doing.
If, for some reason, you are not comfortable with splice or filter methods, there is a nice (outdated, but still working) method by John Resig: http://ejohn.org/blog/javascript-array-remove/

Categories