The "return" statement - javascript

I had a question about the return statement that is by itself in the control flow.
var rockPaperScissors = function(n) {
var rounds = n;
var results = [];
var weapons = ['rock', 'paper', 'scissors'];
var recurse = function(roundsLeft, played) {
if( roundsLeft === 0) {
results.push(played);
return;
}
for(var i = 0; i<weapons.length; i++) {
var current = weapons[i];
recurse( roundsLeft-1, played.concat(current) );
}
};
recurse(rounds; []);
return results;
}
I was wondering why the return statement is not written as:
return results.push(played);
Is there any benefits? If so, why and when should you write it that way?

That's because recurse is only being used for its side-effects (namely, for what it does to results), not its value. The return is still necessary so that the recursion bottoms out, but other than that, there is no reason to return anything from recurse.

return; is the same as return undefined;, so basically return nothing.
It is the same effect as if the function would finish without a return statement.
return results.push(played); returns the result of results.push(played);, which may not be undefined.
If you ignore the return value of your function recurse, there is no difference, which is the case in your function rockPaperScissors.

Related

Return inside for loop return initial value

I have a problem to understand why does RETURN in FOR loop returns me always initial fact value (let fact = 1):
const factorial = function(a) {
let fact=1;
if(a===0){
return 1;
}
else{
for(let i=1; i<=a; i++){
fact*=i;
return fact;** // This return
}
return fact
}
return fact;
};
//Result for all values e.g 1,5,10 is always 1, as in initial let fact =1
And when I remove it, my factorial function works totally fine. I have no idea why does it happen:
const factorial = function(a) {
let fact=1;
if(a===0){
return 1;
}
else{
for(let i=1; i<=a; i++){
fact*=i;
//Nothing
}
return fact
}
return fact;
};
// Code works fine, I receive factorial correctly
I was expecting to return factorial of my initial value. Instead I receive the initial variable value(1).
If I've understood your question correctly, you are wondering why did you get a return value of 1 in the first code regardless of the input value. That is because you had a return statement inside your for loop, which meant that your for loop would only be entered once and then exited with a return value of 1. Essentially, for loop never iterates, which means that you never get to calculate the value of factorial as fact = 1 * 2 * 3 * ..., you only do the initial step, which is fact = 1.
const factorial = function(a) { // <- you have tested this with 1,5 and 10
let fact=1; // <- here you set fact variable to value of 1
if(a===0){ // <- you check if you sent value is equal to 1,
return 1; // since you have used 1, 5 and 10 you will not be returning a value of 1 here
}
else{ // <- you enter this block of code when the value of a≠0
for(let i=1; i<=a; i++){ // <- you set the value of i to 1 and you enter the for loop
fact*=i; // <- you multiple your fact value, which is 1, with a value of i, which is also 1, which means you will get fact=1
return fact; // <- you return a value of fact, which is 1 here!
}
return fact
}
return fact;
};
return operator does not breaking only for loop: it goes deeper and stops whole function.
So, when you left return inside for without any condition, the return stops whole function at the first iteration of that loop (when fact is 1).
That means, that your code:
const factorial = function(a) {
let fact=1;
if(a===0){
return 1;
}
else{
for(let i=1; i<=a; i++){
fact*=i;
return fact; // This return
}
return fact
}
return fact;
};
In fact, is equal to:
const factorial = function(a) {
let fact=1;
if (a === 0){
return 1;
} else {
let i = 1;
fact *= i;
return fact;
}
};
Example of valid condition for return operator inside for loop:
function isAnyStringInside(values) {
for (let i = 0; i < values.length; i += 1) {
if (typeof values[i] === 'string') {
return true;
}
}
return false;
}
isAnyStringInside([1,2,3,4,5,'Hello',2,3,4,5]); // true
isAnyStringInside([1,2,3,4,5,2,3,4,5]); // false

Why does this function not work within the eventListener?

