How to understand the javascript class model?

J

Jing You

hi every one,

I have got some confused problem when I try to write some custom object
by javascript.

Look at the example code here:

<BODY>
<script language="jscript">

function Class()
{

this.member = null;
this.event = null;

this.memberFunction = function()
{
alert("memberfunc" + this.member);
this.callEvent();
alert('after call');
}

this.callEvent = function()
{
alert("call:" + this.event);
if (this.event)
{
this.event();
}
}

}

var obj = new Class();
obj.member = "hello";

obj.event = function()
{
alert('event');
}

obj.memberFunction();
</script>

<button id=hello >click</button>
<script>
hello.onclick=obj.memberFunction;
</script>

I try to define a javascript class and define a event handler for it.
There is a member and
a memberFunction and a event in the Class body. Then I created a object
(obj) of Class and
defined a event handler like this:

obj.event = function()
{
alert('event');
}

When I call the function: obj.memberFunction(); the event handler was
fired and alert
a message ('event'). But when I try to use a button to fire the event, it
doesn't work. It seems we
have lost the member function callEvent, it is a undefined value, the same
as this.event member.

Anyone can tell me why?
 
M

Michael Winter

<script language="jscript">

The language attribute has long-been deprecated in favour of the
(required) type attribute:

function Class()
{

this.member = null;
this.event = null;

this.memberFunction = function()
{
alert("memberfunc" + this.member);
this.callEvent();
alert('after call');
}

this.callEvent = function()
{
alert("call:" + this.event);
if (this.event)
{
this.event();
}
}

}

In general, when all data members 'public', methods should be added via
the prototype object. This produces only one function object for each
method. With the code above, each new object will create new functions
even though they could be shared.

function Class() {
this.member = null;
this.event = null;
}
Class.prototype.memberFunction = function() {
alert('memberFunction: ' + this.member);
this.callEvent();
alert('after call');
};
Class.prototype.callEvent = function() {
alert('callEvent: ' + this.event);
if('function' == typeof this.event) {this.event();}
};

Creating methods as you did should normally be used when utilising
'private' members:

function MyObject() {
var private = 'value';

this.method = function() {
alert(private);
};
}

var o = new MyObject();

o.method(); // 'value'
o.private; // error

[snip]
<button id=hello >click</button>
<script>
hello.onclick=obj.memberFunction;
</script>

The value of id and name attributes should never be used as global
variables. Many browsers do not support this.

var element;

if(document.getElementById) {
element = document.getElementById('hello');
}
if(element) {
element.onclick = obj.memberFunction;
}
I try to define a javascript class [...]

There's no such thing. Javascript uses a prototype-based inheritance
model, where your objects use other objects as a basis for their
features and behaviours. Your Class, above, is a constructor function
that when executed, can be used to initialise an object instance and
augment the object that results from the instantiation.
When I call the function: obj.memberFunction(); the event handler was
fired and alert a message ('event'). But when I try to use a button
to fire the event, it doesn't work.

The this operator exists everywhere (unlike in other languages), and as
such, its value is determined by how code is executed.

In 'global' scope

<script type="text/javascript">
alert(this == window); // true
</script>

the this operator refers to the global object (usually referred to as
window). Similarly, functions that are called directly have the same value:

var o = {
method : function() {alert(this == window);}
},
f = o.method;

f(); // true; this refers to global object
o.method(); // false; same function object,
// but this now refers to 'o'

Notice that in this latter case, the this operator refers to the object
before the last dot operator: 'o'. A similar thing happens in your case.
When the browser fires the event listener, it does so as though it did

buttonElement.onclick()

In other words, the this operator refers to the BUTTON element.

To solve this, you need to keep a reference to the object that you can
use later. One way is to use the 'private' member form I showed earlier:

function Class() {
var instance = this;

this.member = null;
this.event = null;

this.memberFunction = function() {
alert('memberFunction: ' + instance.member);
instance.callEvent();
alert('after call');
};
}
Class.prototype.callEvent = function() {
alert('callEvent: ' + this.event);
if('function' == typeof this.event) {this.event();}
};

Looking at the implementation of the memberFunction member, you can see
that it's defined in terms of the instance private variable. Even when
the this operator will refer to the BUTTON element, instance will still
refer to the object. When the method calls the callEvent method, it does
so through the object reference, so the this operator will refer to the
object again.

Hope that helps,
Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top