How to understand the javascript class model?

Discussion in 'Javascript' started by Jing You, Aug 25, 2005.

  1. Jing You

    Jing You Guest

    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?
     
    Jing You, Aug 25, 2005
    #1
    1. Advertising

  2. On 25/08/2005 03:15, Jing You wrote:

    > <script language="jscript">


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

    <script type="text/javascript">

    > 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

    --
    Michael Winter
    Prefix subject with [News] before replying by e-mail.
     
    Michael Winter, Aug 25, 2005
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. E11
    Replies:
    1
    Views:
    4,791
    Thomas Weidenfeller
    Oct 12, 2005
  2. Replies:
    1
    Views:
    489
    Andreas Wollschlaeger
    Oct 6, 2006
  3. Martin P. Hellwig
    Replies:
    1
    Views:
    377
    Martin P. Hellwig
    Mar 26, 2010
  4. Sam Kong
    Replies:
    1
    Views:
    71
    Martin Coxall
    Oct 13, 2006
  5. Ruby Rabbit
    Replies:
    4
    Views:
    124
    Ruby Rabbit
    Jan 7, 2009
Loading...

Share This Page