2

I'm trying to create 2 objects that share the same way of implementing:

function Human(hand,leg,head,body,foot1,foot2){

  this.hand = hand;
  this.leg = leg;
  this.head = head;
  this.body = body;
  this.feet = [foot1,foot2];
}


function Robot(hand,leg,head,body,foot1,foot2){

  this.hand = hand;
  this.leg = leg;
  this.head = head;
  this.body = body;
  this.feet = [foot1,foot2];
}

And I want them to have different prototypes:

Human.prototype.scream = function(){ 
    alert("HUMANNN"); 
    //some other functions 
};

Robot.prototype.scream = function(){ 
     console.log("ROBOOBOT"); 
    //some other functions 
};

var Tom = new Robot(1,2,3,4,5,6);
Tom.scream();

var I = new Human(312314123,2141123,213131412,4121312,132124,12313);
I.scream();

Is there a better way to create the functions Human and Robot so that I don't have to write it twice?

I tried

function Robot(hand,leg,head,body,foot1,foot2){

 Human(hand,leg,head,body,foot1,foot2);

}

var Micky = new Robot(1,2,3,4,5,6);
Micky.scream();

But it didn't work.

5 Answers5

1

I tried

function Robot(hand,leg,head,body,foot1,foot2){
    Human(hand,leg,head,body,foot1,foot2);
}

That does call Human as a function, not as a constructor - not on an instance, but with the global object as the this value. You would need to use .call:

function Robot(hand,leg,head,body,foot1,foot2) {
    Human.call(this, hand,leg,head,body,foot1,foot2);
}

or, if you don't want to write them out you can use the arguments object and apply:

function Robot() {
    Human.apply(this, arguments);
}

However, instead of calling one constructor from the other I would recommend to put the common code into a generic constructor and call that from both Human and Robot, so that you can put specific instance-initialisation code in their constructors as well:

function Humanoid (hand, leg, head, body, foot1, foot2) {
    this.hand = hand;
    this.leg = leg;
    this.head = head;
    this.body = body;
    this.feet = [foot1, foot2]
}
function Human() {
    Humanoid.apply(this, arguments);
    …
}
// if you want Humans to inherit Humanoid prototype properties:
// Human.prototype = Object.create(Humanoid.prototype);
Human.prototype.… = …;

function Robot() {
    Humanoid.apply(this, arguments);
    …
}
// if you want Robots to inherit Humanoid prototype properties:
// Robot.prototype = Object.create(Humanoid.prototype);
Robot.prototype.… = …;

A way to create the functions Human and Robot so that I don't have to write it twice?

If you are sure that the constructor code is always exactly the same you also might use a closure:

function getConstructor() {
    return function Human(hand,leg,head,body,foot1,foot2) {
        this.hand = hand;
        this.leg = leg;
        this.head = head;
        this.body = body;
        this.feet = [foot1,foot2];
    }
}
var Human = getConstructor();
Human.prototype.… = …;
var Robot = getConstructor();
Robot.prototype.… = …;
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

You could create a mixin function that adds properties to the constructor and call it with the proper context. You could also use an object instead of so many arguments:

function mixin(props) {
  for (var prop in props) {
    this[prop] = props[prop];
  }
}

function Human(props) {
  mixin.call(this, props);
}

function Robot(props) {
  mixin.call(this, props);
}

Human.prototype.scream = function() {
  console.log('Human has '+ this.legs.length +' legs'); 
};

Robot.prototype.scream = function() { 
  console.log('Robot has '+ this.legs.length +' legs'); 
};

var human = new Human({
  head: 1,
  body: 1,
  hand: 1,
  legs: [1,2],
  feet: [1,2]
});

var robot = new Robot({
  head: 1,
  body: 1,
  hand: 1,
  legs: [1,2,3],
  feet: [1,2,3]
});
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Not the right term? Dunno, call it what you want, concept still applies. It adds the properties of an object to a function constructor. – elclanrs Nov 07 '13 at 09:03
  • Mixins hold concrete functionality, that can be added to objects or its prototypes by extending them with the mixin. – Zoltan.Tamasi Nov 07 '13 at 09:09
0

What you need is apply or call

// with call
function Robot(hand,leg,head,body,foot1,foot2){
  Human.call(this, hand, leg, head, body, foot1, foot2);
}

var you = new Robot(1,2,3,4,5,6);
you.scream();

// with apply
function Robot(hand,leg,head,body,foot1,foot2){
  Human.apply(this, arguments);
}

var you = new Robot(1,2,3,4,5,6);
you.scream();

With apply you basically pass all the arguments in same order you got from the original function.

ZER0
  • 24,846
  • 5
  • 51
  • 54
0

Why don't you create a common prototype both for Human and for Robot and only override the scream function:

function HumanRobotProt(hand,leg,head,body,foot1,foot2){

  this.hand = hand;
  this.leg = leg;
  this.head = head;
  this.body = body;
  this.feet = [foot1,foot2];
}

Human.prtotype = new HumanRobotProt;
Robot.prototype = new HumanRobotProt;

function Human(hand,leg,head,body,foot1,foot2){
    Human.call(this, hand,leg,head,body,foot1,foot2);
    this.scream = function(){ 
    alert("HUMANNN"); 
}

function Robot(hand,leg,head,body,foot1,foot2){
    Robot.call(this, hand,leg,head,body,foot1,foot2);
    this.scream = function(){ 
    alert("ROBOOOT"); 
}
Alex Art.
  • 8,711
  • 3
  • 29
  • 47
  • 1
    [Don't use `new` to set up the prototype chain](http://stackoverflow.com/questions/12592913/what-is-the-reason-to-use-the-new-keyword-here)! Btw, your constructors are recursing infinitely (until a stack overflow) – Bergi Nov 07 '13 at 09:03
0

A better OOP approach

// From "Pro Javascript Design Patterns" by Ross Harmes and Dustin Diaz
function extend(subClass,superClass) {
    var F = function() {};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;

    subClass.superClass = superClass.prototype;
    if(superClass.prototype.constructor == Object.prototype.constructor) {
        superClass.prototype.constructor = superClass;
    }
}

function Humanoid(hand,leg,head,body,foot1,foot2){
    this.hand = hand;
    this.leg = leg;
    this.head = head;
    this.body = body;
    this.feet = [foot1,foot2];
}
function Robot() {
    Robot.superClass.constructor.apply(this,arguments);
}
extend(Robot,Humanoid);

function Human() {
    Human.superClass.constructor.apply(this,arguments);
}
extend(Human,Humanoid);

var John = new Human(2,2,1,1,1,1);
console.log(John);
Luca Rainone
  • 16,138
  • 2
  • 38
  • 52