I am just starting with JavaScript and for my first project I am trying to display a working calculator using JS, HTML and CSS. I am just one step away from it finally handling easy operations but for some reason my "solver"-function does not work when hitting the Enter-button.
I already tried out all the functions in a "test.js" console.logging the results and everything worked perfectly. But for some reason it won't work when combining it with the eventListener and trying to display it within the textfield. I also tried simpler functions and displaying only variables in the textfield which works. It is just the solver-function that won't.
I will attach my code - most of you would definitely code a calculator much different and especially much shorter than the way I did it but I am proud I got this far, so please don't judge me too harshly! :D
First the declaration of functions which worked perfectly in the test.js. The solver was originally designed to return the previous 4 functions in a nested way but I thought this might be the problem, so I changed it.
function adds(num1, num2) {
return num1+num2;
};
function subs(num1, num2) {
return num1-num2;
};
function muls(num1, num2) {
return num1*num2;
};
function divis(num1, num2) {
return num1/num2;
};
//Creates an array with string elements.
function createArray(string) {
let array = [];
for(let element of string) {
array.push((element));
}
return array;
};
//Returns an array where numbers are joint within one element (e.g. '1','2' becomes '12').
function joinNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] =numArray[index] + array[i];
}
return numArray;
};
//Returns an array where all elements with numbers in them are changed to proper numbers instead of strings.
function makeNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] = parseInt(array[i]);
}
return numArray;
};
//Calculates the array that is provided and returns a single number as solution.
function operate(array) {
let solution = array[0];
for(let iOp = 1; array.length >= iOp; iOp=iOp+2) {
if(array[iOp] === '+') {
solution = adds(solution, array[iOp+1]);
}
if(array[iOp] === '-') {
solution = subs(solution, array[iOp+1]);
}
if(array[iOp] === '*') {
solution = muls(solution, array[iOp+1]);
}
if(array[iOp] === '/') {
solution = divis(solution, array[iOp+1]);
}
}
return solution;
};
//Takes a string (meant to be the value of a textfield) and returns the solution by calling all previously declared helper functions.
function solver(string) {
let cr = createArray(string);
let jo = joinNums(cr);
let ma = makeNums(jo);
let op = operate(ma);
return op;
};
Now on to the input field and hitting the enter-button:
//This is the enter-button
let enter = document.getElementById("enter");
//This is the textfield where calculations are entered. The textfield is then meant to be changed to display the operations result.
let textfield = document.getElementById("resultLn");
//The eventlistener.
enter.addEventListener("click", () => {
textfield.value = solver(textfield.value);
});
You do not use let statement at the for cycles i operand (at function joinNums, makeNums).
In addition at function operate, you can use switch.
Hi,
Your calculator code works well, If there was a problem, checkout your html.
I test with some operations and it works well. If there any operation doesn't work, please type this operation to help you
//This is the enter-button
let enter = document.getElementById("enter");
//This is the textfield where calculations are entered. The textfield is then meant to be changed to display the operations result.
let textfield = document.getElementById("resultLn");
//The eventlistener.
enter.addEventListener("click", () => {
textfield.value = solver(textfield.value);
});
function adds(num1, num2) {
return num1+num2;
};
function subs(num1, num2) {
return num1-num2;
};
function muls(num1, num2) {
return num1*num2;
};
function divis(num1, num2) {
return num1/num2;
};
//Creates an array with string elements.
function createArray(string) {
let array = [];
for(let element of string) {
array.push((element));
}
return array;
};
//Returns an array where numbers are joint within one element (e.g. '1','2' becomes '12').
function joinNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] =numArray[index] + array[i];
}
return numArray;
};
//Returns an array where all elements with numbers in them are changed to proper numbers instead of strings.
function makeNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] = parseInt(array[i]);
}
return numArray;
};
//Calculates the array that is provided and returns a single number as solution.
function operate(array) {
let solution = array[0];
for(let iOp = 1; array.length >= iOp; iOp=iOp+2) {
if(array[iOp] === '+') {
solution = adds(solution, array[iOp+1]);
}
if(array[iOp] === '-') {
solution = subs(solution, array[iOp+1]);
}
if(array[iOp] === '*') {
solution = muls(solution, array[iOp+1]);
}
if(array[iOp] === '/') {
solution = divis(solution, array[iOp+1]);
}
}
return solution;
};
//Takes a string (meant to be the value of a textfield) and returns the solution by calling all previously declared helper functions.
function solver(string) {
let cr = createArray(string);
let jo = joinNums(cr);
let ma = makeNums(jo);
let op = operate(ma);
return op;
};
<input type="text" id="resultLn">
<button id="enter">Enter</button>

How to replace return on if condition?

Is possible to replace by if condition instead using return while we have many condition in our program
var v2=[12,23,44,3,1,3,456,78,22];
function checkresult(v2) {
return v2 >= 18;
}
var a= v2.filter(checkresult);
document.getElementById("demo").innerHTML = a;
Yes, you can obviously use conditional statements inside a filter as long as you're returning a boolean value.
var v2=[12,23,44,3,1,3,456,78,22];
function checkresult(val) { // A suggestion to use different variable name other than v2
if(val >= 18)
return true;
else if(<condition-2>)
return true;
else if(<condition-n>)
return true;
return false;
}
var a= v2.filter(checkresult);
document.getElementById("demo").innerHTML = a;
Yes, it is possible
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var a = [1,2,'a','b','a',1,'c'];
var unique = a.filter(onlyUnique);
As example this code, onlyUnique function is return unique values in array. You can change the function content.

Comparing values between two arrays

I'm trying to set up a function that checks if a word or a text is a palindrome. To do that, it splits the text so that every letter is an element of a new array, it takes rid of the white spaces and it makes the reverse array.
Then it checks if every element of the two arrays, at the same positions, are equal. If not it returns false, if yes it returns true.
Here the function:
function palindrome(str) {
var low = str.toLowerCase();
var newArray = low.split("");
var noSpace = newArray.filter(function(val) {
return val !== " ";
});
var reverse = noSpace.reverse();
function check (a, b) {
console.log(`checking '${a}' against '${b}'`);
var partial;
var result = 1;
for (var i = 0; i < a.length; i++) {
console.log(`comparing '${a[i]}' and '${b[i]}'`);
if (a[i] !== b[i]) {
result = 0;
} else {
partial = 1;
result *= partial;
}
}
return result;
}
var result = check(noSpace, reverse);
if (result == 1) {
return true;
} else {
return false;
}
}
palindrome("r y e");
I don't know what's wrong but it seems that the function keeps on returning a true value no matter what word or text I pass to the function. What is wrong with that?
Your issue seems to be because reverse() changes the actual array as well. So doing
var reverse = noSpace.reverse();
Will reverse noSpace and assign a reference to it on the variable reverse. That is, both arrays will be the same (reversed) array.
To bypass that, I've used .slice() to create a copy of the original array, and then called .reverse() on that new array, ridding you of any conflicts.
Here's a working snippet of what it looks like:
function palindrome(str) {
var str_array = str.toLowerCase().split("");
var no_space = str_array.filter(function(val) {
return val !== " ";
});
// By applying '.slice()', we create a new array
// reference which can then be reversed and assigned
// to the 'reverse' variable
var reverse = no_space.slice().reverse();
function check(a, b) {
var partial;
var result = 1;
for(var i=0; i < a.length; i++) {
if(a[i] !== b[i]) {
// We don't need to keep
// comparing the two, it
// already failed
return 0;
} else {
// I've kept this part even though
// I don't really know what it is
// intended for
partial = 1;
result *= partial;
}
}
return result;
}
return check(no_space, reverse) === 1;
}
console.log(palindrome("a b a"));
console.log(palindrome("r y e"));
The way you have coded for palindrome is way too complicated.
But there is one problem with your code: when you do a reverse() it changes the original array as well.
So you will need to make sure that you copy it via slice().
Also you can directly send a boolean result rather than doing a 1 and 0.
At result *= partial;, 1 * 1 will always equal 1
I didn't correct your code, but here is a optimized solution for you.
function palindrom(string) {
var arr = string.split("");
var lengthToCheck = Math.floor(arr.length / 2);
for (var i = 0; i < lengthToCheck; i++) {
if (arr[i] != arr[arr.length - (1 + i)]) {
return false;
}
}
return true;
}
First I split the array after every charater of the passed String. After that I get the half of the length of the array as it's enough to check just one half.
With the for-loop I compare the first half with the second half. As soon as I found two characters that do not match I return false. In case the whole first half matches the second half of the array, the for-loop will be completed and after that true will be returned.
What's actually happening is .reverse() reverses an array in place, it then stores a reference to that array which is not what you're calling in your check() method.
Simple fix would be to change your if statement:
if (a[i] !== b.reverse()[i])

