views:

667

answers:

1

I would move my former js codes to more OOP style. Here's the code.

function addEvent( obj, type, fn ) {
  if ( obj.attachEvent ) {
    obj['e'+type+fn] = fn;
    obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
    obj.attachEvent( 'on'+type, obj[type+fn] );
  } else
    obj.addEventListener( type, fn, false );
}

function test() {

}

test.prototype = {
    init: function () {

     addEvent(document, 'mousedown', this.displaydown);

    },

    displaydown : function(e){
     document.getElementById('mydiv').innerHTML = "down";
     addEvent(document, 'mousemove', this.displaymove);
    },

    displaymove : function(e){
     document.getElementById('mydiv').innerHTML = "move";
    }
}

var test0 = new test();

test0.init()

I could not add mousemove event after mousedown with

addEvent(document, 'mousemove', this.displaymove);

But if I write inline style like

addEvent(document, 'mousemove', function(e){
   document.getElementById('mydiv').innerHTML = "move";
});

It's OK. It looks the 2 codes do the same thing. Why is there the difference? Thanks!


edit,

After struggle for 2 nights I finally solved the problem. Thanks johnvey for your enlighting.

The erro occurs on this keyword. In the event of an object, this refers to window rather than object itself. The solution is I defined global parameter me (me = this) at the beginning. Now it's OK.

+2  A: 

This is a classic Javascript stumbling block, relating to how the "this" key is scoped within a closure. To illustrate:

redPrinter = function() {
    this.X = 'red';
    return function() {
        return this.X;
    }
}

main = function() {
    this.X = 'blue';
    var myRedPrinter = new redPrinter();
    alert("Red printer returned: " + myRedPrinter());
}

main();

This code will print out:

Red printer returned: blue

because the scope of 'this' in the line:

return this.X

is actually tied to the main() object at the time of invocation.

There are generally 2 ways to address this:

1) Avoid using the 'this' keyword within a function closure. To fix your code this way, I would simply collect all of the event bindings in one place instead of cascading them, thus removing the 'this' references from both 'displaydown()' and 'displaymove()':

test.prototype = {
    init: function () {
        addEvent(document, 'mousedown', this.displaydown);
        addEvent(document, 'mousemove', this.displaymove);
    },

    displaydown : function(e){
        document.getElementById('mydiv').innerHTML = "down";
    },

    displaymove : function(e){
        document.getElementById('mydiv').innerHTML = "move";
    }
}

OR

2) Use function currying to bind the scope at definition time. I've lifted the bind() method from the Prototype library to illustrate:

// declare the global bind() method for all functions
Function.prototype.bind = function(obj) {
    var method = this,
    temp = function() {
        return method.apply(obj, arguments);
    };
    return temp;
} 

test.prototype = {
    init: function () {
        addEvent(document, 'mousedown', this.displaydown);
    },

    displaydown : function(e){
        document.getElementById('mydiv').innerHTML = "down";

        // note that we bind the method object here
        addEvent(document, 'mousemove', this.displaymove.bind(this));
    },

    displaymove : function(e){
        document.getElementById('mydiv').innerHTML = "move";
    }
}

The important change here is:

this.displaymove.bind(this)

which basically says, "when you call displaymove(), re-scope the keyword 'this' to the original scope context instead of the current Event object.

johnvey
Hi, johnveyThanks! I think I need to do as the 2nd method. But I could not bind(). An error comes up at this step. I'm using IE.6. Is this the reason?
unigogo
IE6 shouldn't be the problem. What is the error that you're getting? As a larger question, what is it that you're trying to do? Calling addEvent() from inside another event handler is not good because you'll end up attaching the same handler over and over.
johnvey
johnvey,I finally found the error on your code.addEvent(document, 'mousedown', this.displaydown); should be also binded. or this in the scope of mousedown is window. I just worked on a slider for easy loading.http://www.pagecolumn.com/webparts/sliders.htm
unigogo