Why couldn't I add the mousemove event after the mousedown in the prototype?

I would move my legacy js codes to a more OOP style. Here is 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 couldnt 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";
});

      

Everything is good. It looks like 2 codes are doing the same thing. Why is there a difference? Thank!


change

After fighting for 2 nights, I finally solved the problem. Thanks johnvey for your understanding.

Ero occurs on the this keyword . In the case of an object, this refers to the window and not to the object itself. The solution is to define the global parameter me (me = this) at the beginning. Now everything is all right.

0


source to share


1 answer


This is a classic Javascript sticking point, dealing with how the "this" key resides 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 be printed:

Red printer returned: blue

      

since the scope 'this' is in the line:

return this.X

      

is actually attached to the main () object at the time of the call.

Generally, there are two ways to solve this problem:



1) Avoid using the 'this' keyword within a function closure. To fix your code this way, I simply collected all the event bindings in one place, rather than cascading them, thereby 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 currying function to bind the scope during definition. I removed 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";
    }
}

      

An important change here:

this.displaymove.bind(this)

      

which basically says, "When you call displaymove (), override the 'this' keyword in the context of the original context scope instead of the current Event object.

+2


source







All Articles