Okay, so my question will be weirdly specific as I'm not just randomly learning JavaScript. I'm trying to follow along with a course, so I'm on the lesson about Closures, and I'm at an assignment where I need to finish this exercise. I've tried writing the code in several ways but I keep failing on the last bit of the instructions which specifies to only invoke once, like if the result is 25 and it's called again, it sees it was called by 5 once already, and just returns 25 still. But I'm stuck.
Here is the exercise:
function cacheFunction(cb) {
// use closure to create a cache for the cb function
// the function that you return should accept a single argument and invoke cb with that argument
// when the function you return is invoked with an argument it should save that argument and its result
// when the function you return is called again with an argument that it has seen before it should not call cb
// but should instead directly returned the previous result
// example:
// cb -> function(x) { return x * x; }
// if the function you return is invoked with 5 it would pass 5 to cb(5) and return 25
// if the function you return is invoked again with 5 it will look on an object in the closure scope
// and return 25 directly and will not invoke cb again
--Code here
}
Now here is what I have and it's not working..
function cacheFunction(cb) {
return function (number) {
number + number;
return cb(number);
}
}
I know there is more to it and the way i wrote it, it isn't right, but I'm still new to this and any help would be appreciated. :)
Oh and my JS test for it says this:
cacheFunction(cb)
√ should return the callback function (1ms)
√ should return the callback functions result when the cached function is invoked (1ms)
× should cache function results (4ms)
● cacheFunction(cb) › should cache function results
expect(jest.fn()).toHaveBeenCalledTimes(2)
Expected mock function to have been called two times, but it was called nine times.
46 | cachedFunction(10);
47 | cachedFunction(10);
> 48 | expect(cb).toHaveBeenCalledTimes(2);
49 | });
50 | });
51 |
Why was it called 9 times?
By exercise requirements you need memoization. Simple definition in your case: don't call cb function if you already called cached function with the same number. I could give you an answer, but it will not help you learn the JS. So instead I will provide simple hints.
Your callback is calculator, so move number + number inside of it.
Second create store to hold your values. So if number was already sent, you do not need to recalculate. Think about variable type for store.
Think about first checking the store and if there is no value calculate and store the value.
About the why nine times, I hope you understand that if you cached function will be called nine times with the same arguments. It needs to call cb function only once
Concept used : Closures
Solution:
Instantiate only once using a boolean, which will be remembered because of closures in JS.
const numberFunc = ( num ) => num;
const RunOnlyOnce = ( fn ) => {
let value = null;
var isRun = false;
return function(...args){
if(!isRun){
isRun = true;
value = fn(args);
}
return value;
}
}
const callmeOnce = RunOnlyOnce(numberFunc);
callmeOnce(25); //25
callmeOnce(25); //25
callmeOnce(25); //25
callmeOnce(25); //25
In eloquent JavaScript, the author provides the following example + prose:
With a slight change, we can turn the previous example into a way to
create functions that multiply by an arbitrary amount.
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
var twice = multiplier(2);
console.log(twice(5));
// → 10 The explicit
localVariable from the wrapValue example isn’t needed since a
parameter is itself a local variable.
Thinking about programs like this takes some practice. A good mental
model is to think of the function keyword as “freezing” the code in
its body and wrapping it into a package (the function value). So when
you read return function(...) {...}, think of it as returning a handle
to a piece of computation, frozen for later use.
In the example, multiplier returns a frozen chunk of code that gets
stored in the twice variable. The last line then calls the value in
this variable, causing the frozen code (return number * factor;) to be
activated. It still has access to the factor variable from the
multiplier call that created it, and in addition it gets access to the
argument passed when unfreezing it, 5, through its number parameter.
how does javascript know that the 5 in:
console.log(twice(5));
is suppose to be the value for number? Is JavaScript essentially saying to itself "I already have 2 as the value for factor, and I can't change that, so 5 has to be the value for number".
In other words
var twice = multiplier(2)
so twice = multiplier(2) {return function (number)}
thus twice(5) = multiplier(2) {return function (5)}
Is this right?
if there was another local variable inside multiplier, could I call:
twice(5,10)
and javascript would know that means:
factor = 2
number = 5
third variable = 10
ES6 VERSION
const multiplier = factor => {
return number => number * factor;
}
The part that confused me was thinking that the variable 'twice' was being assigned the multiplier function, rather than the return of the multiplier function (which is also a function).
const twice = multiplier(2);
So what is actually being assigned is:
const twice = number => number * 2
twice(2)
-> 10
Think of it as this :
var twice = function(number) {
return number * 2;
};
When you call multiplier(2) you are creating a new function that embeds factor into that new function.
I was stuck on this for a bit as well. Here's what helped it click for me.
On the book's website, you can interact with the code on the page:
https://eloquentjavascript.net/03_functions.html#p_O3ISvGjNhj
I tried removing the arguments from the twice variable:
function multiplier(factor) {
return number => number * factor;
}
let twice = multiplier(2);
console.log(twice);
This returned: number => number * factor
That helped me realize that twice is being assigned the inner function of multiplier. When I don't pass an argument, it returns the inner function itself. When I pass an argument to twice, it becomes the argument of that inner function, and executes it.
So when I tried this:
console.log(twice());
It attempted to execute the function. And it returns NaN because I didn't pass an argument for number.
So, when we do this:
let twice = multiplier(2);
We are binding the variable twice to the inner function of the multiplier function with (effectively) an argument of 2 passed.
The previous comments explained this operation much more succinctly, but it didn't quite make sense to me until this clicked.
I'm currently working on a programming problem in my personal time that asks that I make a javascript function that can be called in this manner.
add(1) // 1
add(1)(2) // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10
add(1)(2)(3)(4)(5); // 15
What I'm having trouble figuring out is how to make it return a value on the very last call.
For example, in order for add(1)(2) to work, then add(1) has to return a function, but according to the instructions add(1) when called by itself will return 1.
I'm assuming one way you can overcome this is to figure out how many times in succession the add function is being called, but I cannot think of a way to achieve that. Does anyone have any hints that can point me in the right direction?
I've read these two articles (1, 2) on function currying and I understand them, but I'm not sure how to do currying when dealing with a variable number of arguments.
It is impossible to curry a variadic function with an unknown number of arguments.
Where add is a variadic function, you could do something like
var add5 = curryN(add, 5);
add5(1)(2)(3)(4)(5); //=> 15
var add3 = curryN(add, 3);
add3(1)(2)(3); //=> 6
There's simply no avoiding this tho because a curried function will continue to return a function until the last argument is received, at which point the computation is run.
The only other option is to create some way to "short-circuit" the arguments and notify the function that the arguments are done being sent. That would require something like
var xadd = curryUntilUndefined(add);
xadd(1)(2)(3)(4)(5)(undefined); //=> 15
Here, the undefined signals the end of the variadic arguments. I don't really recommend this tho because of the other problems it can create for you. Not to mention, it's not particularly nice to look at.
It is not impossible, use valueOf().
function add(initNum) {
var sum = initNum;
var callback = function (num) {
sum += num;
return callback;
};
callback.valueOf = function () {
return sum;
};
return callback;
};
console.log(add(1)(2)==3); //true
console.log(add(1)(1)+1); //3
console.log(add(1)(2)(3).valueOf()); //6
I don't know if you've ever felt like you've dived off the stupid tree and hit every branch on the way down, but JavaScript has that effect on me, an experienced PHP programmer but just doesn't get JS sometimes.
so I wrote this function using jQuery.extend({ .. }) as follows:
loadSection: function(obj){
if(typeof obj=='undefined')obj=event.target; //but this doesn't work
if(typeof obj=='string')obj=document.getElementById(obj);
var params=null;
var instr={};
var k=0;
while(true){
..etc..
I want to be able to call it two ways:
$.loadSection($('#employee-data-173'));
//or $loadSection('employee-data-173') for convenience
or:
$('#employee-data-173').loadSection();
Clearly (to you anyway!) I'm not grasping the concept of what's being passed in the second case. And that's not even getting into a case like this:
$('.someElement').click(loadSection);
You want to use the same function in three totally different usecases. In each case different arguments are automatically passed to the function. So first declare and prepare it to handle all possible types of arguments:
function loadSection(index, obj, args) {
var element, params = null;
if (obj && obj.nodeType) { // for usecase 2
element = obj; if (typeof args == 'object') params = args;
} else {
if (typeof obj == 'object') params = obj;
if (typeof index == 'string') { // usecase 1 with selector-string
element = document.getElementById(index);
else if (index.jquery) { // usecase 1 with jQuery object
if (index.length == 1) element = index[0]; // if only one element inside jQuery
// if more than one element there call this function recursively on each
else index.each(loadSection);
}
else if (index.target) element = index.target; // for usecase 3
}
/* your stuff */
}
In your usecase 1 you have to add the function to the global jQuery object and call it by $.loadSection(argument), where argument may be a id-selector-string or an jQuery-object $("selector"). There are two ways with identic result:
$.loadSection = loadSection;
$.extend({loadSection: loadSection});
In usecase 2 you want to call the function as a method of a jQuery object. Therefore you have to add it to the jQuery.prototype like so:
$.fn.loadSection = function( args ) { // $.fn is synonym for jQuery.prototype
return this.each(loadSection, args);
};
If you call now $("selector").loadSection() the function is executed once for each element matched by "selector". Arguments index and obj are automatically passed to loadSection.
In usecase 3 the function is used as callback-function for an event. Since its prepared for this case, the event object is automatically passed to it. So just do:
$('.someElement').click(loadSection);
You can use all cases mixed in the same piece of code.
EDIT "What shall/can the function return?"
It may return whatever you want to. Only the behaviour depends on usecase.
In usecase 1 you can do: var result = $.loadSection("selector") and result gets the returned value.
In usecase 2 there is an iteration over all elements in the jQuery object. The return value of loadSection is simply ignored except you explicitely return false. Then iteration stops. So if you do if (index == 2) return false; the function is executed maximum 3 times even when you have 7 elements inside jQuery object.
The function as a whole always returns the jQuery object, so you can do chaining:
$("selector").loadSection().css({color: 'blue'}).animate(...). ...
In usecase 3 the function is only executed but the return value gets never recognized anywhere, so you can't catch it.
EDIT 2 "How to pass additional params to the function?"
1) Now loadSection is prepared to take additional args (see above). 2) The setup of $.fn.loadSection is modified to take args (see above). 3) args must be an object or array eg {prop: 'color', id: 23} (otherwise it's ignored) but may be omitted.
In usecase 1 pass args as second argument
var result = $.loadSection("selector", args); // you find args inside in ""var params"
In usecase 2 args is the one and only possible argument. jQuery now makes an iteration inside an iteration: the function is called on each element once for each item in args!
The inner iteration is stoppable by return false, but the iteration over all elements no longer.
$("selector").loadSection({prop: 'color', id: 23}) // if $() contains 3 elems, function run six times
In usecase 3 its impossible to pass args since you only point to the function by its name.
I'm learning lots of javascript these days, and one of the things I'm not quite understanding is passing functions as parameters to other functions. I get the concept of doing such things, but I myself can't come up with any situations where this would be ideal.
My question is:
When do you want to have your javascript functions take another function as a parameter? Why not just assign a variable to that function's return value and pass that variable to the function like so:
// Why not do this
var foo = doStuff(params);
callerFunction(foo);
//instead of this
callerFunction(doStuff);
I'm confused as to why I would ever choose to do things as in my second example.
Why would you do this? What are some use cases?
Here's yet another example. Does some formatting operations on an array:
function pctFormatter(num) {
return num + '%';
}
function centsFormatter(num) {
return num + '.00';
}
function formatThisArray(array, formatter) {
var output = [];
for(var i = 0; i < array.length; i++) {
output.push( formatter(array[i]) );
}
return output;
}
formatThisArray([1,2,3], pctFormatter);// returns ['1%', '2%', '3%']
formatThisArray([1,2,3], centsFormatter);// returns ['1.00', '2.00', '3.00']
Handlers/listeners are a good example.
More generally, you can pass a function f as a parameter to function g when you don't know yet if g will need to call f, how many times it will need to call it, and/or with which parameters.
Examples:
sort algorithms: comparison function
regular expressions: replace function
callbacks (e.g. event handlers)
You'd do it when you don't have the params to pass, but the callerFunction() does.
A callback to an AJAX request is one use case.
function myCallback(response) {
// do something with the response
}
myAJAX('http://example.com/foo.json', myCallback)
This lets myAJAX to the work of making the request, and waiting for the response. Then it invokes myCallback and passes it the response when that response finally arrives.
// Why not do this
var foo = doStuff(params);
callerFunction(foo);
//instead of this
callerFunction(doStuff);
First example will run the function doStuff with params and the assign the result to foo. callerFunction will be called with parameter foo (which is now a result of dooStuff);
Second example will call callerFunction and pass doStuff as a parameter. The callerFunction might or might not call the doStuff.
Well, sometimes you don't know who the caller of a function will be until it's called - this precludes passing pre-calculated values.
A couple of examples that spring to mind are:
(a) setTimeout or setInterval - you want to call a specific function after a specified period, either one-shot, or repeatedly. If the function called returned a value that had a dependance on time, there are instances where you couldn't possibly pre-calculate the value - it needs to be done at the scheduled time. So, we tell the functions which of our own functions to call at the specified time.
(b) when loading (or at least attepmpting to) various resources. We can give the element a function that is to be executed when loading is successful, and another when it fails. You don't actually know when the effort to load a resource has finished until either of these two (user-supplied) functions are called. In the case of many resources, this is where you increment the counters that maintain the number of successful/failed load attempts.
(c) the NodeList returned by calls to getElementsByClass or getElementsByTagName. It's not an actual (javascript native) Array object. As such, you can't call the forEach method on it, like you can with an array. To get around this, I use the following helper function:
// getElementsByTagName, getElementsByClass - both return a NodeList
// it is accessed in the same way as an array - with the [] operators, but it's
// not an array object - this is a function that allows us to still iterate through it
// in much the same way.
function forEachNode(nodeList, func)
{
var i, n = nodeList.length;
for (i=0; i<n; i++)
{
func(nodeList[i], i, nodeList);
}
}
This allows me to get a list of nodes and then call some user-defined function on each of them. In use, it looks like this:
var allAnchors = document.getElementsByTagName('a');
forEachNode(allAnchors, showNodeTextVal);
function showNodeTextVal(curElem, curIndex, origList)
{
alert(curElem.innerText);
}
Or more simply:
var allAnchors = document.getElementsByTagName('a');
forEachNode(allAnchors, function(curElem){alert(curElem.innerText);} );
This is a much clearer, less error-prone situation than it would be if we didn't use this helper function. To achieve the same functionality, we'd need to code the following:
var nodeList = document.getElementsByTagName('a');
var i, n = nodeList.length;
for (i=0; i<n; i++)
{
alert(nodeList[i].innerText);
}
Most common case is handlers in JQuery:
function clickHandler(e){
// handle click on e.Target
}
$("#button").click(clickHandler);
$(function(){
// do ready state initialization
});
callerFunction(doStuff);
with this code you give a "pointer" of the function doStuff to the function callerFunction
you can use it like this:
function callerFunction(doStuff) {
var x = doStuff(...);
...;
}
you can so use the function in the function and not only the return value of doStuff.
greetings!
When do you want to have your javascript functions take another
function as a parameter?
It's useful for callbacks for example:
function add( a, b, callback ) {
callback( a, b );
return a + b;
}
function added( a, b ) {
alert('You just added two numbers: '+ a +' and '+ b);
}
alert( add( 1, 2, added ); // Will alert the message and then the result.
This a very simple example but it's very useful with asynchronous functions so you can run code after it has finished without interrupting the script.
You need to pass functions themselves, not return values, when you want to have your code really deal with functions as functions - code to execute. Consider this pseudo-code example:
function saveToLocalStorage(data) {...//saves to local storage}
function saveToServer(data) {...//saves via AJAX to server}
function saveToAmazonS3(data) {.../saves to Amazon S3 }
function multiSave(data, saverFunctions) {
saverFunctions.forEach(function (saverFunction) {
saverFunction(data);
});
}
multiSave({user: "tim"}, [saveToLocalStorage, saveToServer, saveToAmazonS3]);
In this case, I want the actual functions themselves to be passed around and for other code to later invoke them. When we do this, a function such as multiSave is called a higher-order function because it deals with other functions directly. Because of the way multiSave works, I can easily put some checkboxes in the UI next to local/server/S3 and allow the user to choose where their data goes in a way that would be less elegant if I was unable to pass functions around as arguments.
When you're passing a function as an argument, that argument is not the return value of that function, but it's the function itself, you can call it as much as you like, with any argument you like, or you can assign it to an event. You say you want some practical use cases, here's a short list of very common situations, all requiring a function to be passed as an argument.
Let's take a look at your average jQuery code, and count the number of times where a function is passed as an argument:
$(document).ready(function()//<-- 1
{
$('#foo').on('click',function()//2
{
});
$.each(something,function()//3
{});
//and so on
});
If you don't use jQuery, then try event delegation
document.body.addEventListener('click',function(e)
{
e = e || window.event
console.log('This function was passed as an argument to the addEventListener method');
},false);
Or even the simple Array.prototype.sort function (/method):
anArray.sort(function(a,b)
{
return (a > b ? 1 : -1);
});
Or in cases where you need to make an ajax call, instead of creating a new XMLHttpRequest object on the spot, you might want a single function that sets the xhr object up, and pass the url, data and onreadystatechange callback as arguments:
function makeXHR(url,data,callback)
{
try
{
var xhr = new XMLHttpRequest();
}
catch(e)
{
//etc...
}
xhr.onreadystatechange = callback;
}
makeXHR('some/url','foo=bar',function()
{
if (this.readyState === 4 && this.status === 200)
{
//do stuff
}
});
In all of these examples, I've created the functions in-line, of course referencing a function (by just passing its name) works just fine, too:
makeXHR('some/url','foo=bar',defaultXhrCallback);
These are just a few of thousands of use cases where you can/have to pass a function as an argument to another function