Javascript - why my function is recursive? - javascript

I don't know where am I going wrong. Why is my function resursive? I expect a result of sum = 3;
function init() {
let object = {
firsNum: 1,
sum: 0,
};
add(1, object.firsNum, fun);
console.log(object.sum);
}
function fun(a) {
a.firstNum++;
a.sum += a.firsNum;
fun(a);
}
function add(a, b, callback) {
return callback(a + b);
}
init();

I think you don't fully understand every programming concept you've used in your code.
Apart from that your original code contains a typo: a.firstNum++; where it should read firsNum like in all other places.
Let's break down your code into separate concerns.
Recursion
Recursion means that a function calls itself. Recursion is one way to compute, iterate or traverse data. The other one is iteration using loops like while or for.
Let's look at this simplified example:
function recurse(counter) {
console.log(counter);
recurse(counter + 1);
}
recurse(0);
This will call recurse() indefinitely since there's nothing that stops it to call itself. Recursion as well as iteration require some stop condition to break the recursion.
If you'd like to stop at a certain value you'd have to call the function only until that condition is met:
function recurse(counter) {
console.log(counter);
if (counter < 42) {
recurse(counter + 1);
}
}
recurse(0);
This will only recurse and increment until 42 is reached.
You could even pass the stop condition with the function itself:
function recurse(counter, maxValue) {
console.log(counter);
if (counter < maxValue) {
recurse(counter + 1, maxValue); // maxValue gets passed along
}
}
recurse(0, 42);
To make your recursive function stop at a certain value you've to add such a condition:
function fun(a) {
a.firstNum++;
a.sum += a.firstNum;
if (a.sum < a.maxNum) {
fun(a);
}
}
You'd then have to ensure your object specifies the condition:
let object = {
maxNum: 3, // stop condition added
firsNum: 1,
sum: 0,
};
Though this on its own won't solve the problem. Read on.
Callbacks
Callbacks are functions passed as function parameters, object properties or array elements to other functions.
Callbacks allow you to decide what function to call during the runtime without having to implement branching behavior using if or switch statements and requiring certain function names at time of writing.
function someCallback() { /* ... */ }
function callTheCallback(callback) {
callback(); // Execute the parameter as a function
}
callTheCallback(someCallback);
let someCallbackReference = someCallback;
// Call the same function but indirectly via a variable
callTheCallback(someCallbackReference);
In the above example someCallback could indirectly origin from an other object.
You could even directly specify a function expression as a callback:
callTheCallback(function() {
// ...
});
With callbacks it's crucial to grasp the difference between passing a function call result and the function itself:
callTheCallback(someCallback); // Callback function passed
callTheCallback(someCallback()); // Result of a function call passed
Note that it could be perfectly valid to pass the result of a function call if the return value itself is a function. This is also not uncommon in programming.
Callbacks are often used for inversion of control (IoC) in general and asynchronous programming specifically.
Examples for callback functions:
Filtering arrays: Array.prototype.filter() (IoC synchronous)
Events: window.onload (asynchronous)
In your case fun() is passed as third parameter callback to add().
Now that you know how to use recursion and callbacks there are still semantic errors in your code...
Semantical errors
In contrast to syntactical errors (wrong code grammar) semantical errors are errors with the meaning of the code.
Interface of add()
Analyze your function API:
function add(a, b, callback) {
return /* some value - callback() call removed for simplicity */;
}
add() accepts three parameters and returns a value. The third parameter is named "callback" and thus shall be a function.
Your call of add() looks sensible although you don't use the returned value (which is not necessarily an error).
add(1, object.firsNum, fun);
Implementation of add()
Since the parameters of add() are not documented, it is ambiguous what your intention was.
The name along with the fact that there are two parameters, a and b, leads one to the assumption that the two values shall be added. And you very well do this:
return callback(a + b);
But! what you've passed as callback function - which is fun() - expects different parameters, not a number. fun() expects an object.
Properly documented it would look like this:
/**
* Recursively sum values until a maximum value is reached.
*
* #param {Object} a object containing the sum, the increment and the max value
* #param {Number} a.firsNum start value
* #param {Number} a.maxNum the maxium value up to which to add "firsNum" to "sum"
* #param {Number} a.sum the summed value, shall be 0 initially
* #returns {undefined} nothing is returned
*/
function fun(a) {
// ...
}
The above comment style is called JsDoc: https://jsdoc.app
Note to use proper names for functions, variables and parameters. Proper names help documenting the code whithout writing explicit documentation comments.
Fixing the error
With the limited knowledge on what your actually wanted to achive one can only speculate. I assume add(), although it's name and parameters looks sensible, is implemented wrong. Your issue could be solved by calling the callback (fun()) correctly:
function add(obj, callback) {
return callback(obj);
}
And:
add(object, fun);
Since we require the object add() now expects it as a single parameter.
Well that does not make a lot sense anymore now. fun() could be called directly from within init() and not via a callback reference and add() has as a confusing name.
I won't further speculate what your intention was and how to implement alternative solutions to the problem.
What you've learned
About Mozilla developer network
How recursion works
Functions can be passed as parameters and be assigned to variables or properties
Reading code
The benefits of documenting code and properly naming functions and variables

