简体   繁体   中英

Javascript new effect on prototype

I'm trying to bind a javascript object to an event listener and this is how I'm going about it: (this is a simplified example, but it uses the pattern I'm interested in)

function foo(x){
    this.x = x;
}

foo.prototype = {
    'bar': function(){
       // do something with this.x
    },
    'events': function(){
        $(document).on('custom_event', function(event, x){
            var G = new foo(x);
            G.bar();
        });
    }
};

(function(){
    var G = new foo();
    G.events();
})();

So after the self-invoking anonymous function is run, every time custom_event is fired the bar method of my foo object will be called.

Questions:

When new foo(x) is called from within the event handler of my foo object, does it cause a duplication of the event listener?

It is my understanding that prototype methods belonging to an object are only created once and that calling new foo() only effects, in my case, this.x . If I am correct, I'm confused why it's necessary to use new from within the event listener in foo 's events method in order to use the prototype methods attached to foo .

What am I missing?

It seems you're mainly confused about the usage and effects of the new operator. I quote from You Don't Know JS, this & object prototypes :

When a function is invoked with new in front of it, otherwise known as a constructor call, the following things are done automatically:

  1. a brand new object is created (aka, constructed) out of thin air
  2. the newly constructed object is [[Prototype]] -linked
  3. the newly constructed object is set as the this binding for that function call
  4. unless the function returns its own alternate object , the new -invoked function call will automatically return the newly constructed object.

Make sure you understand that well. On your questions:

When new foo(x) is called from within the event handler of my foo object, does it cause a duplication of the event listener?

No. What you do with new foo(x) is use the foo function as a constructor, so you're only creating a new, prototypally linked, object (similar to {} ) and then executing the code inside foo , with that new object as this . So that will result in an almost empty object, except for its property x . You're only setting up the event listener inside the events function!

It is my understanding that prototype methods belonging to an object are only created once and that calling new foo() only effects, in my case, this.x . If I am correct, I'm confused why it's necessary to use new from within the event listener in foo 's events method in order to use the prototype methods attached to foo .

They are defined once, on the object you refer to as "the prototype" (which is really just the prototype property on the function foo ), yes. And it's not necessary to use new here, all you're doing with that is creating a throwaway foo object inside a function of an already existing foo object.

What you'll likely want to do is not worry about setting this.x inside the constructor, but inside the event handler, before calling bar() :

something.on('custom_event', function(e, x) {
  this.x = x;
  this.bar();
});

The problem that you'll encounter here is that this in the context of the event handler will most likely be set/overridden by jQuery, and not point to the " foo object" you want to point to. To circumvent this problem, you need to either lexically capture the this at the moment of setting up the event handler (which is the events function):

events: function(){
    var self = this;
    $(document).on('custom_event', function(event, x){
        self.x = x;
        self.bar();
    });
}

or bind the this inside the callback handler to the " foo object" you want to reference:

events: function(){
    $(document).on('custom_event', (function(event, x){
        this.x = x;
        this.bar();
    }).bind(this));
}

See Function.prototype.bind on MDN for some explanation of what this does.


Further note: I'm not sure what your custom event really is, but you're listening on the entire $(document) inside every single event handler. If you have DOM elements corresponding to each foo object, you should instead set these event handlers up on these specific DOM elements.

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