Don't Repeat Yourself [closed] - javascript

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.

Related

Multi-push vs. multi-map [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 days ago.
The community is reviewing whether to reopen this question as of 4 days ago.
Improve this question
I'm asked to get attributes collection out of an array object,
let a = [
{name:'aname',age:21},
{name:'bname',age:22},
{name:'cname',age:23},
{name:'dname',age:24},
{name:'ename',age:25},
{name:'fname',age:26},
{name:'gname',age:27}]
// wanted
let ok = {
names:'aname;bname;cname;dname;ename;fname;gname',
ages:'21;22;23;24;25;26;27'
}
and I got 2 ways of doing it:
alpha just using map of an array:
// alpha
let res = {
names:'',
ages:''
}
res.names=a.map(iter=>iter.name).join(';')
res.ages=a.map(iter=>iter.age).join(';')
//then return res
// ========================================================
and beta just iterate the array and append each attribute in the tabulation array:
// beta
let res = {
names:[],
ages:[]
}
a.forEach(iter=>{
res.names.push(iter.name)
res.ages.push(iter.age)
})
// then handle res's fields
ok.names = res.names.join(';')
ok.ages = res.ages.join(';')
so which way should I use to get the collection? Will alpha get slower or faster than beta when the objects in a get lots of fields(attrs)?
Both approaches are good. I'd say it depends on your personal preference what you'd want to use.
However, It seems to me that if you are aiming for performance, the following would yield better results.
let a = [
{name:'aname',age:21},
{name:'bname',age:22},
{name:'cname',age:23},
{name:'dname',age:24},
{name:'ename',age:25},
{name:'fname',age:26},
{name:'gname',age:27}]
let ok = { names: '', ages: ''}
for (let i = 0; i < a.length; i++){
const iter = a[i]
ok.names += iter.name + ";";
ok.ages += iter.age + ";";
}
ok.names = ok.names.slice(0,-1)
ok.ages = ok.ages.slice(0,-1)
console.log(ok)
This apporach eliminates the need to create new arrays or joining them (join is a heavy operation). Just create the string you want and at the end of it all, remove the one extra semicolon.
I consider that alfa is simpler and clearer for me, but I guess it is up to you...

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.

I want to create a little test-program with "dices" with javascript [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 4 years ago.
Improve this question
I am trying to figure out how I can create a "game" where I have three dices, and three bets. If any of the bets hits, I will be granted 1 point, else nothing happens.
Example variables and arrays I would like to use;
var points = 1;
var slot1 = Math.floor((Math.random()*6)+1);
var slot2 = Math.floor((Math.random()*6)+1);
var slot3 = Math.floor((Math.random()*6)+1);
var dices = [slot1, slot2, slot3];
function Bet(bet1, bet2, bet3) {
"NEED HELP WITH THE CODE HERE"
}
Bet(1,2,3);
Thanks alot for all kinds of help!
I think a nudge in the right direction is more appropriate than a ready-to-go answer, since your question smells a little bit like homework :-)
You basically need to cross-check each item from both lists. You can do this with either a nested for .. in loop or a call to .some() with a nested .contains(). The latter will give you the cleanest solution. Docs
Alternatively, you can use Tagas' solution but that would make your function less reusable. If the number of bets vary, you'll need to adjust your function..
Try this:
function rollDice() {
//generate a number between 1 to 6
return Math.floor(Math.random() * (6 - 1 + 1)) + 1;
}
function makeBet(bet1, bet2, bet3) {
let slot1 = rollDice(),
slot2 = rollDice(),
slot3 = rollDice();
console.log('Slot 1:', slot1);
console.log('Slot 2:', slot2);
console.log('Slot 3:', slot3);
if(bet1 == slot1 || bet2 == slot2 || bet3 == slot3) {
//return 1 point as there is a match
return 1;
}
//return nothing as there was no match
return 0;
}
//Make a bet!
makeBet(1, 2, 3);

Why does this addition result in NaN? [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 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.

How to pick a random function from a predefined set? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
If I have these functions defined:
function playZoomout() {
// do things
}
function playZoomin() {
// do things
}
function playPanright() {
// do things
}
function playPanleft() {
// do things
}
and am running this every four seconds:
var timer = setInterval(playZoomout,4000);
How can I replace "playZoomout" with a randomly selected function picked from the ones defined above? I'm looking for a jQuery or plain javascript solution.
Create an array of function references, then fetch an element randomly from the array and invoke it.
var fns = [playZoomout, playZoomin, playPanright, playPanleft]
setInterval(function () {
fns[Math.floor(Math.random() * fns.length)]();
}, 1000)
Demo: Fiddle
Add each functionname to an array, with numerical key indexing. Then, randomly generate a number between the lower and upper index and use a control structure to repeat the process.
Something like this should work (see http://jsfiddle.net/w6sdc/):
/* A few functions */
var a = function() {
alert("A");
}
var b = function() {
alert("B");
}
var c = function() {
alert("C");
}
/* Add the functions to an array */
var funcs = [a, b, c];
/* Select a random array index */
var i = Math.floor(Math.random() * 2) + 0;
/* Call the function at that index */
funcs[i]();
Wrapping the index selection and the function call in a setInterval should be straight forward from this point.

Categories