Just commented out the recursive code
function init() {
let object = {
firsNum: 1,
sum: 0,
};
add(1, object.firsNum, fun);
console.log(object.sum);
}
function fun(a) {
a.firstNum++;
a.sum += a.firsNum;
//fun(a);
}
function add(a, b, callback) {
return callback(a + b);
}
init();

Your code
function init() {
let object = {
firsNum: 1,
sum: 0,
};
add(1, object.firsNum, fun);
console.log(object.sum);
}
function fun(a) {
a.firstNum++;
a.sum += a.firsNum;
fun(a);
}
function add(a, b, callback) {
return callback(a + b);
}
init();
init
Defines an object with attributes of firsNum and sum, then calls add, passing 1, 1 and fun.
fun
Receives a parameter. Increments firstNum of the parameter and adds it to sum. Then it calls itself.
add
Gets three parameters: a, b and callback. Calls callback and passes a + b to it.
The flow
init is called, then it calls add and passes 1 to a, 1 to b and fun to callback. As a result, add calls callback, which is fun and since both a and b are 1, a + b = 2 is passed to fun. fun increments a.firstNum, which seems to be a bug, since a is a number, then some other strange value is added to sum. Just remove fun(a); inside fun to get rid of recursion, but that's not the only bug in your code. Also, make sure that there is a return statement inside fun.

Related

Attempting to pass a string to a constructed function