In angular updating one variable inexplicably updates another

I am using angular and plotly to plot either the raw data or a moving average. I have the moving average working but I am running into an issue with assigning variables. I retrieve an array of user objects which each have an x and y key with arrays associated with them.
$scope.init=function(){
$rootScope.page='companyResults';
$scope.isPlotlyDone = false;
$scope.moving = false;
var refresh = function () {
incidentService.dayWiseTripsByUser(...).then(function (plotArray){
$scope.unaffectedPlot = plotArray;
$scope.movingAveragePlot = allMoving(plotArray);
console.log($scope.unaffectedPlot[0].y);
console.log($scope.movingAveragePlot[0].y);
});
};
refresh();
}
Im that code block, I would expect that $scope.unaffectedPlot[0].y and $scope.movingAveragePlot[0].y would have different arrays since I ran the latter through the following set of functions. The curious thing is that both $scope variables are synced, so if I run the second through allMoving the unaffectedPlot variable also gets smoothed and neither get synced obviously if I don't call allMoving. What am I missing about Angular? What is a good way to have a moving average work with a toggle? My plan is to show one variable or the other depending on if a button is clicked.
var d3_numeric = function(x) {
return !isNaN(x);
}
var d3sum = function(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (arguments.length === 1) {
// zero and null are equivalent
while (++i < n) if (d3_numeric(a = +array[i])) s += a;
} else {
while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
}
return s;
};
var movingWindowAvg = function (arr, step) {
return arr.map(function (_, idx) {
var wnd = arr.slice(idx - step, idx + step + 1);
var result = d3sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }
return result;
});
};
var allMoving = function(pltArray) {
var movingArray = [];
pltArray.forEach(function(plot){
var oneMoving = plot;
oneMoving.y = movingWindowAvg(plot.y, 5);
movingArray.push(oneMoving);
});
return movingArray;
}
This actually isn't an angular issue. I had to test it some since I didn't see what was going on either.
When you wrote
oneMoving.y = blah
you were actually altering the contents of plot for each element and in turn altering the contents of plotArray unintentionally (since plot is an object)
So you are only creating a reference variable when you say 'var onMoving = plot' )
To outright solve your problem you can clone plot but that isn't so clean of a process
One easy yet dirty way is
JSON.parse(JSON.stringify(obj))
from this thread
I threw together a shotty example that captures what was going wrong for you
var array = [{one:1, two:2},{one:1, two:2},{one:1, two:2}],
copyArray = array,
newArr = doStuff(array)
function doStuff(a) {
var otherNewArr = []
a.forEach(function(ae) {
var aVar = ae
aVar.one = 5
otherNewArr.push(aVar)
})
return otherNewArr
}
console.log(copyArray,newArr)
And to fix it just replace
var aVar = ae
with
var aVar = JSON.parse(JSON.stringify(ae))

Categories

Resources