2

My intend:

  • With an object o with a method work
  • Print "Hello" before o.work()
  • Print "Bye" after o.work()
  • o.work() will be called by a 3rd party

My attempt:

// sample library object
var o = {
     score: 5,
     work: function() {
                     console.log(this.score);
                }
};

// my code
var cons = function () {
     this.score = 10;
     this.work = function () {
          console. log("Hello");
           // how to call parent's work() ?
           // if I do this.prototype.work() -> prints 5
           // But parent's work should be called when this.score is 10
          console. log("Bye");
     };
 };
 cons.prototype = o;
 my_o = new cons();

 // my_o will be passed to 3rd party instead of o

In short:

  • I am attempting to decorate inherited method.
  • Its easy with super but JavaScript doesn't have super.

They say prototypal inheritance is supirior.

Update:

  • work() uses this.score, which is overridden after inheritance.

Update 2:

  • Expectation is o.work() should print 5
  • Expectation is my_o.work() should print 10
Yugal Jindle
  • 44,057
  • 43
  • 129
  • 197
  • NB: if you write `this.work = function ...` you are _not_ using prototypical inheritance, you've added that method _directly_ to the current _instance_ of `cons`. – Alnitak Dec 24 '13 at 08:28
  • I am updating the question. – Yugal Jindle Dec 24 '13 at 08:57
  • o.work() would do just fine. Usually you would not have instance specific values for Parent and Child on prototype, if so needed it's better the Child holds an instance of Parent. More on constructor functions and prototype can be found here: http://stackoverflow.com/a/16063711/1641941 – HMR Dec 24 '13 at 14:16

5 Answers5

2

It's a bit ugly, but you can call cons.prototype.work;

var Cons = function () {
     this.work = function () {
         alert('Hello');
         cons.prototype.work.call(this); // <= here
         alert('Bye');
     };
 };

Or more generic:

var Cons = function () {
     this.parentwork = arguments.callee.prototype.work;
     this.work = function () {
         alert('Hello');
         this.parentwork.call(this);
         alert('Bye');
     };
};

See this jsFiddle

KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • Updated the question - Please check ! – Yugal Jindle Dec 24 '13 at 09:01
  • You mis-read the update. The point being parent has a different value for `score` and child has a different value. The new value of score is what is defined by the child. – Yugal Jindle Dec 24 '13 at 09:13
  • You answered it well. but your (not-required) alert code made it all confusing. – Yugal Jindle Dec 24 '13 at 09:19
  • See the updated jsFiddle. The alert replacement is for convenience – KooiInc Dec 24 '13 at 09:26
  • Great job, it worked. `alert` : Have it as a external lib to `jsfiddle` so that it doesn't gets in between. – Yugal Jindle Dec 24 '13 at 09:27
  • @YugalJindle I think score is an instance specific value. You do know that all Cons instances share one instance of o as their "parent"? When you have c1 and c2 and somehow change the o.score than it'll change for all both c1 and c2. If this is desired behaviour then no problem, not sure what score would represent but it may be better to set parentScore and consScore. Initialise the parentScore value by calling `Parent.call(this);` in Const (the Child). See this link for more info:http://stackoverflow.com/a/16063711/1641941 – HMR Dec 24 '13 at 14:36
0

You need to either know exactly who the parent you are trying to call is, and call it directly (passing the local this value using the .call method) or you need to use an OOP library that implements such abilities at the cost of requiring a rather convoluted code design.

Entoarox
  • 703
  • 4
  • 8
0

No, you would need to give the do function in the constructor and the do function in the prototype different names.

Instance members created inside a constructor will occlude properties of the same name defined in the prototype

Have a look at this pic from john resig book :

enter image description here

When we run the test by loading the page into the browser, we see that the test passes! This shows that instance members created inside a constructor will occlude properties of the same name defined in the prototype.

The precedence of the initialization operations is important and goes as follows:

  • 1 Properties are bound to the object instance from the prototype.
  • 2 Properties are added to the object instance within the constructor function.
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
0

replace the line

 // how to call parent's work() ?

with

cons.prototype.work();

as simple as that:)

WebServer
  • 1,316
  • 8
  • 12
0

Figured it out :

// sample library object
var o = {
     score: 5,
     work: function() {
                     console.log(this.score);
                }
};

// my code
var cons = function () {
     this.score = 10;
     this.parent = arguments.callee.prototype;
     this.work = function () {
          console. log("Hello");
           // this.prototype.work() // Doesn't work since 'this' is an object
           // objects don't contain a link to prototype.
           // ###### With direct reference to `cons` ###### //
           // cons.prototype.work(); // (No Context) -> prints 5
                    // OR
           cons.prototype.work.call(this); // (With 'this' context) -> prints 10
           // ###### Without direct reference to `cons` [ Preferred ] ###### //
           // this.parent.work(); // (No Context) -> prints 5
                    // OR
           this.parent.work.call(this); // (With 'this' context) -> prints 10
          console. log("Bye");
     };
 };
 cons.prototype = o;
 my_o = new cons();

 my_o.work();

Expectations Met:

  • o.work() prints 5
  • my_o.work() prints 10
Yugal Jindle
  • 44,057
  • 43
  • 129
  • 197