Call function by string

Discussion in 'Server and Client Scripting' started by Garma, Jul 3, 2013.

  1. Garma

    Garma Member

    Joined:
    Nov 23, 2011
    Messages:
    80
    Likes Received:
    0
    Is there a way to call a function by string parameter? Let's say I have an array of object names:

    Code (javascript):
    1. loaded_plugins = new Array('Tournament', 'Hangman', 'Battlezone', 'Trivia');
    The plugin names are the object names. Tournament.beforeChatMessage is a function and it works if I call it manually. But when I do something like this:

    Code (javascript):
    1.     this.executeEvents = function(event_name) {
    2.         for (var i in this.loaded_plugins) {
    3.             if (typeof loaded_plugins[i][event_name]() == 'function') {
    4.                 eval(loaded_plugins[i][event_name]());
    5.             }
    6.         }
    7.     }
    nothing is executed as loaded_plugins[event_name] is always undefined. As you can call properties and functions of an object in javascript by index Tournament['beforeChatMessage'] should be called. So any ideas?
     
  2. ArchZombie

    ArchZombie Member

    Joined:
    Aug 1, 2012
    Messages:
    65
    Likes Received:
    0
    PO Trainer Name:
    ArchZombie0x

    BLARGH. DONT DO THIS.
    I'm not even going to tell you what you did wrong.. because it'd still be wrong! You don't need to be compiling code on the fly, your code should not include a jit compiler! It's extremely error prone, causes bugs, and suffering. Here it might not cause any issues, but it's a very bad habit and results in 75% + of script security vulnerabilities.

    Instead do something like this:

    Code (javascript):
    1. this.plugins = new Object;
    2. this.plugins["tournament"] = sys.exec("tournament.js"); //if you don't have sys.exec you can use sys.import or eval(sys.getFileContent("tournament.js")
    3. this.nilfunc = function () {};
    4. for (var x in this.plugins) (this.plugins[x][event_name] || this.nilfunc)();
     
  3. TheUnknownOne

    TheUnknownOne Member

    Joined:
    Mar 28, 2011
    Messages:
    988
    Likes Received:
    3
    You should access them as variables. Every global variable is in the 'this' keyword (global scope), assuming there is no other scope taking priority.

    For example, like so:

    Code (javascript):
    1.  
    2. // You should put this before the ({ }) block.
    3.  
    4.  
    5. var loadedPlugins = ["Tournament", "Hangman", "etc"];
    6. var global = this; // This makes it possible to access the global scope everywhere (assuming this is run in the global scope)
    7.  
    8.  
    9. function executeEvents(eventName) {
    10.     var len = loadedPlugins.length,
    11.         plugin,
    12.         i;
    13.    
    14.     for (i = 0; i < len; i += 1) {
    15.         plugin = global[loadedPlugins[i]];
    16.        
    17.         if (plugin[eventName]) {
    18.             plugin[eventName]();
    19.         }
    20.     }
    21. }
    22.  
     
  4. coyotte508

    coyotte508 Well-Known Member Administrator Server Owner Administrator Server Owner

    Joined:
    Apr 21, 2010
    Messages:
    6,363
    Likes Received:
    168
    I think your error is that you used loaded_plugins instead of this.loaded_plugins.
     
  5. ArchZombie

    ArchZombie Member

    Joined:
    Aug 1, 2012
    Messages:
    65
    Likes Received:
    0
    PO Trainer Name:
    ArchZombie0x
    No, the actual error is that's he's trying to 1. call a property of a string and 2. eval the result? What he was trying to do was some kind of silly JS code generation. But this is a bad way to code anyway and I strongly don't recommend it.

    I recommend NEVER using the global scope. It's a bad habit and using it like that errors in JavaScript strict mode (not to be confused with sys.enableStrict, which is changes the way some sys functions work) Try using another object.
     
    Last edited: Jul 4, 2013
  6. TheUnknownOne

    TheUnknownOne Member

    Joined:
    Mar 28, 2011
    Messages:
    988
    Likes Received:
    3
    That's your personal choice and opinion. Putting everything into native and pseudo native (sys, script) objects isn't exactly a good habit either.

    QtScript does not have strict mode, and probably never will. It's also completely optional:

    »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
    (01:48:05) ~Client~: You evaluated the following code:
    (function () { 'use strict'; var a = 013; return a;}());
    »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
    (01:48:06) ~Client~: 11
    (01:48:06) ~Client~: Code took 0 milliseconds / 0 seconds to run.

    Strict mode isn't the best thing either, and tends to break things in certain environments.

    Again, that's up to personal preference. If someone wants to use the global scope, so be it. It's there for a reason.
     
  7. ArchZombie

    ArchZombie Member

    Joined:
    Aug 1, 2012
    Messages:
    65
    Likes Received:
    0
    PO Trainer Name:
    ArchZombie0x
    Putting everything into script is actually a good habit. If it's part of your script, shouldn't it be part of the script object? Modifying sys is always a bad idea. It's a preference until it breaks things or causes memory leaks. Then it's a preference that breaks things and causes memory leaks. I'm not going to demand anyone code like that, but I strongly recommend it.
     
    Last edited: Jul 4, 2013
  8. coyotte508

    coyotte508 Well-Known Member Administrator Server Owner Administrator Server Owner

    Joined:
    Apr 21, 2010
    Messages:
    6,363
    Likes Received:
    168
    Oh right, Garma, sorry. Try this:

    Code (javascript):
    1.     this.executeEvents = function(event_name) {
    2.         for (var i in this.loaded_plugins) {
    3.             if (typeof this.loaded_plugins[i][event_name] == 'function') {
    4.                 this.loaded_plugins[i][event_name]();
    5.             }
    6.         }
    7.     }
    You don't need the eval. If you have the name for the function, you can just do containingobject[nameofthefunction](function arguments). I'm not sure about the typeof call, but that's it.
     
  9. ArchZombie

    ArchZombie Member

    Joined:
    Aug 1, 2012
    Messages:
    65
    Likes Received:
    0
    PO Trainer Name:
    ArchZombie0x
    The problem is he's got the /names/ of global properties instead of a property of an object. So you'd probably need eval to read them.

    aka, he has to do
    Code (text):
    1. eval (loadedplugins[i] + "[eventname]()");
    BUT that's bad scripting!

    Instead he should make loaded plugins an array of the actual plugin objects (instead of their names) then you wont need eval or global object hacks.
     
  10. Lamperi

    Lamperi I see what you did there

    Joined:
    Apr 25, 2010
    Messages:
    2,647
    Likes Received:
    11
    Don't use Math or Date either - they are global too :<