-1

I have the following situation, in which I extend a parent class and override behavior. However the overridden behavior is not called.

// parent scope definition
(function ($) {

 $.extend(true, window, {
  Demo: {
    Parent: Parent
  }
 });

 function Parent() {
  function A() {
    //do something
  }
  function B() {
    //do something else
    A();
  }
  // public api
  $.extend(this,{ "A":A, "B":B });
  }
})(jQuery);

// child scope definition
(function ($,parent) {

 $.extend(true, window, {
  Demo: {
    Child: Child
  }
 });

 function Child() {
  // inherit all from parent
  parent.apply(child,arguments);
  this.A = function () {
    // override parent behavior
  }
  this.B();
 }
})(jQuery,Parent);

//...somewhere else, in another scope call: var kid = new Child();
<html>
  <script>
    var kid = new Child();
  </script>
</html>

When creating a new Child object, B will be called, with "this" pointing to the Child context. However, the context of A will not the Child, but the global (window) context. The overridden behavior for A will not be called either.

I have to use the module pattern (no prototypical inheritance) and also override "superclass" behavior.

Could someone please let me know how I can "preserve" the context, in order to make sure the overridden behavior is called.

Thank you in advance, Andrei

edit #1: I must use modules (and hopefully do as little change to the "Parent" as possible when overriding behavior)

edit #2: For more clarity, thanks to the answers provided below, I must use the "revealing module pattern" for the Parent module/object and extend/override its behavior in Child.

edit #3: It seems the question title and problem are different and may be misleading: the handled and answered problems which are the real core issue are regarding javascript overriding in the context of the (revealing) module patter (as indicated in one of the answers). The scope change (which does occur) has been mistakenly considered as the real problem. I am removing its mention form the title. The correction is done so that others may benefit from answers below. There is a scope change, but that is probably normal in the present code design and in my calling scenario. Disregard this aspect (context) in this question.

