Calling one function inside the other, through a string

Asked

Viewed 37,227 times

8

To facilitate the work of other programmers in the company whose default is no pattern, i created a Javascript library with some form field formatting and validation functions (date, phone, CPF, CNPJ, etc.).

At the end of the process, this library allowed me a very simple call:

<input type="[data|telefone|...]" name="" value="">

At the end of the page loading i Gero a Nodelist and assign the appropriate functions to each input in accordance with its type.

That code then went like this: Jsbin.com

The problem with the method used is that although only one of the functions is being executed for each input (as it should be), I’m setando ALL the functions for each object found in my Nodelist. That is, for each object I get a kilometric code, containing several functions that this object never will use.

In normal pages, where this feature is not widely used, the problem is totally inconspicuous. However, on pages where these functions are called numerous times, it is possible to notice a certain loss of performance after page loading.
And since the company’s system is to be used also on mobile devices, a small loss of performance may end up becoming a major problem.

To solve this, I thought of isolating each of the functions. Here’s my problem!
I have N functions (date, phone, Cpf, ...), within a global function (setEvents) and all I have to call these internal functions is their name in the form of string.

I’ve tried many ways, but failed to succeed.
The only way it’s worked so far is by using eval. But as the JS Bin: "Eval is evil."

  • What’s the idea behind [função a ser chamada]? that’s passed into a() or where it comes from?

  • @Sergio I determine which function will be called through a this.getAttribute("type") and call a different function for each result found.

4 answers

5


Just a hint, you can put the functions inside an object, and call it by name:

<script>
  function a() {
    var nomeDaFuncao = [função a ser chamada];

    var fncObj = {
        b: function(objeto) {
         . . .
        }

        c: function(objeto) {
         . . .
        }
    }

    fncObj[nomeDaFuncao](objeto);
  }
</script>

But it would be much better if you explain the reason for this strange logic... because even the way I said it, it sounds kind of strange to have something like this... would it be that a switch would not solve?

  • I am creating a library with formatting and field validation functions. In this case, to call the date function, for example, simply put <input type="data">. Now I want to improve the call to reduce the processing on the page load. So I thought I’d separate into specific functions. But I’m having this problem when it comes to calling each of the functions.

  • 1

    According to what I’ve been reading, a switch would be the fastest way. Anyway, there is no noticeable difference in the times, so the ideal would be to worry more about readability than about performance in this case.

  • The switch is my plan B. As I already have to make the declaration of the names of the functions in an event onload, I’m trying to do it again within the overall function. But, if there’s no way, that’s what I’m going to do. I just edited my post to better explain my problem. Maybe this will help in a solution. Thank you.

3

Hello, try to do like this:

function a(){
    alert('olá a');
    var nomeFuncao = 'b';
    var b = function(){
        alert('olá b');
    };

    var c = function(){
        alert('olá c');
    };

    eval(nomeFuncao)();
}

JS Bin

You can also use this alternative without eval():

func_a = function(arg1) {
    alert('call a '+ arg1);
};
func_b = function() {
    alert('b');
};
func_c = function() {
    alert('c');
};

var n = "a";

 window["func_" + n]('arg1');

JS Fiddle

Another option using Jquery:

$.main = {
    a : function(arg){
        alert('function a - arg: '+arg);
    },
    b : function(){
        alert('b');
    },
    c : function(){
        alert('c');
    },
    call : function(func,arg){
        $.main[func](arg);
    }
};
$.main.call('a','param 1');
$.main.call('b');
$.main.call('c');

With Jquery

  • Sorry, but I couldn’t quite understand your solution. You just turned the functions into variables and continued using the eval to call them. And it’s just the eval that I want to eliminate.

  • Okay, see an alternative without Val();

2

Can use a namespace for this. A multi-function object calling the function it needs and does not pollute the global space as in its original idea.

var validar = {

    date: function (value) {
        return [value, 'Função para data'];
    },
    text: function (value) {
        return [value, 'Função para texto'];
    },
    password: function (value) {
        return [value, 'Função para passwords'];
    }
}

And then you can wear it like this:

// "el" no exemplo é o elemento que quer analisar
var type = el.getAttribute("type");
var retornoFuncao = validar[type](el.value);

Example

I used the same code within each function but I imagine I wanted to adapt this part.

1

Try adding your functions explicitly to the object window as here:

window.dyna = function(param) {
    alert("dyna " + param);
}
window["dyna"]("oi");

Some browsers this is not even necessary and would work the way you did.

Edit 1

Testing here does not work in your example why functions b() and c() are not directly in the object window. Therefore they are not found in the scope of window

Since they are created in the scope of Function a(), and they will only exist within Function a(), and whether within a() you want to access b(), for example, you have to do something like this:

this["b"]();
// que é o mesmo que this.b();

Edit 2

To use the this, as I mentioned you have to do something similar to this, your problem is of scope, so you have to attach your function in an object that is accessible in the scope where you intend to call it, in case the this, as follows in the example code:

function a(nomeDaFuncao) {

  // anexa a function "b" ao objeto local this
  this.b  = function(param) {
      alert("b " + param);
  }

  // anexa a function "c" ao objeto local this
  this.c = function(param) {
      alert("c " + param);
  }

  // chama a function pelo nome no objeto local this
  this[nomeDaFuncao]("oi");
}

a(nomeDaFuncao);

Example here

To better understand how the scope of objects in the , recommend that link that is very good and that of MDN.

Note: I don’t know what your real problem is to need such a solution, but depending on what it is, there may be simpler and cleaner ways to do it, but this solution will work for your current question.

  • @Marty, if you read the question, you might see that this is exactly what he’s looking for, an alternative to calling a method by name (string), in the specific scope. If you understand a little bit of [tag:javascript] you know that eval, It’s also nothing "cool".

  • I already tried to use this[nomeDaFuncao](objeto); but it didn’t work either. According to the debugger "this[nameplacement] is not a Function"

  • @Júliopradera, see if my updated solution helps you in something.

  • @Márcio, I always saw everywhere that Eval(), was not created to execute dynamic scripts, through strings, Val for me and others colleagues is the worst of the ideas, while window[], is also not best, more is the "less worse" to my understanding, however you have every right to disagree. And detail, I do not cling to reputation.

  • @Fernando the two answers I mentioned do not use Val, they use another way, exactly because I do not like Val or access the window. And I didn’t put the link because of the rep, but the tag that I have some little pots. Anyway, good luck there using window ;)

  • @Fernando Your new solution works, but it’s her that I’m using and trying to change. : D / I thought this would be a simple problem, and so I ended up not explaining myself very well. I just edited the post to show you my real problem. I would be very grateful if you could read it. And thanks for the help.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.