console.log(-1) still returns NaN - javascript

I have my js code for homework here. I have an if statement that should return -1 in console when the input is not a number but instead of returning -1 it returns NaN. Can anybody help me with this?
function calculateFoodOrder(numAnimals, avgFood) {
// IMPLEMENT THIS FUNCTION!
var total = avgFood*numAnimals;
if ((Number(numAnimals || avgFood) < 0) && (isNaN(numAnimals || avgFood))) {
console.log(-1);
} else {
return total
}
}
calculateFoodOrder()

Default values in your function are 'undefined'. That's why javascript is showing NaN. Define default values to avoid this. For example:
function calculateFoodOrder(numAnimals = 0, avgFood = 0) {
var total = avgFood*numAnimals;
if ((Number(numAnimals || avgFood) < 0) && (isNaN(numAnimals || avgFood))) {
console.log(-1);
} else {
return total;
}
}

If I understand your task correctly, you merely have to check both parameters for not being NaN using isNaN.
Your sample code does not work because any comparison with NaN returns false and thus Number(numAnimals || avgFood) < 0 is never going to be true. Check here for details on NaN.
function calculateFoodOrder(numAnimals, avgFood){
//REM: Default result
let tResult = -1;
//REM: Check if both paramters are not NaN
//REM: Be aware that whitespaces and empty strings validate to zero
if(
!isNaN(numAnimals) &&
!isNaN(avgFood)
){
tResult = Number(avgFood) * Number(numAnimals)
};
return tResult
};
//REM: Default test case
console.log(calculateFoodOrder());
;document.querySelector('button').onclick = function(){
console.log(
calculateFoodOrder(
document.getElementById('innumAnimals').value,
document.getElementById('inavgFood').value
)
)
};
<input type = 'text' value = '' id = 'innumAnimals' placeholder = 'numAnimals' />
<input type = 'text' value = '' id = 'inavgFood' placeholder = 'avgFood' />
<button>do</button>

Please do not confuse yourself with caveats if you are a beginner. You should assign to itself after converting to number, then judge if it's a NaN value or less then zero just like this,
function calculateFoodOrder(numAnimals, avgFood) {
// IMPLEMENT THIS FUNCTION!
numAnimals = Number(numAnimals);
avgFood = Number(avgFood);
var total = avgFood * numAnimals;
if (isNaN(numAnimals) || isNaN(avgFood) || numAnimals < 0 || avgFood < 0 ) {
console.log(-1);
} else {
return total
}
}
calculateFoodOrder()

Related

How to replace undefined value with a string

I tried to use this code:
if((data.memberData.workStreak || 0) >= 5){
won+=400;
embed.addField(message.language.get("WORK_CLAIMED_HEADINGS")[0], message.language.get("WORK_CLAIMED_SALARY", won))
.addField(message.language.get("WORK_CLAIMED_HEADINGS")[1], message.language.get("WORK_AWARD"));
data.memberData.workStreak = 0;
} else {
for(let i = 0; i < award.length; i++){
if (typeof i === 'undefined') {
return '<:b_:682865394637078531>';
}
if(data.memberData.workStreak > i){
let letter = Discord.Util.parseEmoji(award[i]).name.split("_")[1];
award[i] = ":regional_indicator_"+letter+":";
}
}
But it did absolutely nothing.
Any help?
You can simply use the OR operator and print string instead of undefined. In below statement if a is undefined then it will store empty string in a instead of undefined.
a = a || ''
Replace your line with below line:
let letter =Discord.Util.parseEmoji(award[i]).name;
OR
let letter =Discord.Util.parseEmoji(award[i]);
Please find working snippit below:
const a = undefined;
console.log(a);
console.log(a || '');
I don't know exactly, what this little code snippet is aimed to do.. But may this could help you?
let letter = Discord.Util.parseEmoji(award[i]).name.split("_")[1];
if (letter == undefined) {
return '<:b_:682865394637078531>';
}
if(data.memberData.workStreak > i){
award[i] = ":regional_indicator_"+letter+":";
}

Exclude 0 from !value

I am trying to create a variant of the following code, but would like when stdin == 0 to continue with the prompts and break only on every other !value case.
So far I have managed to make it work when stdin is a string (no unary +) and with Number(value) converting at the end.
The problem with my checks is that both zero and !value convert to false, which is the standard case afaik. I have tried with AND, OR operators but with no luck.
let sum = 0;
while(true) {
let value = +prompt('Choose value:','');
if ( !value ) break;
sum += value;
}
value is a number, and the only falsy numbers are 0 and NaN. You can check for NaN directly:
if (isNaN(value)) break;
Keep in mind that +'' is 0 and not NaN, however. It might be more appropriate to save the cast for later. There’s even the option of applying stricter validation, ruling out inputs like Infinity or 1.2e3:
let sum = 0;
while (true) {
const input = prompt('Choose value:');
const value = Number(input);
if (isNaN(value) || input === null || input.trim() === '') {
break;
}
sum += value;
}
You can check directly if the value equals to zero:
let sum = 0;
while(true) {
let value = +prompt('Choose value:','');
if ( value !== 0 && !value ) break;
sum += value;
}
console.log(sum);
You could use a default value of NaN for getting an empty string '' before converting to number.
Then check if the value is not a number and break the loop.
let sum = 0;
while(true) {
let value = +(prompt('Choose value:').trim() || NaN);
if (isNaN(value)) break;
sum += value;
}
console.log(sum);

Get function parameter length including default params

If you make use of the Function.length property, you get the total amount of arguments that function expects.
However, according to the documentation (as well as actually trying it out), it does not include Default parameters in the count.
This number excludes the rest parameter and only includes parameters before the first one with a default value
- Function.length
Is it possible for me to somehow get a count (from outside the function) which includes Default parameters as well?
Maybe you can parse it yourself, something like:
function getNumArguments(func) {
var s = func.toString();
var index1 = s.indexOf('(');
var index2 = s.indexOf(')');
return s.substr(index1 + 1, index2 - index1 - 1).split(',').length;
}
console.log(getNumArguments(function(param1, param3 = 'test', ...param2) {})); //3
Copying my answer over to here from a duplicate question:
Well, it's a bit of a mess but I believe this should cover most edge cases.
It works by converting the function to a string and counting the commas, but ignoring commas that are in strings, in function calls, or in objects/arrays. I can't think of any scenarios where this won't return the proper amount, but I'm sure there is one, so this is in no way foolproof, but should work in most cases.
UPDATE: It's been pointed out to me that this won't work for cases such as getNumArgs(a => {}) or getNumArgs(function(a){}.bind(null)), so be aware of that if you try to use this.
function getNumArgs(func) {
var funcStr = func.toString();
var commaCount = 0;
var bracketCount = 0;
var lastParen = 0;
var inStrSingle = false;
var inStrDouble = false;
for (var i = 0; i < funcStr.length; i++) {
if (['(', '[', '{'].includes(funcStr[i]) && !inStrSingle && !inStrDouble) {
bracketCount++;
lastParen = i;
} else if ([')', ']', '}'].includes(funcStr[i]) && !inStrSingle && !inStrDouble) {
bracketCount--;
if (bracketCount < 1) {
break;
}
} else if (funcStr[i] === "'" && !inStrDouble && funcStr[i - 1] !== '\\') {
inStrSingle = !inStrSingle;
} else if (funcStr[i] === '"' && !inStrSingle && funcStr[i - 1] !== '\\') {
inStrDouble = !inStrDouble;
} else if (funcStr[i] === ',' && bracketCount === 1 && !inStrSingle && !inStrDouble) {
commaCount++;
}
}
// Handle no arguments (last opening parenthesis to the last closing one is empty)
if (commaCount === 0 && funcStr.substring(lastParen + 1, i).trim().length === 0) {
return 0;
}
return commaCount + 1;
}
Here are a few tests I tried it on: https://jsfiddle.net/ekzuvL0c/
Here is a function to retrieve the 'length' of a function (expression or object) or an arrow function expression (afe). It uses a regular expression to extract the arguments part from the stringified function/afe (the part between () or before =>) and a regular expression to cleanup default values that are strings. After the cleanups, it counts the comma's, depending on the brackets within the arguments string.
Note This will always be an approximation. There are edge cases that won't be covered. See the tests in this Stackblitz snippet
const determineFnLength = fnLenFactory();
console.log(`fnTest.length: ${determineFnLength(fnTest)}`);
function fnTest(a,
b,
c = 'with escaped \' quote and, comma',
d = "and double \" quotes, too!" ) { console.log(`test123`); }
function fnLenFactory() {
const fnExtractArgsRE = /(^[a-z_](?=(=>|=>{)))|((^\([^)].+\)|\(\))(?=(=>|{)))/g;
const valueParamsCleanupRE = /(?<=[`"'])([^\`,].+?)(?=[`"'])/g;
const countArgumentsByBrackets = params => {
let [commaCount, bracketCount, bOpen, bClose] = [0, 0, [...`([{`], [...`)]}`]];
[...params].forEach( chr => {
bracketCount += bOpen.includes(chr) ? 1 : bClose.includes(chr) ? -1 : 0;
commaCount += chr === ',' && bracketCount === 1 ? 1 : 0; } );
return commaCount + 1; };
const extractArgumentsPartFromFunction = fn => {
let fnStr = fn.toString().replace(RegExp(`\\s|function|${fn.name}`, `g`), ``);
fnStr = (fnStr.match(fnExtractArgsRE) || [fn])[0]
.replace(valueParamsCleanupRE, ``);
return !fnStr.startsWith(`(`) ? `(${fnStr})` : fnStr; };
return (func, forTest = false) => {
const params = extractArgumentsPartFromFunction(func);
const nParams = params === `()` ? 0 : countArgumentsByBrackets(params);
return forTest ? [params, nParams] : nParams;
};
}

Cannot read property length null error when used with regular expressions

I'm a javascript beginner doing some CodeWars.com questions. I came across this question and I'm stuck due to a "cannot read property length null" error. I've tried to look up that error and can't find what the problem is in my program.
The assignment is:
"Check to see if a string has the same amount of 'x's and 'o's. The method must return a boolean and be case insensitive. The string can contains any char."
And this is what I've written so far:
function XO(str) {
var x = "x";
var o = "o";
var numX = str.match(/x/gi).length;
var numO = str.match(/o/gi).length;
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
if (numX === -1 && numO === -1){
return true;
}
}
XO("xoxo");
The assignment also says that if there is neither an X or an O then the program should return true.
This will not give you that error. When there are no matches, the match function returns null and you cannot get the length of null. A few extra lines solves this issue.
function XO(str) {
var x = "x";
var o = "o";
var numX = 0;
var numO = 0;
var xMatch = str.match(/x/gi);
var oMatch = str.match(/o/gi);
if (xMatch) {
numX = xMatch.length;
}
if (oMatch) {
numO = oMatch.length;
}
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
} else {
return false;
}
}
if (numX === -1 && numO === -1){
return true;
} else {
return false;
}
}
console.log(XO("ddd"));
I think you are making this problem more complex than it has to be.
All you need to do is make the string lowercase(to account for case insensitive), traverse the string, and when it finds an x, add 1 to a counter, and when you find and o, decrease 1 from the counter.
If it ends at 0, you return true, else you return false. There's no need for regexes
function XO(str){
var count = 0;
str = str.toLowerCase();
for(var i = 0; i < str.length; i++){
if(str[i] === 'x') count++;
if(str[i] === 'o') count--;
}
return count === 0 ? true : false;
}
Yes you have to check the return value of match is not null before checking the length property. However
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
looks like an infinite loop if either string contains lower case 'x' or 'o' and there are a different number of each.
More simply:
function XO(str)
{ var matchX = str.match(/x/gi);
var matchY = str.match(/o/gi);
return (matchX && matchY) ? matchX.length == matchY.length : !matchX && !matchY;
}

How to catch null, undefined, blank values with AngularJS filter

I'm attempting to write a filter for use in a grid that will catch all null, undefined, blank string, or other similar values and display a dash "-". I've written the following so far, but it doesn't catch null values, and I'm wondering if it could be more succinct and possibly refactored to avoid three layers of nested if/else statements. Percentage values need to be checked that they're over 0 and under 1. Also, negative numbers and 0's should be returned as is. Thanks!
angular.module('AdverseEventsExplorer.main').filter('emptyCellFilter', function ($filter) {
return function (input, cellFilter, args1, args2) {
if (cellFilter == undefined) {
return (angular.isNumber(input) || angular.isDefined(input) && input.length > 0) ? input : '-';
} else {
if (cellFilter.match(/pctg|percent|pctgFilter|incidence/ig)) {
return (input > 0 && input < 1.0000000) ? $filter(cellFilter)(input, args1, args2) : '-';
} else {
return (angular.isNumber(input) || angular.isDefined(input) && input.length > 0) ? input : '-';
}
}
};
});
Version 2.0 taking into account #tymeJV's comment:
angular.module('AdverseEventsExplorer.main').filter('emptyCellFilter', function ($filter) {
return function (input, cellFilter, args1, args2) {
if (!cellFilter) {
return (angular.isNumber(input) || (input)) ? input : '-';
} else {
if (cellFilter.match(/pctg|percent|pctgFilter|incidence/ig)) {
return (input > 0 && input < 1.0000000) ? $filter(cellFilter)(input, args1, args2) : '-';
} else {
return (angular.isNumber(input) || (input)) ? $filter(cellFilter)(input, args1, args2) : '-';
}
}
};
});
Whenever you encounter a function that's getting too complex to refactor try extracting some of the smaller statements to concisely named variables. It makes it much easier for our brains to keep track of the function's requirements, and it's also more readable to new devs reading your code.
var inputHasValue = angular.isNumber(input) || input;
if(!inputHasValue){
return '-';
}
if (!cellFilter) {
return input;
}
var isPercentageCell = cellFilter.match(/pctg|percent|pctgFilter|incidence/ig);
var valueIsInRange = input > 0 && input < 1;
if(!isPercentageCell || valueIsInRange){
return $filter(cellFilter)(input, args1, args2);
}
return '-';
typeof x ==='number' || !!x
is false when x is null, undefined or empty string
Only one case in which it doesn't work – if you need to filter boolean variables, but your case doesn't seem to need it.
Anyway in that case you can use
typeof x === 'boolean' || typeof x ==='number' || !!x

Categories

Resources