1

I am trying to pass a callback function inside a self-invoking function in JavaScript but I get 'undefined' when done function is executed.

I read this answer to write this code below:

function done() {
 console.log(dateFilter.getI());
 console.log(dateFilter.getF());
}
var dateFilter = (function(callback) {
 var _dInicio = new Date(), _d = new Date(),
 _dFim = new Date(_d.setMonth(new Date().getMonth() - 1));
 return {
 getI: function() { return _dInicio; },
 getF: function() { return _dFim; },
 setI: function(d) { _dInicio = d; },
 setF: function(d) { _dFim = d; }
 }, callback();
 })(done);

Maybe I am using the comma operator wrong, but I think this should work. Someone could point me where i am misunderstanding something?

asked Feb 6, 2018 at 17:33
1
  • done doesn't return anything. Are you at least getting the logs for the dateFilter? Commented Feb 6, 2018 at 17:35

3 Answers 3

3

You're calling the done function after a return, further, you're not passing the param dateFilter.

return { -> return before calling callback `function`.
 getI: function() { return _dInicio; },
 getF: function() { return _dFim; },
 setI: function(d) { _dInicio = d; },
 setF: function(d) { _dFim = d; }
}, callback( );
 ^
 |_ Calling callback without param `dateFilter`

Look at this code snippet

function done(dateFilter) {
 console.log(dateFilter.getI());
 console.log(dateFilter.getF());
}
(function(callback) {
 var _dInicio = new Date(),
 _d = new Date(),
 _dFim = new Date(_d.setMonth(new Date().getMonth() - 1));
 callback({
 getI: function() {
 return _dInicio;
 },
 getF: function() {
 return _dFim;
 },
 setI: function(d) {
 _dInicio = d;
 },
 setF: function(d) {
 _dFim = d;
 }
 });
})(done);

See? now is printing the values.

answered Feb 6, 2018 at 17:38
Sign up to request clarification or add additional context in comments.

5 Comments

I see, that works, but this way I can't access dateFilter inner functions out of done function scope, can I?
@AlexandreMiziara I don’t understand. Which inner functions?
all the functions inside dateFilter (getI, setI, etc.)
Your snippet does assign var dateFilter = undefined, as the IIFE doesn't return anything.
@AlexandreMiziara they are available because were passed as param to your done function.
2

Two reasons this cannot work:

  • You are returning the result of callback with your comma operator, but done does not return anything
  • You are trying to use dateFilter during the IIFE initialisation of dateFilter - it is not yet assigned the return value

There is absolutely no reason to use a callback with an IIFE. Just write

var dateFilter = (function() {
 var _dInicio = new Date(), _d = new Date(),
 _dFim = new Date(_d.setMonth(new Date().getMonth() - 1));
 return {
 getI: function() { return _dInicio; },
 getF: function() { return _dFim; },
 setI: function(d) { _dInicio = d; },
 setF: function(d) { _dFim = d; }
 };
}());
console.log(dateFilter.getI());
console.log(dateFilter.getF());
answered Feb 6, 2018 at 17:39

3 Comments

Actually I need to execute a function after ensure that dateFilter has been executed, that's why I tryied using callback. Should I use promies instead?
There is nothing asynchronous in here, so just placing it after the IIFE will ensure that it has been run.
If the initialisation process was asynchronous, then yes, use promises.
1

You're really close. Your hunch about the comma operator is correct. And I think there's a better way to wire up your done() callback so that the code is a bit more robust, and the order in which things happen is a bit clearer.

First, let's look at the return statement. All return statements do two things (evaluate the return value, then return it), but because of the comma, this one is doing three, in the following order:

  1. Evaluating the object literal { getI:... }
  2. evaluating callback(), which means calling callback()
  3. returning the return value of callback(), since the comma operator returns it's second operand.

So, note that callback() actually gets called before your function returns, so it happens before dateFilter has a value. (And, even if it did have a value, it would be the return value from callback(), which is undefined.)

And I think there's another aspect of your code here that I think is worth a look. Callbacks typically take parameters. The simplest way to think of it is: Instead of returning a value, you pass it to the callback.

In general, code is easier to read and debug if you pass parameters instead of side-effecting shared variables.

I just made one change to your code, and it's working:

function done(dateFilter) {
 console.log(dateFilter.getI());
 console.log(dateFilter.getF());
}
(function(callback) {
 var _dInicio = new Date(), _d = new Date(),
 _dFim = new Date(_d.setMonth(new Date().getMonth() - 1));
 callback({
 getI: function() { return _dInicio; },
 getF: function() { return _dFim; },
 setI: function(d) { _dInicio = d; },
 setF: function(d) { _dFim = d; }
 });
 })(done);

So, what did I do?

  • Instead of side-effecting the dateFilter value, I pass it directly to callback.

This means: no comma operator in the return statement, and no need to side-effect the dateFilter global value. (dateFilter is now a parameter to done isntead.)

I hope that clarifies things for you. Cheers!

answered Feb 6, 2018 at 18:02

1 Comment

That clarifies a lot. I wasn't seeing how the order of the things was beeing executed before. Thanks for your answer. Now I understant better how callback and comma operator can work together.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.