Call back function is hard to understand

let add = function(a,b){
  return a + b
}

let multiply = function(a,b){
    return a * b


}


let calculate = function(num1, num2, call){

     call(num1, num2)


}


console.log(calculate(4, 2, add))

says undefined, why

The calculate function doesn’t return anything, so JavaScript defaults to using undefined.

Return the call, and you will get a result.

I thought callback functions don’t need return or is this even one?

All functions return a value. That value is undefined unless you use the return keyword to return something more intentional.

It’s only arrow-notation that is an exception as that has an implicit return of the last expression evaluated. Everything else needs to use the return keyword to return anything other than undefined.

2 Likes

Nope. A callback function is a function passed into another function as an argument. In your case add is being used as callback function. And probably multiply, too, but not in the sample you provided.

If you like more modern JavaScript syntax you can write:

const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
const calculate = (num1, num2, call) => call(num1, num2);
console.log(calculate(4, 2, add));

But at some point that gets hard to read, so I’d probably stick to using function.

Also, use const to declare things that you won’t reassign and let for things that you will reassign.

1 Like

That’s a good point. The let keyword acts as a warning that the variable is planned to be reassigned at some later stage. When there is no plan to reassign the variable and you use let, it becomes an annoying distraction looking for where the variable gets reassigned, only to find that it hasn’t.

The const keyword is the reliable default when it comes to assigning variables. The aim is to always use const for consistency and reliability. That way uses of let are few and far between, and tend to only be reserved for rare and well-known situations.

1 Like

You could make that even more elegant using destructuring. Destructing coupled with arrow functions are the two modern features I use the most to write compact, elegant, flexible functions. Arrow functions come in a lot of handy with reactive code where done correctly every function is just a pipeline of stream operations.

of([1, 2]).pipe(sum()).subscribe(sum => console.log(`sum = ${sum}`);

When pairing with reactive code much of the modern features result in more elegant, compact syntax.

I’ve always liked the idea of building a true async language removing all the cruft of js.

([1, 2])(sum)(`sum = ${$1}`)
  1. Doing away with function keyword entirely making () an automatic async arrow function.
  2. The first token inside () acts as the function name.
  3. Doing away with explicitly declared inputs instead use implicit inputs.

Anyway reactive programming in js is an overkill for this as as all those separate function declarations. Just use reduce.

const sum = [1, 2].reduce((p, c) => p + c, 0);
console log(`sum = ${sum}`);

While I agree about the use of destructuring, you might want to examine more closely the level that Growly is at for appropriateness.

1 Like

You are probably right about that. However, I do believe that introducing people to reactive programming sooner rather than later has its advantages. Thinking in async streams is much different than thinking in traditional procedural or even functional programming. Most of what JavaScript is manipulation of async streams. You can either do that using a very limited promise based system or become familiar with reactive tools that make it much easier to create large scale modern async dynamic browser applications.

of([1, 2]).pipe(sum()).subscribe(sum => console.log(sum = ${sum});

For me this is only horrible to read…

1 Like

I’m not going to further get of topic but observables have significant advantages over promises. Yes, there is a learning curve but once harnessed much more powerful and elegant than promises or god forbid nested callbacks.

I do not see any advantage in forcing code which can be synchronous to be async only because its more hip.

1 Like

@Growly

You were very close

const add = function(a, b){
  return a + b
}

const multiply = function(a, b){
  return a * b
}

const calculate = function(num1, num2, callback){
  // return the result of calling the callback function
  return callback(num1, num2) 
}

console.log(calculate(4, 2, add /*callback*/)) // 6
console.log(calculate(4, 2, multiply /*callback*/)) // 8

It’s got it’s time and place, and in another thread would be a great topic :slight_smile:

4 Likes

Correct, this is a bad example. One where you need to orchestrate http requests transform, combine, merge data is not.

Just for the sake of completeness,
const when declared as an object or array can have different values assigned just as the values of the arguments for a const function can have different value arguments assigned.

1 Like

I see, gg

Do some methods don’t need a return function?

Yes, there are some functions that don’t use a return function. Instead of returning information, they tend to have what are called “side-effects” that affect other things.

An example of a callback function that uses a side effect is:

const list = ["grannysmith apple", "cavendish banana", "maraschino cherry"];
const apples = [];
list.forEach(function findApples(fruit) {
  if (fruit.includes("apple")) {
    apples.push(fruit);    // <== side-effect
  }
});

The findApples() callback function has a side-effect where it reaches out of the function and changes the apples array.

Instead of using a side-effect, it’s better if a technique is used where the function uses a return value. That can be done with the filter method.

const list = ["grannysmith apple", "cavendish banana", "maraschino cherry"];
const apples = list.filter(function findApples(fruit) {
  return fruit.includes("apple");
});

We can also extract out that findApples function:

function findApples(fruit) {
  return fruit.includes("apple");
}
const list = ["grannysmith apple", "cavendish banana", "maraschino cherry"];
const apples = list.filter(findApples);

And we can replace that function with arrow-notation instead:

const findApples = (fruit) => fruit.includes("apple");
const list = ["grannysmith apple", "cavendish banana", "maraschino cherry"];
const apples = list.filter(findApples);
2 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.