I'm having some problems with a specific part of a JavaScript program I'm making. I need to have a a system where a user can input a key word, and the function dealing with the input will call another function to deal with the rest of the input. (So if the user inputs "pick up stick" the "interpret" function will find the word "pick", call the "pick" function which will deal with picking things up). I have gotten stuck at one stage (after getting the input system to work and the interpret function to recognise the key word.) where I can't get the interpret function to call the function from inside the object literal. I've tried using indexes (like "inputFunctions.[1]") which doesn't work and also using surrogate variables.
Really stuck here, please help me!
The relevant section of my code is below (in a little bit of a state but hey-ho)
var interpretFunctions = {
pick: function(){},
"look": function(){
textlineUpdate("You are looking");
},
equip: function(){},
inventory: function(){},
attack: function(){},
fight: function(){},
run: function(){},
use: function(){},
interpret: function(mostRecentInput){ /* Is called when the user provides an input, finds whether the user input is a valid command */
var mostRecentInput_low = mostRecentInput.toLowerCase();
var commands = ["pick", "look", "equip", "inventory", "attack", "fight", "run", "use"];
console.log(mostRecentInput_low);
var splitInput = mostRecentInput_low.split(" ");
console.log(splitInput);
for (var command=0; command<commands.length; command++){ /*finds out if the first word is a valid command */
console.log(splitInput[0]);
if(splitInput[0]===commands[command]){ /* Tries to call the relevant function if a valid command is found */
console.log(">>>"+commands[command]);
var correctInput = commands[command];
interpretFunctions.correctInput();
}
}
}
};
Thanks! ~pip
EDIT: apologies for the lack of comments! I am a bit lazy and havent put any anywhere in my program but they're in this bit now :)
JS allows to call functions by name, so no fancy lookup needed, just call them (if you don't need to handle errors)
dirty: use eval() //try to avoid that
another possibility: don't use an array to store your functions, use a lookup ie. dictionary dict['pick'] would return function pick()... where an invalid one should give null or exception that has to be caught, havent tested..
Edit: Jeol's solution (below) is way simpler than mine. Use that (told ya I was rusty). Maybe also add a check to see if it's actually a function.
Disclaimer: I'm really rusty when it comes to coding and the approach that I've taken is super naive (I'm assuming that the input will always just be 3 words like "look at door", "pick up dog" etc. which is a terrible idea). This is just to show you one possible way of calling functions dynamically. I guarantee that this is probably not the optimal way:
var interpretFunctions = {
pick: function (direction, object) {
// do proper handling here - maybe add item to inventory or something.
console.log("You picked", direction, "the", object);
},
look: function (direction, object) {
// do proper handling here - maybe trigger some other event or whatever.
console.log("You looked", direction, "the", object);
},
// ...
// other functions here...
// ...
interpret: function (mostRecentInput){
var splitInput = mostRecentInput.toLowerCase().split(" ");
var command = splitInput.splice(0,1)[0];
// Object.keys saves you having to manually update your array of commands.
// You may not want to do this - I don't know.
var commands = Object.keys(interpretFunctions);
if (commands.indexOf(command) !== -1) {
// pass the rest of the input to the appropriate function.
return interpretFunctions[command].apply(null, splitInput);
}
// handle invalid input here
console.log("Cannot", mostRecentInput, "- try something else.");
}
};
// test valid input
interpretFunctions.interpret("pick up stick");
interpretFunctions.interpret("look at floor");
// test invalid input
interpretFunctions.interpret("squeeze rubber duck");
Just store the commands in an object with keys. Then you can just check to see if it's undefined.
var commands={}
commands["log"]=function(str){console.log("[log] " + str)}
commands["log"]("apples")
> [log] apples
commands["log"]==undefined
> false
commands["undefinedkey"]==undefined
> true
e.g.
var commands = {"pick": function(inputArr){console.log(inputArr.join(" "))}}
var cmd = splitInput[0]
splitInput.shift()
if (commands[cmd] == undefined) console.log("Error! command not found")
else commands[cmd](splitInput) // sends rest of command split up
Thanks for all your help guys! I eventually managed to solve my problem by actually reading the documentation here. Before I had only skimmed it and didn't realise that accessing objects inside an object-literal using the index [] involved merely putting the name of the object-literal and the square brackets directly afterwards. I had thought it was perhaps interpretFunctions.[1] (for example).
Whoops!
Well at least it works now and I can continue with the project!
Yeah the mozilla documentation is usually pretty good at explaining stuff, if you take the time to read it :-)
Maybe you already know all this, but if you want to know more about the complexities of JS then I'd strongly recommend reading You Don't Know JS (it's a free online book). Happy coding!