Why should you wrap the callback with an anonymous function?

My html contains two forms overlapping with each other, one is used as an add form and the other is used as an edit form. I am using jQuery to show and hide them with the following code:

var editForm = $("#edit-form");
var addForm = $("#add-form");

var showEditForm = function() {
    editForm.fadeIn(function() {
        addForm.fadeOut();
    });
};
var showAddForm = function() {
    editForm.fadeOut(function() {
        addForm.fadeIn();
    });
};

      

I wanted to make the code more compact, so I set the call fadeOut()

directly to the callback by fadeOut()

doing the following:

var showEditForm = function() {
    editForm.fadeIn(addForm.fadeOut);
};
var showAddForm = function() {
    editForm.fadeOut(addForm.fadeIn);
};

      

But this throws the following error Uncaught TypeError: Failed to execute 'animate' on 'Element': Valid arities are: [1], but 4 arguments provided.

, but why doesn't it work?

+3


source to share


3 answers


I suspect the problem is what addForm.fadeOut

is called with a bad combination of arguments when passed to a function fadeIn

(and vice versa).

A classic example of this trap looks like this:

["0", "1", "2", "3"].map(function(i) {return parseInt(i);})

      

This works as expected and yields [1,2,3,4]

. You might expect that you can shorten this as you did above and write

["0", "1", "2", "3"].map(parseInt);

      



Unfortunately this is up to [0, NaN, NaN, NaN]

. The problem is that it .map

calls any function if it contains three arguments: a value, an index and the array itself, and parseInt

takes up to two arguments: a value, but also a radix / base to parse (e.g. radix 2 to parse a string like binary). What actually happens:

[
    parseInt("0", 0), //0, radix is ignored
    parseInt("1", 1), //NaN, what is base 1?
    parseInt("2", 2), //NaN, 2 isn't valid binary
    parseInt("3", 3)  //NaN, 3 isn't valid ternary/base-3
]

      

I suspect from the error message that the same is happening here. The "arity" of a function is the number of arguments passed to it, so the error message says that 4 arguments were supplied when only one was expected.

In general, with functions that take optional arguments, you need to be careful before passing them to other functions directly, otherwise you won't be able to control which arguments it will be called with.

+1


source


This is because calling a function as a property of an object is a special syntax to call a function with an object as a context.

When you call a function like this:

obj.func();

      

then this

will be a reference to obj

inside the function.

If you get a link to a function, then call it:



var f = obj.func;
f();

      

this this

will be a reference to the global context, i.e. object window

.

By using editForm.fadeIn(addForm.fadeOut);

, you will get a link to addForm.fadeOut

and submit the method fadeIn

. It is no longer associated with an object, so it will be called with the global context instead of the object as context.

You can use a method proxy

to bind a function to an object so that it will be called with the correct context:

var showEditForm = function() {
  editForm.fadeIn($.proxy(addForm.fadeOut, addForm));
};
var showAddForm = function() {
  editForm.fadeOut($.proxy(addForm.fadeIn, addForm));
};

      

+8


source


Fiddle: http://jsfiddle.net/jmj8tLfm/

addForm.fadeIn

and addForm.fadeOut

is called without specifying the context this

that is usually passed in the call addForm.fadeIn()

. Try it .bind()

- appropriately use this variable like this:

var showEditForm = function() {
    editForm.fadeIn(addForm.fadeOut.bind(addForm));
};
var showAddForm = function() {
    editForm.fadeOut(addForm.fadeIn.bind(addForm));
};

      

+2


source







All Articles