0

I have the following Pet and cat inherits from Pet, as follows:

function Pet(){};

Pet.prototype.run = function takeoff(cb, sec) {
 setTimeout(function() {
   cb();
   console.log('Run');
 }, sec);
};
Pet.prototype.bark = function bark(cb, sec) {
 setTimeout(function() {
   cb();
   console.log('bark');
 }, sec);
};
Pet.prototype.comeback = function comeback(cb, sec) {
 setTimeout(function() {
   cb();
   console.log('Comeback');
 }, sec);
};

var cat = new Pet();
cat.prototype = Object.create(Pet);

cat.prototype.run = function(){
    var that = this;

    that.run = Pet.prototype.run.call(that);
    return that;
}

cat.prototype.bark = function(){
    this.bark = Pet.prototype.bark.call(this);
    return this;
}

cat.prototype.comeback = function(){
    this.comeback = Pet.prototype.comeback.call(this);
    return this;
}


console.log(cat);
cat.run().bark().return();

In this situation, the cat and Pet have the same function names. The only difference is return this is added to cat methods to make method chaining possible in cat but not Pet. However, note that I have to write the name of the function every time and set the same name to its parent's prototype. Is it possible to generalize this so that any method I specify for Pet will be duplicated in cat but yet I don't have to specify the method for cat every time?

guest
  • 2,185
  • 3
  • 23
  • 46
  • I wanted to tell you this in your previous question also, but that got deleted. This is not prototype chaining. You are creating an object and then changing its properties. This will not change function but will give precedence to your current function – Rajesh Oct 17 '16 at 07:54
  • function Cat(){}; Cat.prototype = Object.create(Pet); This way cat has all the public methods of Pet. – Fida Oct 17 '16 at 07:56
  • @Rajesh yeah that's what I was trying to do but didn't communicate clearly. – guest Oct 17 '16 at 08:03
  • Hmm, isn't `cat` is an instance of `Pet`? How can you call prototype methods that don't exist...? – evolutionxbox Oct 17 '16 at 08:11

2 Answers2

1

You can add a property in child classes and based on this value, you can return this.

Sample

// Parent Class
function Pet() {
  this.sec = 1000
};

Pet.prototype.run = function takeoff(cb, sec) {
  setTimeout(function() {
    //cb();
    console.log('Run');
  }, sec || this.sec);
  if (this.animalName) return this;
};
Pet.prototype.bark = function bark(cb, sec) {
  setTimeout(function() {
    //cb();
    console.log('bark');
  }, sec || this.sec);
  if (this.animalName) return this;
};
Pet.prototype.comeback = function comeback(cb, sec) {
  setTimeout(function() {
    //cb();
    console.log('Comeback');
  }, sec || this.sec);
  if (this.animalName) return this;
};

// Child class
var Cat = function() {
  this.animalName = 'Cat'
}

// Linking of classes
Cat.prototype = new Pet();

// object of child class
var cat = new Cat();
cat.run().bark().comeback()

var pet = new Pet();
try {
  // Chaining not allowed.
  pet.run().bark().comeback()
} catch (ex) {
  console.log(ex.message)
}
Community
  • 1
  • 1
Rajesh
  • 24,354
  • 5
  • 48
  • 79
  • thanks for your help. how would you modify `cat` methods without modfying `Pet` methods? Also, because of the `setTimeout`, it seems that it is not in order. Let's say if `sec` in `comeback = 100`, and `sec` in `run = 500`, it will print `Come back` before `Run` – guest Oct 17 '16 at 08:33
  • If you wish to override, just add that method in child class prototype. Also, setTimeout will register an event at specific tick. Thats it. processing of functions at same tick is take care of by compiler and you cannot force it. You can either get rid of setTimeouts or keep a counter to add delay – Rajesh Oct 17 '16 at 08:36
  • OK, I tried to override the child prototype class, as edited above: `index.html:101 Uncaught TypeError: Cannot read property 'bark' of undefined` – guest Oct 17 '16 at 09:02
  • Because you are not returning anything. – Rajesh Oct 17 '16 at 09:15
  • I thought `return that` serves that purpose? how would you fix it for it to return `this` object? – guest Oct 17 '16 at 09:23
  • Can you share a sample JSFiddle where I can debug your code? – Rajesh Oct 17 '16 at 09:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/125890/discussion-between-guest-and-rajesh). – guest Oct 17 '16 at 09:31
1

After a discussion with guest I came up with a solution that extends each function to use a promise. The code will be executed in order and the object will be chained.

function Pet(){};

Pet.prototype.run = function run(callback) {
 setTimeout(function() {
   callback()
   console.log('Run');
 }, 1000);
};
Pet.prototype.bark = function bark(callback) {
 setTimeout(function() {
   callback()
   console.log('Bark');
 }, 500);
};
Pet.prototype.comeBack = function comeBack(callback) {
 setTimeout(function() {
   callback()
   console.log('Comeback');
 }, 750);
};

// DON'T MODIFY ANYTHING ABOVE HERE

// START ADD YOUR CODE HERE

function createChainableFunction(fun) {
      var that = this;
      return function() {
          if(!that.promise) {
            that.promise = new Promise(function(resolve, reject) {
              fun.call(that, resolve);
            });
          }
          else {
            that.promise.then(function() {
                that.promise = new Promise(function(resolve) {
                  fun.call(that, resolve);
                });
            });
          }


          return this;
      }
}

function isFunction(functionToCheck) {
   var getType = {};
   return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}

function createChainable(object) {
   var chainable = {
   'promise': null
   };
   chainable.prototype = Object.getPrototypeOf(object);
   for(var prop in object) {
      if(isFunction(object[prop])) {
         chainable[prop] = createChainableFunction.call(chainable.prototype, object[prop], prop);
      }
   }

   return chainable;
}

var cat = createChainable(new Pet());

cat.run().bark().comeBack();
TOAOGG
  • 392
  • 1
  • 10