acostache
  • 2,177
  • 7
  • 23
  • 48
  • What is `child`? What is `self`? What is `Parent` (it's not in scope)? – Bergi Jun 20 '14 at 11:54
  • 2
    Do you want to create modules (standalone objects) or classess (constructor functions)? If the former, then what does "superclass" mean? If the latter, why are `Parent` and `Child` [IEFEs](http://benalman.com/news/2010/11/immediately-invoked-function-expression/)? Or where are they invoked? – Bergi Jun 20 '14 at 11:57
  • @Bergi Editted; self should be this, sorry. I would like to create modules. – acostache Jun 20 '14 at 12:09
  • `var kid = new Child();` is *not* a module, it's a constructor? And why don't you want to use prototypical inheritance? – Bergi Jun 20 '14 at 12:37
  • I am constrained to using modules; at least I "cannot" use prototypical inheritance for "Parent". The "Parent" must stay a module. – acostache Jun 20 '14 at 12:43
  • why the downvote? would the downvoter care to explain if possible what is not correct regarding the question? – acostache Jun 23 '14 at 19:57
  • (btw, the question has been rephrased to disregard the context aspect: the main problem being discussed begin inheritance here) – acostache Jun 24 '14 at 06:18

3 Answers3

1

I've rewritten your code as follows, not sure if this is what you are looking for:

// No need of IEFE
function Parent() {
  this.A=function A () {
    console.log("Executing A");
  }
  this.B= function B () {
    console.log("Executing B");
    this.A();
  }

};

//again, no need of IEFE, just declaring    
function Child() {
  // inherit all from parent
  Parent.apply(this);
  this.A = function () {
    console.log("Executing the new A");
  }
  this.B();
};

var c=new Child();
console.log("Done");

And the console shows:

Executing B
Executing the new A
Done 
Pablo Lozano
  • 10,122
  • 2
  • 38
  • 59
  • Thank you for the answer. At least in the Parent, I must use the `$.extend`. And if possible, not make A and B [privileged members](http://javascript.crockford.com/private.html) of the Parent module. – acostache Jun 20 '14 at 12:36
  • @acostache: In the code you presented in the question, they *are* privilged members? – Bergi Jun 20 '14 at 12:40
  • @Bergi No, not in the sense of using `this`, like Crockford states. I do not want to use `this`, but use the "revealing module pattern" – acostache Jun 20 '14 at 12:42
  • 1
    @acostache: What "sense of using `this`"? Don't believe Crockford. Being privileged is a quality of functions that are *declared inside the constructor function*, where they can access the constructor's local variables, and that are then being "exported" (e.g. by assigning them to a property of `this`, or using `$.extend` to do that). Your functions `A` and `B` are that. – Bergi Jun 20 '14 at 12:45
  • @Bergi Ok, my bad, I did not get that part. Thanks for the clarification. Then, I just do not want to use `this` in Parent. – acostache Jun 20 '14 at 12:47
  • @acostache: What else do you want to do? Return a plain object literal, i.e. [a factory function](http://stackoverflow.com/questions/8698726/constructor-function-vs-factory-functions)? Would you like to use `this` (and `new`) for `Child`? – Bergi Jun 20 '14 at 12:50
  • @Bergi: I am ok with any, regarding the usage of a new Child instance (let's say I would like to use `new`). My problem is the overriding of Parent's behavior in Child. – acostache Jun 20 '14 at 12:56
  • @acostache actually, you are using `this` as parameter in the `$.extend` call... and that call will just add the privileged members of the source object as privileged ones in the target one – Pablo Lozano Jun 20 '14 at 13:05
  • @Pablo ok, but what about overriding the behavior? – acostache Jun 20 '14 at 13:19
  • @acostache Child overrides the method A, when B is called, it calls A and in the output you can see the behavior of the "new A" – Pablo Lozano Jun 21 '14 at 13:43
1

When you are defining your module

  $.extend(this,{ "A":A, "B":B });

you are implicitly using the Revealing Module Pattern by defining A and B in the closure, using direct closure references to "public" members, and then passing the object literal to $.extend. The Revealing Module Pattern is an anti-pattern variant of the basic module pattern because this variant is unable to pick up overrides. If you want to pick up overrides, the general rule of thumb is to use this as much as possible.

Rewriting your example to use this where appropriate, the following should do the trick:

(function Parent() {
  function A() {
    //do something
  }
  function B() {
    //use this!
    this.A();
  }
  // public api
  $.extend(this,{ "A":A, "B":B });
})();

(function Child() {
  // inherit all from parent
  Parent.apply(child,arguments);
  this.A = function () {
    // override parent behavior
  }
  this.B();
})();
Community
  • 1
  • 1
I-Lin Kuo
  • 3,220
  • 2
  • 18
  • 25
  • Is it possible to achieve the same using the same "design" (revealing module pattern), but without the privileged members (without `this`)? – acostache Jun 20 '14 at 12:40
  • @acostache, AFAIK, there is no easy way to avoid using `this`. You can try to pass in the calling context in a different way from `this` but it's ad hoc and ugly. The correct thing to avoid is Revealing Module Pattern, not `this`. – I-Lin Kuo Jun 20 '14 at 13:09
  • Hmm, is there any "nice" (not necessarily), structured way then to extend something built using the revealing module pattern, in order to override behavior? (apart from our discussion using `this`) – acostache Jun 20 '14 at 13:22
  • To paraphrase Dante -- Abandon all hope of extension, ye who enter the Revealing Module Pattern. – I-Lin Kuo Jun 20 '14 at 15:25
  • Due to the useful discussion and advice, i am marking this as the correct answer. – acostache Nov 23 '14 at 17:01
  • I just gave a talk at NationJS two weeks ago (http://nationjs.com/schedule/index?schedule=yes#i-lin_kuo) "The Revealing Module is an Anti-Pattern. The slides are at http://slides.com/i-linkuo/the-revealing-module-is-an-anti-pattern#/ – I-Lin Kuo Nov 23 '14 at 17:50
0

You could use the bind function

var foo = function () {
// override parent behavior
}
this.A = foo.bind(child);

In the above code bind will return a new function object based on foo with this set to child

  • Where do I do this? because if I do it in my Child module ("constructor" type function), `this` and `child` should be the same, and my scoping problem will not be solved :(. – acostache Jun 20 '14 at 12:34