I was trying to understand this simple code snippet
function fnWrapper (fn) {
return function printResults (...args) {
const results = args.map(fn)
console.log(results)
}
}
const squarePrinter = fnWrapper(x => x*x)
const cubePrinter = fnWrapper(x => x*x*x)
const nums = [1, 2]
squarePrinter(1, 2)
cubePrinter(1, 2)
While, almost everything make sense, I am unable to comprehend this part args.map(fn)
i.e map should give an element but how are we able to pass our fn function and getting the desired result directly
As per map documentation it takes callback function as parameter and returns A new array with each element being the result of the callback function.
For example
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
So in your case
squarePrinter(1, 2)
const results = args.map(fn)
is equivalent to
const results = [1, 2].map(function(x) {
return x*x;
})
map function takes a callback function, which gets executed with the array elements on each iteration.
You might think of the above code like
args.map((x) => x*x);
which is nothing but the fn function provided as argument to the fnWrapper
A typical implementation of map would be something like
Array.prototype.map = function (callback) {
const resultArray = [];
for (let index = 0; index < this.length; index++) {
resultArray.push(callback(this[index], index, this));
}
return resultArray;
}
args.map(fn) will take each argument and perform the operations on those arguments to create a new list.
More Like
squarePrinter(1, 2) => [1,2].map(x => x*x)
Map is a higher order function which can take callback function as argument, in simple form map() implementation would seem like this:
Array.prototype.myMap = function(callback) {
arr = [];
for (let i = 0; i < this.length; i++)
//Map function take 3 parameter: the item, items's index and the array it self
arr.push(callback(this[i], i, this));
return arr;
};
Related
I am currently studying Javascript and am doing the underbar project(re-writing the _underbar library).
I have solved all of them but one, as I am stuck on _.memoize
This is my current code
_.memoize = function(func) {
var cache = {};
var slice = Array.prototype.slice;
return function() {
var args = slice.call(arguments);
if (args in cache) {
return cache[args];
} else {
return (cache[args] = func.apply(this, args));
}
}
};
This is the test case I am failing to pass
// Here, we wrap a dummy function in a spy. A spy is a wrapper function (much like _.memoize
// or _.once) that keeps track of interesting information about the function it's spying on;
// e.g. whether or not the function has been called.
it('should run the memoized function twice when given an array and then given a list of arguments', function() {
// Be careful how you are checking if a set of arguments has been passed in already
var spy = sinon.spy(function() { return 'Dummy output'; });
var memoSpy = _.memoize(spy);
memoSpy([1, 2, 3]);
expect(spy).to.have.been.calledOnce;
memoSpy(1, 2, 3);
expect(spy).to.have.been.calledTwice;
});
Or in words ' It should run the memoized function twice when given an array and then given a list of arguments'
I tried to change the args by checking if the first was a array and if not making all the arguments an array, but to no luck. I also tried to re write the code to hold a result and use Fibonacci to store the cache but it would run the function twice.
How would I resolve this test case?
Thanks
Using cache[args] doesn't make much sense because args is an array, and using bracket notation will convert it to a string. You could make an array of arguments arrays to their return values, then compare the arrays:
const _ = {};
_.memoize = function(func) {
const allArgs = [];
return function(...args) {
// Try to find matching arguments in allArgs
const result = allArgs.find(
item => item.args.length === args.length && item.args.every(
(arg, i) => args[i] === arg
)
);
// If a matching argument array was found, return the result:
if (result) return result.returnValue;
const returnValue = func.apply(this, args);
allArgs.push({ args, returnValue });
return returnValue;
}
};
const memoizedSum = _.memoize((...args) => {
console.log('called with', args);
return args.reduce((a, b) => a + b, 0);
});
console.log(memoizedSum(1, 2, 3));
console.log(memoizedSum(1, 2, 3));
console.log(memoizedSum(4, 5, 6));
Another option with less computational complexity would be to create a Map for each argument. For example, a call with arguments of 1, 2, 3 could result in a data structure of:
Map([[
1, { nested: Map([[
2, { nested: Map([[
3, { result: 6 }
]])}
]])}
]])
Then you'd find whether a nested result exists for the given arguments by recursively iterating through the Maps with .get for each argument, instead of iterating through all arguments the function has been called with so far. The code would be complicated, but it'd be more efficient.
Your function looks good, just one little detail. In your last return you should cache it first and then return it:
cache[args] = func.apply(this, args);
return cache[args];
I have a usercase where I get an array of functions from backend something like:
var arr = [A(){}, B(){}, C(){}];
Now I need a way to execute them such that each function in the array is passed as a parameter to another function in the array.
A(B(C()));
I'm curious how you managed to get the functions from the back-end, but it doesn't matter for your question, so here goes your answer:
var arr = [A(){}, B(){}, C(){}];
var value = arr[arr.length - 1]();
for (var i = arr.length - 2; i >= 0; i--) {
value = arr[i](value);
}
console.log(value);
You can use Array.prototype.reduce to execute consecutive calls to a list of functions.
Update: As ASDFGerte suggests, you can use reduceRight instead of reduce to reverse the function execution flow.
const text = 'That will be 3.50';
const funcList = [extractNumber, parseNumeric, formatCurrency];
console.log('Parsed:', chainFunctions(funcList, text));
console.log('Parsed:', chainFunctionsReverse(funcList.reverse(), text));
function chainFunctions(funcList, startingValue) {
return funcList.reduce((result, func) => func(result), startingValue);
}
function chainFunctionsReverse(funcList, startingValue) {
return funcList.reduceRight((result, func) => func(result), startingValue);
}
function extractNumber(str) {
return str.match(/\b(\d+(\.\d+)?\b)/)[1];
}
function parseNumeric(numStr) {
return parseFloat(numStr);
}
function formatCurrency(num) {
return `$${num.toFixed(2)}`;
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
Really sorry if the title does not make sense. Not sure how to make my question short
What I am wondering is,
I have a recursive function, well doesn't have to be recursive function just when I am doing this function, I wondered if it can be reused in a more flexiable way.
my function looks like this runAxios(ele, api) is the function I wonder if can be reused
const ct = (arr, num, res) => {
const promises = [];
for(let i = 0; i < num; i++){
const ele = arr.shift(); // take out 1st array, literally take out
if(ele){
promises.push(
runAxios(ele, api) // this is the function I am wondering if can be reused
)
}
}
Promise.all.......
};
if runAxios(ele, api) can be anything then I believe this ct can be a lot more flexiable?
I am wondering if it could it something like
const ct = (arr, num, res, fx) => {
const promises = [];
for loop......
if(ele){
promises.push(
fx // this is then passed as any other function other than just a fixed `axios function` that I wrote
)
}
}
Promise.all........
};
when I first tried it, I realized this will not work because runAxios's first parameter is done inside the loop which means the variable does not exist yet until it's inside the function itself.
Just being curious if there is such way to easily do it that I just don't know how or it's actually not possible?
Thanks in advance for any advices.
You were very close with your approach. It should look something like this:
const someFunction = (x) => new Promise((resolve) => resolve(x));
const ct = (arr, fn) => {
const promises = arr.filter(x => x).map(x => fn(x));
Promise.all(promises).then(x => console.log(x));
};
ct([1, 2, 3], someFunction);
(I also took the liberty to replace your loop with a more compact approach.)
Of course it can be done. You just have to call the function passed with the required paramemeters. You will calculate the ele parameter and then pass it to the function. A generic example to see the way it works is shown below:
const functionToBeCalled = (parameter1, parameter2) => {
console.log(parameter1 + parameter2);
}
const ct = (fx) => {
//..code
let ele = 1;
fx(ele, 2);
//..code
};
ct(functionToBeCalled);
I have a few functions in two different files that are all linked together by function calls they are as follows
FILE 1:
function getFunction(func){
}
FILE 2:
function Numbers(one, two) {
return (one*two);
}
var func = getFunction(Numbers);
and these are called by:
func(input_array);
my array has values 1,3,5,7,9 and I need func(input_array) to return 3,15,35,63,9 (the last value loops back to the first value)
basically what I am trying to do is have getFunction return a function such that these values are calculated. I am having trouble because I can't wrap my mind about sending and returning functions. I don't know how to access the array if it isn't sent into the function. Let me know if I need to clarify anything.
function getFunction(callback) {
return function(array) {
return array.map(function(cur, index) {
return callback(cur, array[(index+1) % array.length]);
});
};
}
getFunction returns a closure over the callback parameter, which is the function that you want to call. The closure receives the array parameter, and it calls the callback in a loop over the array using array.map. The % modulus operator performs the wraparound that you want.
Another way to write this that may be clearer is:
function getFunction(callback) {
return function(array) {
var result = [];
for (var i = 0; i < array.length; i++) {
j = (i+1) % array.length; // Next index, wrapping around
result.push(callback(array[i], array[j]));
}
return result;
};
}
var func = getFunction(Numbers);
console.log(func([1,3,5,7,9])); // Logs [3,15,35,63,9]
here is simple function that returns what you need
function Numbers(x) {
output_array=[];
for(i=0;i<x.length;i++){
if(x[i+1]==undefined){
output_array.push(x[i]);
}
else{
output_array.push(x[i]*x[i+1]);
}
}
return output_array;
}
var input_array=[1,3,5,7];
var num = Numbers(input_array);
console.log(num);
OR if you need it in the way function calling another function
and than returning the result use this
function getFunction(Numbers,input_array){
return Numbers(input_array);
}
function Numbers(x) {
output_array=[];
for(i=0;i<x.length;i++){
if(x[i+1]==undefined){
output_array.push(x[i]);
}
else{
output_array.push(x[i]*x[i+1]);
}
}
return output_array;
}
var input_array=[1,3,5,7];
var num = getFunction(Numbers,input_array);
console.log(num);
I have a very basic question about JavaScript.
Consider the following code:
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item,index,array) {
alert(arguments.length);
return (item > 1);
});
Now in the above code I am passing anonymous function as an argument of "every" function.
How exactly my anonymous function is getting the exactly 3 arguments(item,index,array).
This isn't really a basic javascript question, but a library question, and how it "happens" depends on the implementation.
This here is a sample implementation of every in javascript:
function every(array, fn) {
for(var i = 0; i < array.length; i++) {
fn(array[i], i, array);
}
}
You would call it like this:
every([1,2,3,4], function(item, index, array) {
// do stuff
});
As you can see, it's the every function itself, that calls the fn (which is the function you pass in), and decides what arguments to pass.
The anonymous function you're passing is simply provided as argument for every() method which calls it for a number of times. every() iterates through your list items and calls your anonymous function each time with three arguments: value, index and your entire array.
Here's an approximate source code of how the actual every() function works:
Array.prototype.every = function(callback) {
for(i=0; i<this.length; i++) {
callback(this[i], i, this);
}
}
Let's build a simple function with a callback argument:
function foo(callback)
{
var callbackArgument = 'bar';
callback(callbackArgument);
}
Let's use it:
foo(function(arg){
console.log(arg);
}); // logs "bar" to the console!
How exactly my anonymous function is getting the exactly 3
arguments(item,index,array)?
Maybe it would be easier to understand with an alternative example You have:
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item,index,array) {
alert(arguments.length);
return (item > 1);
});
You could also write the same in the following manner:
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(item,index,array) {
function anonymous(firstVar,secondVar,thirdVar){
//do your anonymous stuff here
alert(thirdVar.length);
return (firstVar > 1);
}
//get the anonymous function processed data
var anonymousFunctionResults = anonymous(item,index,array);
//do your original stuff that you would have done with the results of anonymous function
anonymousFunctionResults...
}
});
Or in this way:
function anonymous(firstVar,secondVar,thirdVar){
//do your anonymous stuff here
alert(thirdVar.length);
return (firstVar > 1);
}
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(item,index,array, anonymous) {
//get the anonymous function processed data
var anonymousFunctionResults = anonymous(item,index,array);
//do your original stuff that you would have done with the results of anonymous function
anonymousFunctionResults...
}
});
Or in this way:
function anonymous(firstVar,secondVar,thirdVar){
//do your anonymous stuff here
alert(thirdVar.length);
return (firstVar > 1);
}
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(anonymous(item,index,array)) {
//get the anonymous function processed data
//you can use the "firstParameter" variable already of course
//this is just to make a point
var anonymousFunctionResults = firstParameter;
//do your original stuff that you would have done with the results of anonymous function
anonymousFunctionResults...
}
});
If I understood your question well :)