开发者

jquery bind/trigger in a prototypal inheritance scenario. Can't trigger events on the right object

I'm trying to wrap my head around using bind/trigger in an inheritance scenario. Here is what I got:

  var MyApp = {};

  MyApp.GrandParent = function (){
      var self = Object.create({}), $self = $(self);

      self.doFoo = function(){
          console.log('Just to asure we can call from child to grandpare开发者_StackOverflownt');
          $(this).trigger('Happened');
          //$self.trigger('Happened'); //Why doesn't it work this way
      };

      return self;
  }

  MyApp.Parent = function(){
      var self = Object.create(MyApp.GrandParent()), $self = $(self);

      self.doSomething = function(){
          console.log('Just to asure we can call from child to parent');
          $(this).trigger('SomethingHappened');
          //$self.trigger('SomethingHappened'); //Why doesn't it work this way
      };

      return self;
  }

  MyApp.Child = function(){
      var self = Object.create(MyApp.Parent()), $self = $(self);

      $self.bind('SomethingHappened', function(){
          console.log('Client logs: SomethingHappened');
      });

      $self.bind('Happened', function(){
          console.log('Client logs: Happened');
      });

      return self;        
  }

  var foo = new MyApp.Child();
  foo.doSomething();
  foo.doFoo();

Working Example: http://jsfiddle.net/cburgdorf/8fWta/12/

As you can see, we have an inheritance chain starting by the grandparent, over the parent to the child. It works. However, I just don't understand why I can't trigger the events on the $self object. It feels wrong to fire them on $(this).

What I want to archieve is to keep the prototype chain working and fire the events on the $self object. I guess I need to use something like $.proxy maybe but I really don't have a clue.

I know I could also do it like this http://jsfiddle.net/cburgdorf/8fWta/11/ but I would rather keep the prototype chain working...


Andy Edinborough is correct about var self != this.

It looks like you want to store a reference to the jQuery wrapper around your object instances, so I used the flyweight pattern (avoids creating a property on the object instance to store the jQuery wrapper). You can read more about this at James Padolsey's blog.

I also cleaned up your code:

(function(window) {

  var flyweight = $([1]);

  /*--------------------------------------------------------------------------*/

  function GrandParent() {
    /* empty constructor */
  }

  function Parent() {
    /* empty constructor */
  }

  function Child() {
    flyweight[0] = this;
    flyweight.bind('SomethingHappened', function(){
      console.log('Client logs: SomethingHappened');
    })
    .bind('Happened', function(){
      console.log('Client logs: Happened');
    });
  }

  /*--------------------------------------------------------------------------*/

  // setup inheritance
  Parent.prototype = Object.create(GrandParent.prototype, {
    'constructor': {
      'configurable': true,
      'writable': true,
      'value': Parent
     }
  });

  Child.prototype = Object.create(Parent.prototype, {
    'constructor': {
      'configurable': true,
      'writable': true,
      'value': Child
     }
  }); 

  // add methods
  GrandParent.prototype.doFoo = function(){
    flyweight[0] = this;
    flyweight.trigger('Happened');
  };

  Parent.prototype.doSomething = function(){
    flyweight[0] = this;
    flyweight.trigger('SomethingHappened');
  };

  /*--------------------------------------------------------------------------*/

  // expose
  window.MyApp = {
    'GrandParent': GrandParent,
    'Parent': Parent,
    'Child': Child
  };
}(this));

Usage check:

var foo = new MyApp.Child;
var bar = new MyApp.Child;

$(bar).bind('SomethingElse', function() {
  console.log('Client logs: SomethingElse');
});

foo.doFoo(); // Client logs: Happened
foo.doSomething(); // Client logs: SomethingHappened

$(bar).trigger('SomethingElse'); // Client logs: SomethingElse
$(foo).trigger('SomethingElse'); // Nothing happens \o/


I think the problem is in your Object.create() method: self !== this. It looks like self is being used as a prototype for the instance that is being created, and is not actually the same instance being returned.

It looks like this is what's happening in Child:

  1. MyApp.GrandParent() returns an instance of GrandParent--we'll call it a.
  2. The fields and functions of a are used to propogate a new instance of Parent--we'll call it b.
  3. The fields and functions of b are used to propogate a new instance of Child--c.

So the $self reference in MyApp.GrandParent.doFoo is actually a reference to a--the original object, and this is a reference to c--the current object. That's why $(this).trigger(...) works and $self.trigger(...) doesn't.

In this fiddle, http://jsfiddle.net/andyedinborough/s8hV7/1/, I wrote the Object.create(...) function to simply return the instance it was given, and $self.trigger(...) works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