I recently started programming JavaScript and thought everything would be good... Well today I faced a problem I can't solve on my own. My tutorial/ learning project has a class called model. In this class there are several private and one public variable. This variable is of type CustomEvent:
function Model(){
/**
* Array in which the questions are stored
*/
var questions=new Array();
var db;
var valuesSplit="*";
var tableName="quests";
this.myEvent=new CustomEvent("my event");
So as you can see "myEvent" is public and can be called from outside. In this case it is an event which can be subscribed (this is done outside this class by other objects that want to listen) and it can be fired (this is done in the same class). And this is my problem. How can I access myEvent within the model class?
I tried:
this.myEvent.fire()
and:
myEvent.fire()
But I always get "myEvent is not defined".
I recently started programming JavaScript and thought everything would be good... Well today I faced a problem I can't solve on my own. My tutorial/ learning project has a class called model. In this class there are several private and one public variable. This variable is of type CustomEvent:
function Model(){
/**
* Array in which the questions are stored
*/
var questions=new Array();
var db;
var valuesSplit="*";
var tableName="quests";
this.myEvent=new CustomEvent("my event");
So as you can see "myEvent" is public and can be called from outside. In this case it is an event which can be subscribed (this is done outside this class by other objects that want to listen) and it can be fired (this is done in the same class). And this is my problem. How can I access myEvent within the model class?
I tried:
this.myEvent.fire()
and:
myEvent.fire()
But I always get "myEvent is not defined".
Share Improve this question edited Feb 2, 2014 at 23:15 BenMorel 36.7k52 gold badges206 silver badges337 bronze badges asked Oct 17, 2011 at 11:33 battlepopebattlepope 3003 silver badges17 bronze badges 2- 1 where exactly are you writting this.myEvent.fire() or myEvent.fire()? please share that code, if you are writting it inside a function in the class this.myEvent.fire() should work... – Vishwanath Commented Oct 17, 2011 at 11:37
- Thanks for your reply! It tried it directly under the declaration and inside a public function of the class. Nothing worked for me – battlepope Commented Oct 17, 2011 at 11:39
3 Answers
Reset to default 7Probably the first thing to say is: JavaScript doesn't have classes. The sooner you stop thinking of "JavaScript classes," the better off you'll be. :-) JavaScript has OOP, but not the kind with classes. Your Model
function is called a constructor function.
You can access myEvent
from any code that has a reference to the object created by new Model
, which includes code in your constructor (via this
— e.g., the way you're setting it up) and any function called with this
referring to that object (or, of course, "externally" via someObjReference.myEvent
).
So probably this.myEvent.fire()
is what you want, but the code you're calling it from doesn't have the right this
value. That's because in JavaScript, this
is controlled entirely by how a function is called, not where the function is defined as it is in some other languages. See my blog articles Mythical methods and You must remember this
for more details, but I've done a somewhat truncated discussion below.
Here's an example of a fairly standard way to set up a constructor function with useful methods that all instances share:
function Foo() {
this.myEvent = new CustomEvent("my event");
}
Foo.prototype.bar = function() {
this.myEvent.fire();
};
// Usage:
var f = new Foo();
f.bar(); // Fires the event indirectly, via the code in `bar`
f.myEvent.fire(); // Fires it directly
Note that that only works if bar
is called with this
referring to an object with a myEvent
property. It's easy to call bar
with this
set to something else entirely:
document.getElementById("someID").onclick = f.bar;
When the click occurs, the bar
function gets called, but this
does not refer to an object created via Model
. (It will refer to the element with the id "someID" instead.) And so this line in bar
this.myEvent.fire();
...will fail.
If you're used to class-based languages, you can see how this is totally different from, say, Java, C#, or C++. In those langauges, this
inside bar
will always refer to an object created via new Model
. Not so JavaScript, which is both awkward and powerful.
This flexibility of functions (not being bound to any particular object) is one of the biggest things to get used to, and take advantage of, in JavaScript. The other is how functions are closures, which is powerful but not plicated.
So if this
is set by how a function is called, how do you do that? There are two ways:
Call the function by referencing it from an object property in the same expression as the call. That's an awkward way of saying do this:
var f = new Foo(); f.bar(); // <== The key bit f["bar"](); // <== Also works
The expression
f.bar()
does two things, which interact: The first thing it does is retrieve the propertybar
of the object referenced byf
, and get that property's value (which is a function reference). Then it calls that function (because of the()
). The way JavaScript works, because you did those two things in the same overall expression, the interpreter setsthis
tof
during the call tobar
for you. But note this key distinction:var f = new Foo(); var b = f.bar; b(); // <== Different!
Now when the
bar
function gets called,this
will not be set tof
(it'll be set to the global object, which iswindow
on browsers), because we've separated the property retrieval from the function call.Alternately, you can use the built-in features of JavaScript function objects, their
call
andapply
functions.call
andapply
do exactly the same thing, the only difference between them is how you supply the arguments for the function. Example:var f = new Foo(); f.bar(1, 2): // <== Calls `bar` with `this` === `f` and passing in // the arguments 1 and 2 var b = f.bar; b.call(f, 1, 2); // <== Does the same thing as f.bar(1, 2) var args = [1, 2]; b.apply(f, args); // <== Does the same thing as f.bar(1, 2)
E.g.,
call
andapply
allow you to set whatthis
should be explicitly when you call the function. The only difference between them is thatcall
accepts the arguments to give the function as further arguments tocall
, andapply
accepts them as an array.
If you want to use myEvent
in a non public function in your Model
than you have to create another reference to the myEvent
which isn't using the this
reference of your Model. Because the this
in another function is something else than in your Model
function. The easiest way to bypass this problem is if you define a new variable in your Model
:
var that = this;
Then you can call your myEvent
like:
that.myEvent
The myEvent
member should be visible both in the inner & outer scope of the object :
function Model(){
this.myEvent = 'some value';
this.canAccessEvent = function(){
return 'myEvent' in this;
}
}
var m = new Model();
// access from outside :
alert(m.myEvent);
// access from inside :
alert('Model can access the even? ' + m.canAccessEvent());
However, it is very possible that your new CustomEvent
function doesn't exist or does not return a valid object making your myEvent
variable to be undefined
. I suggest you attribute some other value to the myEvent
property and see if it is defined. If it is defined, then the problem lies in your CustomEvent
function.