简体   繁体   中英

What is the best way to retrieve an object in an event callback in JavaScript

Usually I use objects in JavaScript to save data, but event listeners do not allow auxiliary pointers to retrieve these objects.

What is the best way to retrieve an object pointer in an event callback? (Without 3rd party libraries please)

Example:

function MyClass()
{
    this.number = Math.random();
    this.button = document.createElement('div');
    this.button.appendChild(document.createTextNode('Show number'));
    document.body.appendChild(this.button);
    // THIS FOLLOWING LINE REQUIRE CHANGES
    this.button.addEventListener('click', MyClass.prototype.listener);

}
MyClass.prototype.listener = function (e)
{
    // HERE, "THIS" DO NOT POINT TO MY OBJECT
    alert( this.number );
}
testMyClass1 = new MyClass();
testMyClass2 = new MyClass();

Currently, I use a static array to save pointers, but that is hard to maintain:

//New constructor, first try    
function MyClass()
{
    this.number = Math.random();
    this.button = document.createElement('div');
    this.button.appendChild(document.createTextNode('Show number'));
    document.body.appendChild(this.button);
    if (undefined===MyClass.prototype.register) MyClass.prototype.register = [];
    this.id = MyClass.prototype.register.length;
    MyClass.prototype.register.push(this);
    this.callback = new Function( 'e', 
        'var self = MyClass.prototype.register[' + this.id + '];'+
        'MyClass.prototype.listener.call(self, e);'
    );
    this.button.addEventListener('click', this.callback);
}

NOTES:

  • I do not want to define class functions inside the constructor to avoid duplicating the function for every object, that takes a lot of memory. My solution still saves a small function anyway.

If using ES5:

this.button.addEventListener('click', MyClass.prototype.listener.bind(this));

If not using ES5, get a shim for Function.bind .

Note that this does actually create a new function object as the handler for each instance of your class, but there's no easy way to avoid that.

You can use Function.bind to set the context of an event handler

function MyClass()
{
    this.number = Math.random();
    this.button = document.createElement('div');
    this.button.appendChild(document.createTextNode('Show number'));
    document.body.appendChild(this.button);
    // THIS FOLLOWING LINE WAS CHANGED
    this.button.addEventListener('click', MyClass.prototype.listener.bind(this));

}
MyClass.prototype.listener = function (e)
{
    // HERE, "THIS" DO NOT POINT TO MY OBJECT
    alert( this.number );
}
testMyClass1 = new MyClass();
testMyClass2 = new MyClass();

A very simple and elegant way is to make your object implement the EventListener interface.

To do this, your object simply needs to have a handleEvent() method.

MyClass.prototype.handleEvent = function(event) {
     switch (event.type) {
     case "click":
          return this.listener(event);
     default:
          throw "No handler for " + event.type
     }
}

Then you just pass the object itself.

//                                      v--pass the object instead of a function
this.button.addEventListener('click', this);

So this in handleEvent is the expected object, so you can just call your object methods.

You can simply use a function to create a wrapper that takes fewer parameters. In other words,

Change:

this.button.addEventListener('click', MyClass.prototype.listener);

To:

var self = this;
this.button.addEventListener('click', function() { self.listener(); });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM