简体   繁体   中英

call a javascript function from within another function

I am coding a chat program but i am stuck in this part.

var Controller=function conversation() {
this.createMessageNode=function(msg,sender,time,mid){
    var newMessage;
    if(sender==sessionStorage.getItem('userid')){
        newMessage="<div class='message-sent' id='"+mid+"'>"+msg+"<span class='time'>"+time+"</span></div>";
    }else{
        newMessage="<div class='message-recv' id='"+mid+"'>"+msg+"<span class='time'>"+time+"</span></div>";
    }
    sessionStorage.setItem('lastMessage',mid);
    $('.chat-messages').append(newMessage);
}

this.getMessages=function(){
    if(sessionStorage.getItem('lastMessage')==null){
        sessionStorage.setItem('lastMessage',0);
    }
    $.ajax({url:"getmessages.php",type:"POST",data:{last:sessionStorage.getItem('lastMessage'),cid:sessionStorage.getItem('conversationid')},success:function(result) {
        var messages=JSON.parse(result);
        for (var i = 0; i < messages.length; i++) {
            createMessageNode(messages[i].message,messages[i].sender,messages[i].time,messages[i].mid);
            var cont=document.getElementById('chat-messages');
            cont.scrollTop=cont.scrollHeight;
        };
    }});
}

}

now when i do this it shows an error

Uncaught ReferenceError: createMessageNode is not defined

now in the for loop "this" variable is referring to the ajax object. how can i call the createMessageNode function?

Your functions are bound to the this object. If it is a global object (top most parent scope) then you can reference the functions within this by this.yourfunction

You must study SCOPE properly to understand

http://www.w3schools.com/js/js_scope.asp

The issue is createMessageNode() is a method of the Controller object instance, so you need to refer to the instance when calling it. Without refering to the instance, the JavaScript engine is looking for the function in the current scope, then each higher scope all the way up to the global scope.

Typically you would use the this keyword to reference the instance, but in your case, the jQuery ajax call has changed the this context, so you can't directly use this .

A possible solution is, before the ajax call, store the this context:

var that = this;

Now, in the ajax success function:

that.createMessageNode(messages[i].message,messages[i].sender,messages[i].time,messages[i].mid);
^^ refer to the instance

It'd probably be better to write your code following better prototypical inheritance models, like so:

function Controller() {
    this.chatMessages = $('.chat-messages');
}

Controller.prototype.createMessageNode = function (msg, sender, time, mid) {
    var newMessage;
    if (sender == sessionStorage.getItem('userid')) {
        newMessage = "<div class='message-sent' id='" + mid + "'>" + msg + "<span class='time'>" + time + "</span></div>";
    } else {
        newMessage = "<div class='message-recv' id='" + mid + "'>" + msg + "<span class='time'>" + time + "</span></div>";
    }
    sessionStorage.setItem('lastMessage', mid);
    this.chatMessages.append(newMessage);
};

Controller.prototype.getMessages = function () {
    var _this = this;

    if (sessionStorage.getItem('lastMessage') === null) {
        sessionStorage.setItem('lastMessage', 0);
    }

    $.ajax({
        url: "getmessages.php",
        type: "POST",
        data: {
            last: sessionStorage.getItem('lastMessage'),
            cid: sessionStorage.getItem('conversationid')
        },
        success: function (result) {
            var messages = JSON.parse(result);
            for (var i = 0; i < messages.length; i++) {
                _this.createMessageNode(messages[i].message, messages[i].sender, messages[i].time, messages[i].mid);
            }
            var cont = $('#chat-messages');
            cont.scrollTop(cont.scrollHeight);
        }
    });
};

This solves the issue of the context by creating a true class, for example:

var conversation = new Controller();
conversation.getMessages();
conversation.createMessageNode('Hello, World!', 'JimmyBoh', new Date(), 8268124);

Also, whenever you have nested functions, it can help to store the desired context in a local variable, such as _this or that , etc. Here is a more simple example:

function outer() {
    // Temporarily store your desired context.
    var _this = this;

    // Make any call that executes with a different context.
    $.ajax({
        url: "getmessages.php",
        type: "GET",
        success: function inner(result) {
            _this.doSomething(result);
        }
    });
};

Lastly, there might be a time when you want to execute a method in a different context than the current. .call() and .apply() can be used to run a method with a specified context and arguments. For example:

function printThis() {
    console.log(this.toString());
    console.dir(arguments);
}

printThis.call('Hello, World!');
printThis.call('Call array:', [2, 4, 6, 8], 10);   // Keeps arguments as-is.
printThis.apply('Apply array:', [2, 4, 6, 8], 10); // Accepts an array of the arguments.


function Sum(startingValue) {
    this.value = startingValue || 0;
}

Sum.prototype.add = function (number) {
    this.value += number;
}

var realSum = new Sum(2);
var fakeSum = {
    value: 3
};

realSum.add(1);
Sum.prototype.add.call(fakeSum, 2);

console.log(fakeSum.value); // Prints '5'
console.log(realSum.value); // Prints '3'

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