still floundering around in my attempts to understand functions. How would I go about constructing a function with values I want to pass to it?
var box = $('#box1');
function pushCard(arg1) {
if (this.style.opacity == 0.5) {
this.style.opacity = 1;
}
else {
this.style.opacity = 0.5;
window.alert(arg1);
}
}
box.click(pushCard('String'));
tl;dr: be aware of the difference between functions / function results and when functions are passed as values / when they're called (and their result is passed)
The culprit is with this line:
box.click(pushCard('String'));
You're calling box.click() with "something". JavaScript needs to evaluate expressions before passing them as function arguments.
In this case, you instruct JavaScrip to run box.click(pushCard('String')) = call box.click with value of pushCard('String') as first parameter.
In order to do this, JavaScript first needs to evaluate pushCard('String') by running pushCard with value 'String' as first parameter (this doesn't need more evaluation since it's already a value).
The result of pushCard('String') is undefined (you're returning nothing from that function). So in effect, it's the equivalent of box.click(undefined).
This is what you want:
box.click(function() {pushCard('String')});
(or with ES6 arrow functions: box.click(() => pushCard('String'));)
In this case, you're assigning box.click() a function. This is what jQuery .click()` expects, a click handler which will run (be evaluated) then the click happens, not when the click handler is assigned.
In JavaScript, you can pass functions as values, and they are evaluated when explicitly called:
function test() {
alert('I have been called');
}
function delay_it(handler) {
setTimeout(function() {
handler(); // ⇽ call given function
}, 1000);
// shorter: setTimeout(handler, 1000);
}
// Wrong (we're calling test() by ourselves and passing the result (undefined) to delay_it
delay_it(test());
// Correct (we're giving test as function to delay_it, delay_it will call the function)
delay_it(test);

Passing function as parameter on javascript

I recently started to learn javascript and saw this code. It was very different than C++ so please tell me what it means.
function getWeather(lat, lng){
fetch(
`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${API_KEY}&units=metric`
)
.then(function(response){
return response.json();
})
.then(function(json){
const temp = json.main.temp;
const place = json.name;
weather.innerText = `${temp} # ${place}`;
});
}
so basically it gets api and fetch it. After that it continues with .then(function(response)
I have no idea where that response come from. I can guess that response part is something returned from fetch function but still I don't understand how that happens.
const parsedToDos = JSON.parse(loadedToDos);
//for each takes function and execute function on each items.
parsedToDos.forEach(function(toDo){
paintToDo(toDo.text);
});
similar to the previous example, it takes toDo as parameter and it is not even global or local variable in this code but still used. Can anyone tell me the logic behind this?
Which arguments a function receivedsis determined by the caller of the function. If you have the following function
function add(a, b) {
return a + b;
}
Then "you" can call it as
add(1, 3)
Sometimes it is not directly "you" who calls the function, but another function. E.g.
function add1(a) {
return add(a, 1);
}
here add is called by add1. add1 will always pass 1 as second argument.
In addition to that, sometimes functions accept other functions as arguments and call them at some point. Again an example:
function doSomething(callback) {
return callback(40, 2);
}
Here doSomething accepts a function as argument and will always pass 40 and 2 as arguments. If I pass a function that expects to be passed two numbers it will work as expected:
// Works
doSomething(function (a, b) { return a + b; });
If I don't not, then I get some unexpected behavior or an error:
// Error :(
doSomething(function (a, b) { a.foo.bar = b });
But if that happens then I haven't read the documentation properly, because functions which accept callbacks usually explain which arguments are passed to the callback. For example for forEach (emphasis mine):
forEach() calls a provided callback function once for each element in an array in ascending order. It is not invoked for index properties that have been deleted or are uninitialized (i.e. on sparse arrays, see example below).
callback is invoked with three arguments:
the value of the element
the index of the element
the Array object being traversed
Similar for .then.
In summary, arguments are provided by the caller. If you pass a callback to a function then that function will most likely be caller and pass arguments. Read the documentation or look at the source code to find out which arguments these are.

How to check if a callback function passed as a parameter in Javascript has arguments or not?

I have to do this
doSomething
.then(success)
.catch(failure);
And success and failure are callback functions which will get their value at run time (I am trying to write a module).
So I have to know that the function failure which is sent as a callback should have a parameter.
Because the callback is supposed to be like
function(error) {
// An error happened
}
Is there anyway in JS to do this? Or any library that makes this kind of checking possible?
EDIT
Just to clarify. I want a user(not end user), who uses my module, to send in a function as a parameter which will become a callback and I want to check if the function sent, which will be called back, has enough parameters required. I understand it is up to one who uses it to take care of that. But why not try?
With a promise callback (your then and catch handlers), they will only be passed a single argument when called, and will always be passed that argument. (If the promise is obeying native semantics; jQuery's Deferred doesn't always.)
In the general case:
Usually you don't care, because in JavaScript, you can call a function with either fewer or more arguments than it has formal parameters. That is, this is just fine:
function foo(a) {
console.log("a = " + a);
}
foo(); // Fewer arguments than params
foo(1, 2, 3); // More arguments than params
Another reason you don't care is that the function can use arguments even when it doesn't declare formal parameters for them, by using a rest parameter or the arguments pseudo-array (you'll see why this snippet logs foo.length and bar.length in a moment):
function foo() {
console.log("First argument: " + arguments[0]);
}
function bar(...rest) {
console.log("First argument: " + rest[0]);
}
foo(1); // First argument: 1
bar("a"); // First argument: a
console.log("foo.length = " + foo.length); // foo.length = 0
console.log("bar.length = " + bar.length); // bar.length = 0
So just define what your API will call the callbacks with, and do that, and it's up to the users of the API to ensure that they use what you call them with correctly.
On those occasions it matters, you can use the function's length property to know how many formal parameters it declares:
function foo(a) {
console.log("a = " + a);
}
console.log(foo.length); // 1
Note that that will tell you how many formal parameters are declared...
...not counting a rest parameter (...identifier)
...only up until the first parameter with a default value (even if there are ones without a default after it)
So for instance:
function foo(a, b = false, c) { // b has a default value
console.log("a = " + a);
}
console.log(foo.length); // 1, even though `c` has no default value,
// because `c` is after `b`
and
function foo(a, ...rest) {
console.log("a = " + a);
}
console.log(foo.length); // 1, because the rest parameter doesn't count
It's probably an anti pattern for the caller to enforce a certain number of arguments of a callback, but if you must you can check the length of the function:
function test() {}
function test1(a) {}
function test2(a, b) {}
console.log(test.length, test1.length, test2.length)
I need to know whether the function which is sent as a callback should have a parameter
You need to read the documentation of the function that you are sending the callback to. It will mention how (when, how often, and with what arguments) the callback is called.
For your failure that means reading the docs for catch (assuming doSomething is a native promise). It says that the callback will be called with one argument, the rejection reason, when the promise is rejected.
Or any library that makes this kind of checking possible?
You can use a typechecker that will warn you or throw an error when the function you are passing does not have the expected number of parameters.

what happen when we pass arguments inside the function itself?

Kindly Accept my apologies for being a beginner in JS.
I stopped studying JS on a point of what is the correct answer of what happen inside a function when passing arguments, let us describe by code snippet.
function myFun(x){
console.log(arguments);
console.log(x);
}
myFun(1);
according to the above example,
is the correct action happened is :
Example 1
when passing calling myFun(1) this will do :
function myFunction(x){
var x = 1
}
OR
Example 2
function myFunction(x,y,z){
x=arguments[0];
y=arguments[1];
z=arguments[2];
}
according to the main documentation, i didn't find the desired approach, what i found in arguments object creation process is that:
Repeat while indx >= 0,
Let val be the element of args at 0-origined list position indx.
which I couldn't specify this related to the process of assigning the values or not.
So according to above at all ,
which solution is the correct?
how arguments assigned to parameters? if we passed value 1 as an argument , in the function scope, 1 will be assigned to x or 1 will be assigned to arguments Object?
Let's say you have a function like this:
function oneParam(x)
{
console.log(arguments[0]);
console.log(x);
}
Calling it like so: oneParam(1); will put the first parameter passed in, into the arguments array. If you run the above code, you will get the same value printed twice, because they are the same.
1
1
Now let's take a function with multiple params:
function myFunction(x,y,z)
{
console.log(arguments[0], arguments[1], arguments[2]);
x=arguments[0];
y=arguments[1];
z=arguments[2];
console.log(x, y, z);
}
You will notice, that calling this function like this myFunction("a","b","c"); will produce two similar outputs.
a b c
a b c
So essentially, both scenarios are correct. Just depends on what you passed in when calling the function.
Edit: To clarify, the arguments object will have all the params you passed in. These params will, in order, be assigned to named variables that are there in the function signature.
So you can even have oneParam(1, 2, 3); and the arguments object will have all three params, but only the first param 1 will be assigned to the function variable x.
fiddle here
If you name arguments in your function like this:
function myFunction(x,y,z)
{
console.log(x, y, z);
}
then it's better to access them by their names directly.
You can use argumens if you don't know the number of the arguments while defining the function, like Math.max(), for example.
ES6 makes use of arguments slightly easier than it was before, but it's quite similar. Just remember that arguments is not an array, therefore it has to be converted to an array if you want to have access to all array's methods.
function myFunc_ES6() {
var args = [...arguments];
// or
//var args = Object.values(arguments)
args.forEach(arg => console.log(arg));
}
function myFunc_ES5() {
var args = Array.prototype.slice.apply(arguments);
args.forEach(function(arg) {
console.log(arg);
});
}
myFunc_ES6(1,2,3,4);
myFunc_ES5(6,7,8,9);
The Arguments Object
JavaScript functions have a built-in object called the arguments object.
The argument object contains an array of the arguments used when the function
was called (invoked).
as stated in https://www.w3schools.com/js/js_function_parameters.asp
arguments can be used when you don't want to explicitly specify the parameters of a function. This can be useful in many situations.
Eg.
different behavior on different arguments count
function foo() {
if(arguments.length == 2){
// do something
}else{
//do something else
}
}
extending some method
var oldMethod = Object.prototype.method;
Object.prototype.method = function() {
// some extended functionality
// then call the original
oldMethod.apply(this, arguments);
}
working with unknown number of arguments
function average(){
var i, s=0;
if(!arguments.length){
throw('Division by zero.');
}
for(i=0;i<arguments.length;i++){
s+=arguments[i];
}
return s/arguments.length;
}
Regarding the way the values get assigned,
if we have a function:
function foo(x){}
no matter what you pass in as parameters thiswill be true:
x === arguemnts[0]
It is almost like x is staticaLly referenced in the arguments, because operating on arguments alters the refs too:
arguments[0]++;
x === arguments[0] // true
however deleting the arguments[0] will not modify the explicit parameter value
delete arguments[0]
x !== undefined

Javascript call() function - extra parameters

I'm reading Javascript: The Definitive Guide 6th Edition. It teaches ECMAscript 5. Anyway, it doesn't explain certain things thoroughly, like the call() function for example. This is about the extent of the book's definition:
Any arguments to call() after the first invocation context argument are the values that are passed to the function that is invoked. For example, to pass two numbers to the function f() and invoke it as if it were a method of the object o, you could use code like this:
f.call(o, 1, 2);
In the next section the author builds a map function. I've been studying Ruby so I know how map works. My question is about the implementation using the call() function. It looks like this:
var map = function(a,f, o) {
var results = [];
for(var i = 0, len = a.length; i < len; i++) {
if (i in a)
results[i] = f.call(o || null, a[i], i, a);
}
return results;
};
It then defines a square function and puts map to use:
function square(x){
return x*x;
}
var array = [1,2,3,4,5];
var results = map(array, square);
What is the purpose of the i, and a parameters in the call() function? If I remove them I get the same results.
Array.prototype.map is defined to pass the index and the array to the callback, just in case you need them. For example, instead of square(x), you could use Math.pow(base, exponent):
var results = [1, 2, 3, 4, 5].map(Math.pow);
console.log(results); // [1, 2, 9, 64, 625]
This map behaves in the same way. You don’t have to use the arguments if you don’t need them in a particular case.
Function.call allows you to call a function as though it were a method attached to an object.
What this means is you can have a function that is defined somewhere unrelated to an object, and then you can call that function as though it was a part of that object. This is a long way of saying that when you use Function.call, you are telling the JS engine to use the first parameter whenever you use 'this' inside the function.
So:
function set_field_value(name, value) {
// do stuff
this[name] = value;
}
makes no sense by itself, because the special variable 'this' is not set to anything (meaningful)
But, if you use call, you can set it to whatever you want:
// if my_object = some object:
set_field_value.call(my_object, 'firstname', 'bob');
console.log(my_object.firstname); // prints 'bob'
The only important argument to call is the first one, (in the above case, my_object) because the first argument becomes 'this' inside the function. The rest of the arguments are passed 'as is' to the function.
So - in your example, the i and a arguments are there to make the map function look like other map functions, which provide the array (a) and index (i) that are being worked on.
Hope that helps,
Jay
PS - I strongly recommend the book 'Javascript: the good parts' - it makes a lot more sense than the definitive guide.
f.call in this example equals to square.call, and square requires only one parameter(x), so i and a are totally redundant here (and not used). Only a[i] is used by the function.
However, since you can pass in any function you want as the second parameter of the map function, chances are there will be another function instead of square coming up in the book, and that function would require those additional two parameters as well. Or you can make one example yourself to try it.
function threeParams(a, b, c) {
return [a, b, c]; // simply puts the three parameters in an array and returns it
}
var array = [1,2,3,4,5];
var results = map(array, threeParams);
Your main confusion is not really about the call method. It's more about how javascript treats function arguments.
Forget about call for a moment and let's look at a regular function to minimize the number of things under consideration.
In javascript, functions are allowed to be called with more arguments than is specified. This is not considered an error. The arguments may be accessed via the arguments object:
function foo (arg1) {
alert('second argument is: ' + arguments[1]);
}
foo('hello','world'); // this is not an error
Javascript also allows functions to be called with fewer arguments than specified. Again, this is not considered an error. The unpassed arguments are simply given the value undefined:
function foo (arg1,arg2, arg3) {
alert('third argument is: ' + arg3);
}
foo('hello'); // this is not an error
That's all there is to it. When the function passed to map() is defined to accept one argument but map() calls it with three the remaining two arguments are essentially ignored.

Categories

Resources