First return value of function undefined? - javascript

So I have a function here that returns an element of an array for every function call. It keeps from returning the same element twice by checking against another array that used elements are pushed to.
The problem is that I keep getting "undefined" back when I run it the first time. If I make more than one console.log call, the calls after the first one return an element.
I'm thinking it has to do with my first "if" statement, but I'm not sure. Does an empty array return a length property of 0? Is that the issue in my "if" statement?
I appreciate all the help, thanks in advance.
var fortunesList = [
"A",
"B",
"C",
"D",
];
var usedFortunes = [];
var getFortune = fortunesList[Math.floor(Math.random()*fortunesList.length)];
function fortuneCookieGenerator(getFortune) {
if (usedFortunes.length == 0) {
usedFortunes.push(getFortune);
}
else if (usedFortunes.length > 0) {
for (i = 0; i < usedFortunes.length; ++i) {
if (usedFortunes[i] == getFortune) {
getFortune = fortunesList[Math.floor(Math.random()*fortunesList.length)];
i = 0;
}
}
usedFortunes.push(getFortune);
}
return getFortune;
}
console.log(fortuneCookieGenerator());
console.log(fortuneCookieGenerator());
console.log(fortuneCookieGenerator());
console.log(fortuneCookieGenerator());

getFortune is undefined because you have that as an argument to fortuneCookieGenerator but you pass in nothing. After the first time your function gets called usedFortunes.length is greater than 0 triggering the else branch and you assign a new value to getFortune and return that.
You might also benefit from these JS debugging guides: Creativebloq, MDN, Google and MSDN.

Your function has the next signature
function fortuneCookieGenerator(getFortune)
which means that you can pass an argument, getFortune to it. Now, when you want to call the above function, you use the next;
fortuneCookieGenerator()
Which means that you're calling the function without passing an argument. So, at the first call, the getFortune is not defined yet. Also, the variable usedFortunes is still empty. As result of this,
usedFortunes.push(getFortune);
from the first if block gets invoked. You're pushing an undefined variable to the array. Once that gets done, the program proceeds to
return getFortune;
Which returns undefined.
At the second call, you still don't pass an argument, but the variable usedFortunes now is not empty. So it will execute the else if block. There, you have
getFortune = fortunesList[Math.floor(Math.random()*fortunesList.length)];
which initializes the variable. As result of this,
return getFortune;
holds something, you don't receive undefined anymore. That's why you are getting undefined at first call, but not at second and further calls.

getFortune() will be undefined if the condition is not true, so I think you need to add else part also to intialize it.

