The function below adds arguments within 1 paranthesis fine. For example, it computes addTogether(2,3) = 5 and addTogether(2,"3") = undefined.
However, it fails to compute addTogether(2)(3) = 5, instead giving me the error that "addTogether(...) is not a function". The closure function (return function(x)) is supposed to take into the second argument in addTogether(2)(3), and I'm lost on why it dos not work.
function addTogether() {
if (typeof arguments[0] !== "number" || typeof arguments[1] !== "number") {
return undefined;
} //not harmful but not necessary
var sum = 0;
var num = arguments[0];
if (arguments.length === 1) {
//if only 1 argument in the original function...
if (typeof arguments[0] !== "number") {
return undefined;
//returns undefined if arguments[0] isnt a number
}
return function(x) {
if (typeof arguments[0] !== "number") {
return undefined;
//in the closure/2nd function, if first argument isnt a number then no sum will be provided
} else {
sum = num + x; //x = second given argument
return sum;
}
};
}
if (typeof arguments[0] === "number" && typeof arguments[1] === "number") {
for (var x = 0; x < arguments.length; x++) {
if (typeof arguments[x] === "number") {
sum += arguments[x];
//add the argument[0] and [1] if both are number types, not string or array types or any other types
} else {
sum = undefined;
}
}
return sum;
}
// the above "if" statement is rsponsible for achieving addTogether(2,3) = 5;
}
console.log(addTogether(2)(3));
If you want your function to work like addTogether(2)(3), this means that your
addTogether must take an parameter and return a function. addTogether(2) this call will return a new function, and then call the returned function with the second parameter.
In your case when you compare
if (typeof arguments[0] !== "number" || typeof arguments[1] !== "number")
and call the function with one argument, the second typeof arguments[1] !== "number" returns you true, because the second parameter is undefined, so it is not a number and your function returns undefined.
And in your code you can remove some conditions also. Because the above condition will already check them.
function addTogether() {
if (typeof arguments[0] !== "number") {
return undefined;
}
var sum = 0;
var num = arguments[0];
if (arguments.length === 1) {
return function(x) {
if (typeof arguments[0] !== "number") {
return undefined;
} else {
sum = num + x;
return sum;
}
};
}
if (typeof arguments[0] === "number" && typeof arguments[1] === "number") {
for (var x = 0; x < arguments.length; x++) {
if (typeof arguments[x] === "number") {
sum += arguments[x];
} else {
sum = undefined;
}
}
return sum;
}
}
console.log(addTogether(2)(3));
if (typeof arguments[0] !== "number" || typeof arguments[1] !== "number") already causes addTogether(2) to return undefined.
Placing that if statement at the end of the function or turning that || into an && fixes it.
Related
I really thought I had this code correct. I am trying to calculate basketball score with free throws, 2 pointers and 3 pointers. The output when I console.log the totalBasketballScore ends up being 'All entries must be numbers' and undefined. What do I need to change so I get the score when I put the 3 values in the parameters?
function totalBasketballScore(numberFreeThrows, numberMidRange, numberThreePointers) {
const freeThrows = 1;
const midRange = 2;
const threePointers = 3;
if (typeof numberFreeThrows === 'number' && numberMidRange === 'number' && numberThreePointers === 'number') {
let totalFreeThrows = freeThrows * numberFreeThrows;
let totalMidRange = midRange * numberMidRange;
let totalThreePointers = threePointers * numberThreePointers;
let gameTotal = totalFreeThrows + totalMidRange + totalThreePointers;
return gameTotal;
} else {
console.log('All Entries Must Be a Number');
}
}
console.log(totalBasketballScore(1, 2, 4));
Another approach that can be used is isNaN(). isNaN can be used to check if the value is Not a Number. If isNaN() returns false, the value is a number.
function totalBasketballScore(numberFreeThrows, numberMidRange, numberThreePointers) {
const freeThrows = 1;
const midRange = 2;
const threePointers = 3;
if(isNaN(numberFreeThrows)=== false && isNaN(numberMidRange)=== false && isNaN(numberThreePointers)=== false) {
let totalFreeThrows = freeThrows * numberFreeThrows;
let totalMidRange = midRange * numberMidRange;
let totalThreePointers = threePointers * numberThreePointers;
let gameTotal = totalFreeThrows + totalMidRange + totalThreePointers;
return gameTotal;
} else {
console.log('All Entries Must Be a Number');
}
}
console.log(totalBasketballScore(1, 2, 4));
You should use typeof per each parameter, like this:
if(typeof numberFreeThrows === 'number' && typeof numberMidRange === 'number' && typeof numberThreePointers === 'number'){
} else {
}
I need to validate the arguments of a callback function. I have a function that takes count and a func, count checks if the number of passed arguments to a func were correct. I have tried to make other function inside my function that would connect arguments
function checkFunc() {
func.apply(null, arguments);
return [...arguments];
}
But I receive func.apply is not a function. SO I made it in another way but it still doesn't work.
Here is the code with example
const withParamsCountValidation = (count, func) => {
function checkFunc(args1, ...args) {
return func(args1, ...args);
}
if (typeof count === 'number' && checkFunc().length !== count.length) {
new Error`You should pass no more than ${count} parameters`();
}
if (
Array.isArray(count) &&
count.length === 2 &&
checkFunc().length >= count[0] &&
checkFunc().length <= count[1]
) {
true;
}
new Error`You should pass at least ${count[0]} and no more than ${count[1]} parameters`();
};
console.log(withParamsCountValidation(3, test(1, 2)));
function test(som, som2, som3) {
return som + som2 + som3;
}
I figured out how to do it via closures if someone needs:
const withParamsCountValidation = (count, func) => {
func = function () {
return function (...args) {
console.log("args", args, "count", count);
if (typeof count === "number" && args.length !== count) {
throw new Error(`You should pass no more than ${count} parameters`);
}
if (
Array.isArray(count) &&
count.length === 2 &&
args.length >= count[0] &&
args.length <= count[1]
) {
return true;
}
throw new Error(
`You should pass at least ${count[0]} and no more than ${count[1]} parameters`
);
};
};
return func(count);
};
Is there a better way to check for multiple variables in an if statement JavaScript?
num2 = 23;
num1 = 3;
if(typeof num1 === 'number' && typeof num2 === 'number'){
}
You might make a function that checks if every one of its arguments is of the desired type:
const isType = (type, ...args) => args.every(arg => typeof arg === type);
if (isType('number', num1, num2)) {
}
I want to loop through an array and check if each element is a number OR a string that could potentially turned into a number (e.g. "42"). If it can be "converted" then the element should be stored in a new array.
This is my code where I push all converted elements into a new array. Notice: I also want to count how many elements were "converted" from a string into a number and how many were not.
function numberConverter(arr) {
var converted = []
var counterConverted = 0
var counterNotConverted = 0
for (var c of arr) {
if (typeof c == "string" && Number(c) == "number") {
counterConverted++;
parseInt(c, 10);
converted.push(c)
} else {
counterNotConverted++
}
}
if (counterConverted == 0) {
return "no need for conversion"
} else {
return counterConverted + " were converted to numbers: " + converted + "; " + counterNotConverted + " couldn't be converted"
}
}
I know that my if condition
if(typeof c == "string" && Number(c) == "number")
is flawed logically, but I can't make up why.
Thanks for any hints and please explain it in beginner terms.
You can test if a string could be converted to a number like so:
val !== "" && Number.isNaN(Number(val)) === false
And the code could be written like so:
function numberConverter(arr) {
var converted = [];
var notconverted = [];
arr.forEach(function(val) {
if (typeof val === "number") {
converted.push(val);
} else if (typeof val === "string" && val !== "" && Number.isNaN(Number(val)) === false) {
converted.push(Number(val));
} else {
notconverted.push(val);
}
});
console.log("converted", converted);
console.log("not converted", notconverted);
}
numberConverter([0, "1", "", "123-foo", undefined, null, true, [], {}]);
The best solution is to use a functional approach to the code rather than an imperative one.
let arrayNumbers = ["Vadim", 99, {}, [], "100", "55AA", "AA55", Infinity, "false", true, null, -65.535, 2E1, "2E2"].filter( value => value !== null && value != Infinity && value !== '' && !isNaN(Number(value)) && !['boolean','array','object'].includes(typeof value)).map(value => +value);
console.log('Was Converted to Numbers:', arrayNumbers);
You need to check typeof string and isNaN in ESLint way (Number.isNaN(Number())).
function numberConverter(arr) {
const converted = [];
let counterConverted = 0;
for (let i = 0; i < arr.length; i += 1) {
const str = arr[i];
if (str && typeof str === 'string' && !Number.isNaN(Number(str))) {
const number = parseInt(str, 10);
converted.push(number);
counterConverted += 1;
}
}
const counterNotConverted = arr.length - converted.length;
if (counterConverted === 0) {
return 'No need for conversion.';
}
return `${counterConverted} were converted to numbers: ${converted.join(',')}; ${counterNotConverted} couldn't be converted`;
}
console.log(`'${numberConverter(['id', null, {}])}'`); // No need for conversion.
console.log(`'${numberConverter(['1', '-1', 'val'])}'`); // 2 were converted to numbers: [1,-1]; 1 couldn't be converted
console.log(`'${numberConverter(['1', '-1', '0', '1.5', 'val'])}'`); // 4 were converted to numbers: [1,-1,0,1]; 1 couldn't be converted
Do you know any better and faster way to convert a string to the type it represents?
I've always been using this function:
var convertType = function (value){
if (value === "undefined") return undefined;
if (value === "null") return null;
if (value === "true") return true;
if (value === "false") return false;
var v = Number (value);
return isNaN (v) ? value : v;
};
Candidates:
//Me, Gabriel Llamas
var cast1 = function (value){
if (value === "undefined") return undefined;
if (value === "null") return null;
if (value === "true") return true;
if (value === "false") return false;
var v = Number (value);
return isNaN (v) ? value : v;
};
//KooiInc
var cast2 = function (value){
var v = Number (value);
return !isNaN(v) ? v :
value === "undefined" ? undefined
: value === "null" ? null
: value === "true" ? true
: value === "false" ? false
: value
};
//LightStyle
var cast3 = function (value){
try {
return (new Function("return " + value + ";"))();
} catch(e) {
return value;
}
};
//Emmissary's proposal
var cast4 = function (value){
if (value === "undefined") return undefined;
try{
return JSON.parse (value);
}catch (e){
return value;
}
};
Benchmark code (using speedy):
var fn = function (cast){
cast ("undefined");
cast ("null");
cast ("true");
cast ("false");
cast ("12");
cast ("12.34");
cast ("asd");
};
speedy.run ({
"cast 1": function (){
fn (cast1);
},
"cast 2": function (){
fn (cast2);
},
"cast 3": function (){
fn (cast3);
},
"cast 4": function (){
fn (cast4);
}
});
Result:
File: string-conversion.js
Node v0.10.18
V8 v3.14.5.9
Speedy v0.0.8
Benchmarks: 4
Timeout: 1000ms (1s 0ms)
Samples: 3
Total time per benchmark: ~3000ms (3s 0ms)
Total time: ~12000ms (12s 0ms)
Higher is better (ops/sec)
cast 1
6,270,458 ± 0.2%
cast 2
3,305,103 ± 0.0%
cast 3
54,952 ± 0.0%
cast 4
82,790 ± 0.4%
Elapsed time: 12109ms (12s 109ms)
This is a simple function which involves the use of a function to evaluate the strings. This way you can remove the part of cases' "switch". Be aware that this handles also assignments to global variables, so I recommend it only if you know anytime where is the source from(don't allow users to use this function!)
var convertType = function (value){
try {
return (new Function("return " + value + ";"))();
} catch(e) {
return value;
}
};
You can see the jsfiddle here.
How about:
var convertType = function (value){
var values = {undefined: undefined, null: null, true: true, false: false}
,isNumber = !isNaN(+(value));
return isNumber && +(value) || !(value in values) && value || values[value];
};
convertType('null'); //=> null
convertType('something'); //=> "something"
convertType('57.321'); //=> 57.321
convertType('undefined'); //=> undefined
This seems faster # jsPerf
var convertType = function (value){
var v = Number (value);
return !isNaN(v) ? v :
value === "undefined" ? undefined
: value === "null" ? null
: value === "true" ? true
: value === "false" ? false
: value
}
var string2literal = function (value){
var maps = {
"NaN": NaN,
"null": null,
"undefined": undefined,
"Infinity": Infinity,
"-Infinity": -Infinity
}
return ((value in maps) ? maps[value] : value);
};
There are many weird rules in dynamic data type converting, just map it.