简体   繁体   中英

Call the method of a method if it exists

First I should point out that I'm new at both JS and node.js. I'm trying to write a node.js chat bot, currently working at commands.

My problem is with calling a method of a method .. if that's even possible. This is the relevant part :

    var text; // received message from user
    var userId; // Id of the user, number.
    if (cmd.hasOwnProperty(text.split(' ')[0])) { // Message will be a string, it should be ignore if the first word is not a command name.
        console.log("[Inc]" + userId + ": " + text)
        if (text.split(' ').length === 1) { // If the command name is not followed by any arguments then the only argument passed should be the userID(used to send replies to the user).
            cmd[text.split(' ')[0]](userId)
        } else {
            var args = [] // Placing all args in  an array because the commands will take different number of arguments, a calculator command for example could take a lot of args.
            for (var i = 1; i < text.split(' ').length; i++) {
                args.push(text.split(' ')[i])
            }
            console.log(args)
            cmd[text.split(' ')[0]](userId, args)
        }   
    } else {
        console.log("Command not found, try again");    
    }
    var cmd = {
        help : function () {
            cookies : function () { // 
                console.log('Cookies recipe')
            }
            if (arguments.length === 1) {
            console.log('General help text');
            } else if (help.hasOwnProperty(arguments[1])) { 
                this[arguments[0]](); // Seems my problem was here, this was creating the reference error.
            } else {
                console.log('Requested topic not found')
            }   
        },
        invite : function(id) { 
            send_PRIVGRP_INVITE(id)
        }   

    }

Any ideas how I could make this work, or is there some better way, cleaner way to do this. Also I should mention I chose to use commands as objects and methods because some commands will be more complex and I was planing to giving them their on file.js and exporting it to the main.js file and it would be a lot easier to add commands w/o editing the main file all the time.

Keep in mind I'm quite new at this, a detailed explanation would go a long way, thank you.

I think the code below gives the behavior you're looking for, but it's pretty antipattern. It's sort of object oriented looking , but it's really not, since it's defining the cookies function this same way inside each call of the containing function. You probably want cookies to live on cmd , but that's not what your question asks.

I think you eventually are going to inch into doing some real object oriented stuff, where you'll have a constructor set up all the properties for your functions within functions . That is, you'll want to leave JSON notation and run this as "real code" inside of an object constructor returning instances of cmd that you might initialize in different ways (maybe with JSON notation!).

If this isn't what you wanted, drop a comment, and I'll revise. Again, I wouldn't actually use this code in production. Antipattern.

var cmd = {
    help: function () {
        var context = this.help;
        context.cookies = function () {
            console.log('Cookies recipe');
        };

        if (arguments.length === 0) {
            console.log('General help text');
        } else if (context.hasOwnProperty(arguments[0])) {
            context[arguments[0]]();
        } else {
            console.log('Requested topic not found');
        }
    },

    invite: function(id) {
        //send_PRIVGRP_INVITE(id);
        console.log("send_PRIVGRP_INVITE(" + id + ");");
    }
};

cmd.help();
cmd.help("cookies");
cmd.help("milk");
cmd.invite("wack");
cmd.help("invite");

That will produce this output:

General help text
Cookies recipe
Requested topic not found
send_PRIVGRP_INVITE(wack);
Requested topic not found

EDIT: There's some good information on how to use this here:

The quick take-home is that this refers to the function's execution context , as the SO answer quotes ...

The ECMAScript Standard defines this as a keyword that "evaluates to the value of the ThisBinding of the current execution context" (§11.1.1).

So if you don't have something attached to an object, window (or whatever your global context is; in a browser, it's window ) is this . Unless you use strict mode... But otherwise this is the calling object. foo.bar() should have foo in this when bar is called, for instance.

You can use the functions call and apply to explicitly set the context that's in this when calling a function. But that's all explained in detail at those links.

One OO solution

For how to use OO, I'd probably do something like...

function Cmd(helpInfo, executableFunctions) {
    var functionName;

    // Note that we're no longer redefining the cookies function
    // with every call of cmd.help, for instance.
    this.help = function (helpTopic) {
        if (undefined === helpTopic) {
            console.log('General help text');
        } else if (helpInfo.hasOwnProperty(helpTopic)) {
            console.log(helpInfo[helpTopic]);
        } else {
            console.log('Requested topic not found');
        }
    };

    for (functionName in executableFunctions)
    {
        if (executableFunctions.hasOwnProperty(functionName))
        {
            this[functionName] = executableFunctions[functionName];
        }
    }
}

// Set up initialization info for your new command object.
var helpInfoCooking = {
    cookies: "Cookies recipe",
    brownies: "Brownies recipe",
    cake: "Cake receipe"
};

var executableFunctions = {
    invite: function(id) {
        //send_PRIVGRP_INVITE(id);
        console.log("send_PRIVGRP_INVITE(" + id + ");");
    },
    say: function(message) {
        console.log("you'd probably say \"" + message + "\" somehow");
    }
};

// Create an instance of Cmd.
var cmd = new Cmd(helpInfoCooking, executableFunctions);

cmd.help();
cmd.help("cookies");
cmd.help("milk");
cmd.help("cake");
cmd.invite("wack");
cmd.help("invite");

cmd.say("This is a message");

Results:

General help text
Cookies recipe
Requested topic not found
Cake receipe
send_PRIVGRP_INVITE(wack);
Requested topic not found
you'd probably say "This is a message" somehow

YMMV, etc. Maybe overkill if you're doing a singleton setup, but it wouldn't be that hard to rearrange into a real singleton setup either.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM