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);
};
Related
I'm working on an FCC intermediate algorithm "Arguments Optional". Here's the instructions on what needs to happen:
Intermediate Algorithm Scripting: Arguments Optional
Create a function that sums two arguments together. If only one argument is provided, then return a function that expects one argument and returns the sum.
For example, addTogether(2, 3) should return 5, and addTogether(2) should return a function.
Calling this returned function with a single argument will then return the sum:
var sumTwoAnd = addTogether(2);
sumTwoAnd(3) returns 5.
If either argument isn't a valid number, return undefined.
I wrote the code to do everything explained above, but one requirement is that the arguments must all be numbers, otherwise return undefined (#4 above). You'll see I wrote a ternary operator (line 5 of my code) numbersOnly variable that I thought would handle this, but it's just returning [Function] in the console.
function addTogether() {
// Convert args to an array
let args = [...arguments];
// Only accept numbers or return undefined and stop the program
const numbersOnly = value => typeof(value) === 'number'? value : undefined;
// test args for numbersOnly and return only the first two arguments regardless of the length of args
let numbers = args.filter(numbersOnly).slice(0, 2);
// // It has to add two numbers passed as parameters and return the sum.
if (numbers.length > 1) {
return numbers[0] + numbers[1];
}
// If it has only one argument then it has to return a function that uses that number and expects another one, to then add it.
else if (numbers.length === 1) {
let firstParam = numbers[0];
return function(secondParam) {
if (typeof secondParam !== 'number' || typeof firstParam !== 'number') {
return undefined;
}
return secondParam + firstParam;
}
}
}
I'm passing all of tests, with the exception of #4, which should return undefined. I don't quite understand why 5 is passing and returning undefined but 4 is failing. What am I missing here? Thanks!
1. addTogether(2, 3) should return 5.
2. addTogether(2)(3) should return 5.
3. addTogether("https://www.youtube.com/watch?v=dQw4w9WgXcQ") should return undefined.
4. addTogether(2, "3") should return undefined.
5. addTogether(2)([3]) should return undefined.
This because you have to check input args and output args from filter.
Try to add this snippet:
let numbers = args.filter(numbersOnly).slice(0, 2);
if (args.length > numbers.length) {
return undefined;
}
function addTogether() {
// Convert args to an array
let args = [...arguments];
// Only accept numbers or return undefined and stop the program
const numbersOnly = value => typeof(value) === 'number'? value : undefined;
// test args for numbersOnly and return only the first two arguments regardless of the length of args
let numbers = args.filter(numbersOnly).slice(0, 2);
if (args.length > numbers.length) {
return undefined;
}
// // It has to add two numbers passed as parameters and return the sum.
if (numbers.length > 1) {
return numbers[0] + numbers[1];
}
// If it has only one argument then it has to return a function that uses that number and expects another one, to then add it.
else if (numbers.length === 1) {
let firstParam = numbers[0];
return function(secondParam) {
if (typeof secondParam !== 'number' || typeof firstParam !== 'number') {
return undefined;
}
return secondParam + firstParam;
}
}
}
console.log('4. addTogether', addTogether(4, "4"));
Because when you filter the arguments, only '3' gets filtered out, so the length of the remaining array is 1.
const args = [2, '3'];
const numbers = args.filter((n) => typeof n === 'number');
console.log('numbers:', numbers);
console.log('numbers.length === 1:', numbers.length === 1);
I'm trying to make a function that accepts another function and outputs that function repeatedly by only using function expressions/applications.
So far I have a function twice which accepts another function as an argument and returns func(func(x)):
function twice(func) {
function x(x) {
return func(func(x));
}
return x;
}
I'm trying to make a repeater function such that const thrice = repeater(twice) returns func(func(func(x))), and const fourtimes = repeater(thrice) etc. but i'm confused as to how to do this. Any help would be appreciated greatly. Thank you
Using your current structure thats impossible as twice does not expose a reference to func, thus repeater cannot call it.
The only solution I could think of would be to leak func from the inside through a (hidden) property:
const r = Symbol();
const repeater = f => Object.assign(
v => f[r] ? f(f[r](v)): f(v),
{ [r]: f[r] || f }
);
const addThree = repeater(repeater(repeater(n => n + 1)));
console.log(addThree(10));
You should two base cases (if n == 0 => exit, if n == 1 => return f(x)), where n is an additional parameter that specifies how many times the function should repeat with the arguments args:
function repeater(func, x, n) {
if (n == 0) return;
if (n == 1) return func(x);
else {
return func(repeater(func, x, --n));
}
}
let sqr = n => n * n;
console.log(repeater(sqr, 2, 3));
Do you look for something like this?
function chain(f, g) {
return function (x) {
return f(g(x));
}
}
function ntimes(f, n) {
if (n == 0) {
return function (x) { return x }
} else {
return chain(f, ntimes(f, n-1));
}
}
This will make a new function which repeats the original function f n times.
I am implementing sorting of table in Modal Window. I wrote this code but it is incorrect.
<ExtendedModalBar
list={this.state.modalList}
onCancel={this.handleExtendedModalClose}
onSave={(...args) => this.handleSaveFromModal(...args)}
selectedItems={this.state.modalItems}
show={this.state.showExtendedModal}
type={this.state.modalType}
//onClick={this.onSort('', )}
sortColumn={this.onSort('isSecure', this.state.modalList); this.onSort('profile', this.state.modalList)}
/>
My function:
onSort = (column, dataToSort) => (event) => {
const direction = this.state.sort.column ? (this.state.sort.direction === 'asc' ? 'desc' : 'asc') : 'desc';
dataToSort.sort((a, b) => {
if ( typeof(a[column]) === 'string' && typeof(b[column]) === 'string' ) {
const nameA = a[column].toUpperCase(); // ignore upper and lowercase
const nameB = b[column].toUpperCase(); // ignore upper and lowercase
if (nameA < nameB ) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
}
if( typeof(a[column]) === 'number' && typeof(b[column]) === 'number'){
return a[column] - b[column];
}
if(typeof(a[column]) === 'boolean' && typeof(b[column]) === 'boolean'){
const firstBool = +(a[column]);
const secondBool = +(b[column]);
return firstBool - secondBool;
}
}
);
if (direction === 'desc') {
dataToSort.reverse();
}
this.setState({
sort: {
column,
direction,
}
});
};
My sorting function accepts two arguments, columnName and data. if I call the function in onClick only one time, it sorts only one column. how to call function multiple times and pass different arguments, i.e different column names ?
Maybe the problem is related with the following: the onClick attribute expects just one function. I would try with something like this:
onClick={(event) =>
this.onSort('isSecure', this.state.modalList)(event);
this.onSort('profile', this.state.modalList)(event);
}
or some more elegant yet equivalent code. Hope it helps - Carlos
So I am trying to write a general memoizing function in Javascript, using this as my reference material. I've implemented it as instructed:
function memoize(func) {
var memo = {};
var slice = Array.prototype.slice;
return function() {
var args = slice.call(arguments);
if (args in memo)
return memo[args]
else
return (memo[args] = func.apply(this, args));
}
}
function fibonacci(n) {
if (n === 0 || n === 1)
return n;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
function memoFib = memoize(fibonacci);
console.log("Fibonacci of 6 is " + memoFib(6));
but for the life of me I cannot remember the proper syntax to calling the memoized function. How do I do this? How do I generalize this so that it's the memoized fibonacci function which is always called instead of the original function fibonacci?
You're almost there; you just need to fix your syntax when creating the memoized function. Instead of function memoFib =, do var memoFib = (or if ES2015 is an option, const would be better than var). And presumably you'll want to have the recursion calling into the memoized version as well, so i updated those as well. In the following code it may look weird that i'm referencing memoFib on a line that comes earlier than the line with var memoFib but javascript allows that due to hoisting.
function memoize(func) {
var memo = {};
var slice = Array.prototype.slice;
return function() {
var args = slice.call(arguments);
if (args in memo)
return memo[args]
else
return (memo[args] = func.apply(this, args));
}
}
function fibonacci(n) {
if (n === 0 || n === 1)
return n;
else
return memoFib(n - 1) + memoFib(n - 2);
}
var memoFib = memoize(fibonacci);
console.log("Fibonacci of 6 is " + memoFib(6));
And if you want to make absolutely sure no one can ever invoke the nonmemoized version, then you can hide it inside of an IIFE:
const fibonacci = (function () {
function unmemoizedVersion(n) {
if (n === 0 || n === 1)
return n;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
return memoize(unmemoizedVersion);
})();
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.