Reputation: 413
I have a chat class with two methods: updateChat and sendChat.
//chat.js
var state;
var room;
function Chat (theRoom) {
this.update = updateChat;
this.send = sendChat;
this.room = theRoom;
}
function updateChat(){
alert('ROOM: '+this.room);
$.ajax({
type: "POST",
url: "/chat/process.php",
data: {
'function': 'update',
'state': state,
'room': this.room
},
dataType: "json",
success: function(data){
if(data.text){
for (var i = 0; i < data.text.length; i++) {
$('#chat-area').append($("<p>"+ data.text[i] +"</p>"));
}
}
if(data.state)
state = data.state;
}
});
}
}
//send the message
function sendChat(message, nickname)
{
alert('A'+state); //20
//XXX
updateChat();
alert('B'+state); //20
$.ajax({
type: "POST",
url: "/live-event/chat/process.php",
data: {
'function': 'send',
'message': message,
'nickname': nickname,
'room': this.room
},
dataType: "json",
success: function(data){
alert('C'+state); //wrong!: 2 //it should be 20!
//XXX
updateChat();
alert('D'+state); //21
},
});
}
The constructor of the chat object:
var chat = new Chat(4); //4 = the number of the chat room
chat.send('test', 'tester');
My problem are the method calls at the locations marked with XXX. In the updateChat() method, this.room is undefined if I call the updateChat methods like that. But I need to pass the room number to get the right state (state is simply the number of lines in the chat room's text file).
I think it's a problem with variable scope or with the methods not being called in the context of the object.
Upvotes: 0
Views: 130
Reputation: 116654
You may find this easier to grasp if you forget about classes. What you've written there is not a class. There are no classes in JavaScript. You've written a constructor function, but it's of somewhat dubious value because you're assigning the members individually for every instance. The main purpose of constructor functions is to take advantage of prototype-inheritance, so you'd assign the "methods" to the constructor function's prototype.
function Chat (theRoom) {
this.room = theRoom;
}
Chat.prototype.send = sendChat;
Chat.prototype.update = updateChat;
That way, each object created with new Chat(r)
will only need to store the room number, and will not need to store the two methods as properties.
Alternatively, just write a createChatRoom
function:
var createChatRoom = function(room) {
return {
update: function() {
alert('updating: ' + room);
// ... other stuff
},
sending: function() {
alert('sending: ' + room);
// ... other stuff
}
};
};
The beauty of that is probably obvious: you don't need to prefix anything with this
. The room
parameter is in scope to the method definitions, and is also truly private (cannot be modified except through calls to the methods. And the caller doesn't have to remember to put new
. They just call the function and get back a fresh object with two methods in it.
You can even safely do this:
setTimeout(chatRoom.update, 10);
The update
function "knows" what object it is associated with. It never needs to be told which this
to use.
This is so convenient and useful, unless I'm expecting to create very large quantities of objects, I don't bother with constructor functions, new
, prototype
, etc.
Upvotes: 0
Reputation: 630359
You need to maintain this
when calling those methods, so instead of this:
updateChat();
You can use .call()
to maintain context (so this
doesn't revert to window
inside the called function), like this:
updateChat.call(this);
Or call the method on the object as @casablanca points out below:
this.update();
There also one more issue, this
won't be what you want in your $.ajax()
callbacks, it'll be the ajax settings object by default, so you need to set the context
option to maintain it, like this:
$.ajax({
context: this,
type: "POST",
//...rest of your current options/methods
Upvotes: 2