How to pass parameters in function calls by reference in JavaScript?

37

Recently I asked the question Why should we use anonymous functions with jQuery instead of the function directly? and along with the accepted answer came a second question: How to pass arguments to a JS function that we are invoking by reference? / p>

How would the call to $("a").on("click", retornaNada); be if this function were given simple parameters as a number or more complex as an object itself?

    
asked by anonymous 03.02.2014 / 18:03

7 answers

21

I was thinking about this situation that was added between the parameters of .on the possibility to pass arbitrary data to the function of handler . Any object passed as a parameter just before the handler will be available within it via event.data . Example:

function retornaNada(evento) {
    var data = evento.data;
    console.log(data.foo); // Imprime "bar"
}

$("a").on("click", { foo:"bar" }, retornaNada);

Several other jQuery methods accept this data parameter. In the case of "on", the general form (according to the documentation) is:

  

.on (events [ selector] [ data], handler (eventObject))

If this is not enough for you (eg you already have a function ready, and you want to use it without modification as the handler of the event), then you need to transform it by operation currying . There are several ways to do this:

  • currying "manual":

    $("a").on("click", function(e) { retornaNada(10); });
    
  • jQuery.proxy :

    $("a").on("click", jQuery.proxy(retornaNada, meuThis, 10));
    
  • Function that returns function:

    function tranforma(parametro) {
        return function(evento) {
            retornaNada(parametro);
        }
    }
    
    $("a").on("click", transforma(10));
    

    or more generic:

    function tranforma(fn, meuThis, parametro) {
        return function(evento) {
            fn.call(meuThis, parametro);
        }
    }
    
    $("a").on("click", transforma(retornaNada, meuThis, 10));
    

    or even more generic (arriving at a point that is almost identical to jQuery.proxy ):

    function tranforma(fn, meuThis) {
        var args = Array.prototype.slice.call(arguments, 2, arguments.length);
        return function(evento) {
            fn.apply(meuThis, args);
        }
    }
    
    $("a").on("click", transforma(retornaNada, meuThis, 10));
    
  • Update: on the use of this

    In both jQuery.proxy and my transforma (in more generic forms), a meuThis parameter is expected. This is because every JavaScript function invocation expects a binding for the this keyword, even when the function is not being called in the context of an object (ie it is not a method ). Example:

    console.log(this); // Vai imprimir o "objeto global" (no caso de um browser, "window")
    
    function a() {
        console.log(this);
    }
    a(); // também imprime o objeto global
    
    var obj = { x:a };
    obj.x(); // Vai imprimir "obj"
    
    obj.criaLinks = function() {
        $("a").on("click", jQuery.proxy(retornaNada, this, 10));
        // Como se fosse: obj.retornaNada(10)
    
        $("a").on("click", jQuery.proxy(retornaNada, window, 10));
        // Como se fosse: window.retornaNada(10)
    
        $("a").on("click", jQuery.proxy(retornaNada, { foo:"bar" }, 10));
        // Como se fosse: { foo:"bar" }.retornaNada(10)
    };
    obj.criaLinks();
    
        
    03.02.2014 / 18:11
    4

    There is no reference passing in JavaScript, but you can encapsulate this in an object (which is always passed by reference, since only the object's pointer is actually passed).

    Ex:

    function teste(argumento)
    {
        argumento.valor = 10;
    }
    
    var o = { valor = 11 };
    
    teste(o);
    o.valor == 10; // true
    

    Since there is only one object in memory, changes to it are global.

        
    03.02.2014 / 18:10
    4

    What you can use here is the jQuery.proxy () :

    $('div').on('click', $.proxy( minhaFuncao, this, 'minha variavel1', 'minha variavel2' ));
    
    function minhaFuncao(a, b) {
        console.log(a, b);
    }
    

    Example

    So you can pass parameters into the function, keeping the reference to the function.

    This method allows you to pass the referenced function, allows you to change the scope of this and allows you to pass more arguments into the function.

        
    03.02.2014 / 18:17
    2

    Your previous question answers this:

    $("a").on("click", function() { retornaNada(param); });
    
      

    I have a question, some jQuery methods expect a function like   parameter, but to function they must receive an inner function as   parameter instead of a function directly, as in the example below:

         

    $ ("a"). on ("click", function () {returnNot ();}); instead of

         

    $ ("a"). on ("click", returnsNo ());

        
    03.02.2014 / 18:13
    2

    The way you're doing, that's using a Closure (as I told you in the previous question) you are passing a reference from a function to the argument, which is expected.

    However, you can use parameters if you return a function in return of the function you called.

    For example:

    function retornaFunction(data){
      return function(){console.log("Data: "+data+" This: "+this)};
    }
    var data = 1;
    $('div').on("click", retornaFunction(data));
    

    See that you are passing the data parameter and you can also access the this context that refers to your element that you clicked on, which is often used in function assignments like the one you are proposing.

    In fact, there are other ways to do what you want, not by using the .on() function.

    Like for example:

    function retornaFunction(data){
          return function(){console.log("Data: "+data+" This: "+this)};
        }
        var data = 1;
    $('div').click(retornaFunction(data));
    

    This way you do not need to "click" as a parameter.

    You can also create an element and assign an event of Click to it in your creation, such as:

    function retornaFunction(data){
      return function(){console.log("Foo: "+data+this)};
    }
    data = 1;
    var $div = $('<div />', {
      "class": "suaclasse", //opcional apenas exemplo
      text: "texto qualquer"//opcional apenas exemplo
    }).click(retornaFunction(data)); //aqui você atribui o clique.
    
    $('body').append($div);//joga a div no body de seu documento
    
        
    03.02.2014 / 18:45
    2

    So I understand you want to pass parameters to the retornaNada function while passing it as the jQuery's on function parameter ...

    As far as I know, there is no way to do this within good practice, but you could create a function that takes another as a parameter and returns a new function with the actual call within the scope.

    Something like this:

    Function.prototype.getFunction = function (context) {
        var
            args = arguments,
            foo = this;
        return function () {
            foo.apply((context || window), Array.prototype.slice.call(args, 1));
        };
    };
    

    Then your call would look like this:

    $("a").on("click", retornaNada.getFunction(this, arg1, arg2));
    
        
    03.02.2014 / 18:21
    1

    You can pass several parameters via javascript using this example:

    function abreJanela(URL,URL2) {
    location.href = "#?pg=pecas&nome="+URL+"&ano_base="+URL2;  
      
      
      //este metoo manda parametros via GET
      alert("#?pg=pecas&nome="+URL+"&ano_base="+URL2+"");
    };
    <select    name="ano"  id="ano"   class="select" >	
    							<option     value="2014">2014</option>
    							<option     value="2015" selected>2015</option>
    							</select>
    Nome:<input   onchange="javascript: abreJanela(this.value, ano.value)"   type="text"  name="corrida"   >
    
    <br>
    
    Basta completar campo e clicar ENTER
        
    06.01.2015 / 13:48