Do this at first:
console.log(fortuneCookieGenerator(getFortune));
Or,
function fortuneCookieGenarator(getFortune){
.......

Related

forEach/for...in not returning values? [duplicate]

This question already has answers here:
Function with forEach returns undefined even with return statement
(5 answers)
Closed 3 years ago.
So I have a little bit of confusion, I'm solving a challenge on freeCodeCamp.
The challenge reads as follows
Everything Be True
Check if the predicate (second argument) is truthy on all elements of a collection (first argument).
It's solved but I don't understand why I had to take an extra step. My code is as such:
function truthCheck(collection, pre) {
collection.forEach(function(element) {
for (key in element) {
if (!element.hasOwnProperty(pre)) {
return false;
} else if (key === pre) {
if (!Boolean(element[key])) {
return false;
}
}
}
});
return true;
}
truthCheck([
{"user": "Tinky-Winky", "sex": "male"},
{"user": "Dipsy"},
{"user": "Laa-Laa", "sex": "female"},
{"user": "Po", "sex": "female"}
], "sex");
so in this instance it should fail because the 2nd element within collection does not have the sex property. Also you will receive a fail if the pre argument, or in this case sex is not a truthy value.
When these get hit (Which they are, I'm able to tell through console logs) but I figure it would break out of the loop and return from the truthCheck function.....but it doesn't, and it will eventually return true.
I was able to circumvent this by defining a variable and then setting that value to false and then returning the variable at the end. Is there a better way? It seems like these returns should break out of the truthCheck function? Am I missing something?
As the other answers explain, this is meaningless:
collection.forEach(function () {
// do something
return false;
});
because array#forEach simply does not care for the return value of its worker function. It just executes the worker function for each array element.
You could use the worker function to set an outer variable:
function truthCheck(collection, pre) {
var allAreTruthy = true;
collection.forEach(function (elem) {
// if this ever flips allAreTruthy to false, it will stay false
allAreTruthy = allAreTruthy && elem[pre];
});
return allAreTruthy;
}
But there are better ways to express this.
Check if the predicate (second argument) is truthy on all elements of a collection (first argument).
Could be paraphrased as "Every element of the collection has a truthy value at a particular key."
function truthCheck(collection, pre) {
return collection.every(function (elem) { return elem[pre]; });
}
Could be paraphrased as "None of the elements of the collection have a falsy value at a particular key (or are missing the key entirely)."
Or, since an Array#none method does not actually exist, "There aren't some elements of the collection that have a falsy value at a particular key."
function truthCheck(collection, pre) {
return !collection.some(function (elem) { return !elem[pre]; });
}
The advantage of using Array#some is that it stops iterating the array as soon as the condition it seeks for is fulfilled. If your array had many elements this would mean improved performance. For short arrays there's not a lot of difference to using Array#every or Array#forEach.
The above is semantically equivalent to
function truthCheck(collection, pre) {
var i;
for (i = 0; i < collection.length; i++) {
if (!collection[i][pre]) return false;
}
return true;
}
Since JS objects simply return undefined when you access a key that has not been set, a check for hasOwnProperty is superfluous here.
You can't return anything from a ForEach loop. It will return undefined by default.
As the official documentation, Array.prototype.forEach() - JavaScript | MDN, says:
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a Boolean return value, you can use every() or some() instead.
So you can use a very simple for..in loop, for example:
for(var c in collection){
// Do whatever you want
}
[collection].forEach of javascript does not work like an ordinary loop. There is no way to prematurely end it not unless you make it throw an exception.
The behavior that you are expecting is what you would expect out of a javascript for loop but since forEach uses callback functions for each looped object, then you are only exiting the callback function instead of the forEach. Also it is worth noting that in your code, the you have a for loop which has a return in it. The return block in this loop only breaks this loop and not the forEach (which I have mentioned earlier, cannot be prematurely terminated unless otherwise)
As you can see forEach is mostly meant to iterate all elements instead of conditional checks per iterated element.
function truthCheck(collection, pre) {
return collection.every(function (person) { return !!person[pre]; });
}
you execute a function on each element of the collection. This function checks that element an returns something. But that returned value does not affect the result of the outer function. Since the outer function does not depend on the inner function your result is allways true.
if you define a variable, set this to false and return that variable at the end would works but it would be inefficient. Lets think of the following scenario. You found one element which does not has the target key. So right now you should return but you can't. You have to working yourself through the whole collection. The forEach loop does not give you the chance to exit without a mess. Thus a better idea is the for loop. Your can exit exit the for loop if found what you were looking for
a slightly easier way would be:
function truthCheck(collection, pre) {
//iterate thrugh your collection
for (var c in collection){
//get keys of element as an array and check if pre is in that array
if( Object.keys(collection[c]).indexOf(pre) == -1){
// pre was not found
return false;
}
}
return true;
}

How does the Javascript closure with function works?

Hi i have been exploring closures and javascript core concepts i couldn't understand why does the console.log(factory[i]) outputs undefined i have pushed my function inside there right? And if i call temp outside the loop it says undefined whereas if i call inside the loop it returns am bit confused can anyone explain me?Here is my code
var fruits=["apple","orange"];
var factory=[];
for(var i=0;i<fruits.length;i++)
{
var temp=function()
{
console.log(fruits[i]);
}
factory.push(temp());
}
temp();
console.log(factory);
for(var i=0;i<factory.length;i++)
{
temp(i);
console.log(factory[i]);
}
https://jsfiddle.net/kh3okLca/
You are not passing function but the result of the executed function temp() as it don't return anything its undefined. change factory.push(temp()); to factory.push(temp);
The temp() outside return undefined because by that time loop has executed and the value of i is 2 check this following piece of code which logs value of i.
var fruits=["apple","orange"];
var factory=[];
for(var i=0;i<fruits.length;i++)
{
var temp=function()
{
console.log(fruits[i],"console",i);
}
factory.push(temp);
}
temp();
console.log(factory,"factory");
for(var i=0;i<factory.length;i++)
{
temp(i); //i resets to 0 here in same scope
console.log(factory[i](i),"factoryi"); //this doesnt return anything so its undefined but statements are executed
}
Here is the output you have.
//next two executed due to factory.push(temp()) in first if loop
& there is a console.log there inside the function
apple
orange
//here i++ in first loop will be 3, but array have only two element, so it is undefined
undefined
// due to console.log(factory)
// temp function is actually returning undefined,
[undefined, undefined]
// due to temp(i) in second if block
apple
// but factory array is stil empty so factory[i] will be undefined
undefined
from temp orange
undefined
Closure are nothing but function with preserve data. Till now a function is treated as peace of code which takes input and produces some output ,for every function call this code remain same, but closure gives you opportunity to save some data with the function which can be changed so that for each function call it will react differently, keep that in mind everything will be easy .
Suppose you have a function that finds rate of interest , but this functions is used by three teams whose interest rates are different, So in general what we do we pass the team name with the principle amount , each and everytime we have to pass the team name , So by using closure we can three instance of a function for each team (team name as a preserve data ) and now only send the principle amount and get the interest calculated according to the team, I a moment i will add example also,

Sorting behavior on passing function vs. passing anonymous closure

Problem and Question
I have a small application that asynchronously gets JSON data from a server, formats it into a table, and allows the user to perform some simple operations on the table (sorting, filtering, etc.).
One of the sorting functions accesses DOM elements in the previously-generated table (definition given below).
var SORT = function(){
var my = {};
// public methods
my.byName = function(sign){
(!sign) ? sign=1 : 1;
var T = $("#resultArea").find("tbody");
var R = T.children("tr");
R.sort( function(a,b){
var an = $(a).attr("data-name");
var bn = $(b).attr("data-name");
return sign * an.localeCompare(bn);
});
R.detach().appendTo(T);
}
...
return my; }();
When specifying it as a callback for an element the user can click on, I have two formulations.
$("#sort-button").click(SORT.byName); (pass function as argument)
OR
$("sort-button").click(function(){SORT.byName();}); (pass anonymous closure that calls the function)
The first option fails, but the second works. Here is how it fails on a test case with 536 rows to be sorted:
Former row 2 (which precedes row 1 in alphabetical order) is moved to position 268.
Former row 269 is moved to position 536.
Former row 536 is moved to position 2.
I have tried and failed to construct a MWE that fails in the same way (will update question once I succeed). Questions are: What went wrong? Why does using the anonymous closure work?
Update
An earlier version of the snippet had been sanitized to remove the parameter sign and the line at the start (which would set sign to 1 if it evaluated to false or was undefined), the idea being that by passing sign=-1 as a parameter, a descending sort could be done. When I removed sign from the definition in the live code, the problem went away.
So I found that the offending line is (!sign) ? sign=1 : 1; When replaced by the more transparent if(sign !== undefined){sign=1;} the problem goes away. I think what it does is that it sets global sign to one on the first pass, then on the second pass, sign is defined so it returns 1, and the function ends (only one pass having been completed).
Then why does this error not crash the sort on the anonymous closure approach?
As you found out, the problem comes from that sign parameter. When you pass a function as the event handler and call SORT.byName() without arguments, you'll get sign=1 and everything is as expected. But when you pass the function directly as the handler, it will get called with the Event object as its argument. Suddenly you have an object in your sign variable, and multiplying that with a number will yield NaN (an invalid result for a comparison function), which completely messes up your sort.
When replaced by the more transparent if(sign !== undefined){sign=1;} the problem goes away. I think what it does is that it sets global sign to one on the first pass…
Nope. There is no global sign variable at all. And I guess you actually wanted if (sign === undefined) sign = 1;. Which wouldn't work as well when passing in events, so you might want to use if (!Number.isFinite(sign)) sign = 1;.
Without seeing more of your code I can't really tell what's going on. The snippet you have posted seems alright. Regarding your question, there is a subtle difference when you pass SORT.byName vs. sending it wrapped in an anonymous function. Specifically, it is the value of this in the byName function when it is executed.
When you do click(SORT.byName), you are sending a direct reference to the function, which means that when it gets called, the value of this is whatever the jQuery handler for click sets it to be when before it calls your callback function; usually this is a reference to the element that fired the event.
However, when you do click(function() { SORT.byName(); }), the value of this in byName is the SORT object (but this in the anonymous function is still whatever jQuery sets it to). This is because here you're invoking the function explicitly as a method of the SORT object.
So if your sort functions rely on the value of this and assume it to be the SORT object, you can run into issues.
Here's some code that demonstrates this behavior:
var obj = {
field: 10,
method: function() {
console.log(this);
}
};
// The first argument to apply sets the value of "this"
function call(f) {
f.apply("not this", []);
}
call(obj.method); //logs "not this"
call(function() { // logs obj
obj.method();
});
Searching through the DOM and sorting is not fun. You would be better off keeping some state, sorting, and then appending the new results to the DOM after you remove the old like so.
var myNumbers = [
[1,'one'],
[4,'four'],
[2,'two'],
[6,'six'],
[3,'three'],
[8,'eight'],
[7,'seven'],
[5,'five'],
[10,'ten'],
[9,'nine']
];
myNumbers.sort(function(a,b){
if (a[0] > b[0]) {
return 1;
}
if (a[0] > b[0]) {
return -1;
}
return 0;
});
var T = $("tbody");
var R = T.children("tr");
R.detach()
After that you can prepend your results in a loop like you addElemnt function but a loop instead.

Why does this always evaluates to true no matter what argument you apply to it?

I am reading 'JavaScript Allongé' and came across this in a section about functions.
function (value) {
return (function (copy) {
return copy === value
})(value)
}(value);
Say I pass 5... a string, a function, an array or ANYTHING as an argument for that matter! Why would it evaluate to true? Nothing seems to be passed to the argument copy which is nothing? The only thing I can think of is, when you pass 5 to value, its also being dropped in the argument in the return function?
Thanks!
(function (value) { // function accepts a `value` as an argument
return (function (copy) { // function accepts a `copy` argument
return copy === value // `copy` and `value` are both 5
})(value) // `value` becomes `copy` on line 2
}(5)); // pass in 5, becomes `value` on line 1
In other words:
5 gets passed to first outer function, which accepts a value argument (value is now 5)
inner function is called with value, which accepts a copy argument (copy is now equal to value, which is equal to 5)
inner function compares copy to value, both of which have been set to 5.
All this is, is a fancy way to set two local variables to the same value, and then compare them. So as long as a value is equal to itself, this will return true.
You are passing the same object back into the comparison. Therefore it evaluates to true. However, there is some stuff happening here that makes this more interesting than following a reference
{...})(value)
The (value) makes it a self executing function, so it is evaluated inline. It's a nice feature of Javascript that it pays to understand. You can use them this way but they are really nice for creating Javascript Modules that scope and extend code.
There is something being passed in to the argument copy The 4th line of your sample is sending value in to be used as the argument for copy
So if copy is a copy of value, then copy === value will always return true.
The syntax in your sample is defining and then immediately calling a function. This version is logically the same, maybe the behavior makes more sense when seen this way:
var funcA = function(value) {
var funcB = function(copy) {
return copy === value;
}
return funcB(value);
}
result = funcA(5);
You're passing 5 (value) in the first call.
function (value) {
/*remove all stuff so you can focus in the firs step.*/
}(5);
Then you're returning a "call to a function" that receives "value" (which current value is 5) as parameter received in "copy" (so copy's value now is 5).
//function (value) { commented lines doesn't care yet so you can focus
return (function (copy) {
//return copy === value
})(value)
//}(value);
This inner function returns the comparison of "value" (which is accessible because the inner function have access to outer scope (first function and it's parameters)) and "copy" (wich previously received "value=5")
value=5=copy then returns true.
//function (value) { lines doesn't care yet so you can focus
//return (function (copy) {
return copy === value
//})(value)
//}(value);
Say it plain you're comparing the same value.

JavaScript - referencing arguments from within a function

Recently i found myself attaching function arguments to a variable inside the function scope so that i was not referencing the argument every time it was used.
Is there any benefit to this practice?
For example:
function populateResultCount(count){
var count = count;
return $('.resultCounter').text(count);
};
Could easily be re-written like so:
function populateResultCount(count){
return $('.resultCounter').text(count);
};
And would still function correctly.
There's no functional difference between the two. Go with the simpler version.
If you're not using the argument that's passed in, there is no difference. In your first example, you can potentially confuse future maintainers because of var count = count, i.e., you're declaring a variable that has the same name as the argument, and that isn't a best practise.
So, if you can, use your second form. Its intent is clearer and there is no room for confusion.
I can see no benefit to this unless you are manipulating the data somehow. Your variable without the additional assingment can still not be accessed outside of the function.
function Test (count) {
this.increment = function() {
count++;
}
this.getCount = function() {
return count;
}
}
var test = new Test(10);
<button onclick="test.increment(); alert(test.getCount());">Increment</button>
You can do something like that even with the argument. So I think they are same.
All the other answers are correct: There's no reason to "re-assign" a passed argument inside the function.
The only thing I can think of, where you'd mess with reassigning arguments, is if you have optional arguments/default values
function xyz(optionalArgument) {
optionalArgument = optionalArgument || "no argument given";
...
}
But in that case, it'd be better to write it as
function xyz( /* optionalArgument */ ) {
var optionalArgument = arguments[0] || "no argument given";
...
}
Note that the || trick will give you the right-hand side's value, if the left-hand side is a falsy value. I.e. if you're ok with the optional argument being something that's falsy (like explicitly passing null, 0, etc), you'd have to do something like var arg = typeof arguments[x] === 'undefined' ? defaultValue : arguments[x];

Categories

Resources