20

Greetings,

After reading the following article I have a question: https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript

In the inheritance example, the Person constructor doesn't take any parameters. How would this same example look if I were to add one and call it from the Student constructor?

Thanks!

4 Answers 4

38

Well, a way that you can re-use the logic of the Person constructor is invoking it with call or apply, for example:

function Person(gender) {
  this.gender = gender;
}

function Student(gender) {
  Person.apply(this, arguments);
}
Student.prototype = new Person(); // make Student inherit from a Person object
Student.prototype.constructor = Student; // fix constructor property

var foo = new Student('male');
foo.gender;             // "male"
foo instanceof Student; // true
foo instanceof Person;  // true

If you want to prevent the execution of the Person constructor when is called without arguments (like in the line: Student.prototype = new Person();), you can detect it, e.g.:

function Person(gender) {
  if (arguments.length == 0) return; // don't do anything
  this.gender = gender;
}
Sign up to request clarification or add additional context in comments.

2 Comments

@CMS For the second portion if (arguments.length == 0) return;, is there a way to handle constructors where the arguments are NOT required? In that situation, am I forced to call the constructor?
I've tried a lot of different methods (Object.create, Person.prototype, temp functions...) but all of them fail or have bugs (undefined properties, obscured ones, etc.). Thanks for this answer, finally one that really works!
11

Accepted answer seems to be incorrect. Based on what Mozilla says about OO JavaScript, correct way to do it is:

var Person = function(firstName) {
    this.firstName = firstName;
};

function Student(firstName, subject) {
  // Call the parent constructor, making sure (using Function#call)
  // that "this" is set correctly during the call
  Person.call(this, firstName);

  // Initialize our Student-specific properties
  this.subject = subject;
};

// Create a Student.prototype object that inherits from Person.prototype.
// Note: A common error here is to use "new Person()" to create the
// Student.prototype. That's incorrect for several reasons, not least 
// that we don't have anything to give Person for the "firstName" 
// argument. The correct place to call Person is above, where we call 
// it from Student.
Student.prototype = Object.create(Person.prototype); // See note below

// Set the "constructor" property to refer to Student
Student.prototype.constructor = Student;

// Example usage:
var student1 = new Student("Janet", "Applied Physics");

As you can clearly see, Mozilla specifies that it is a common error to use "new Person()" to create the Student.prototype. Hence accepted answer is misleading.

I have actually tested this in my ongoing project and Mozilla's way is correct, while above answer does not work.

Comments

0
// define the Person Class
function Person(name) {
    this.personname = name;
}

Person.prototype.walk = function(){};
Person.prototype.sayHello = function(){
  alert (this.personname );
};

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor


The full code:

<script>
// define the Person Class
function Person(name) {
    this.personname = name;
}

Person.prototype.walk = function(){};
Person.prototype.sayHello = function(){
  alert (this.personname );
};

// define the Student class
function Student() {}

// inherit Person
Student.prototype = new Person("test");

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student and my name is \'' + this.personname + '\'' );
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.sayGoodBye();
</script>

1 Comment

I think this works fine if you always want "test" as the person name, but this is not what I mean when I ask to call it from the Student constructor.
0

By all other comments I created an example which works for me. Since I did not use prototype explicitly I hope I am not missing an important point.

// variable for tracking instantiations and checking the uniqueness of the objects
var instances = 0;

var Generic = function() {
    this.instanceId = ++instances;
    this.toString = function() {return 'Generic [iid='+ this.instanceId +']'};
    console.log('constructor-invoke: Generic ('+ this.instanceId +')');
};

var SpecificName = function(inName) {
    Generic.call(this);
    this.getName = function() { return inName; };       
    var superToString = this.toString.bind(this); // binds the inner function 'this' to this SpecificName instance
    this.toString = function() {
        return 'SpecificName [iid='+ this.instanceId +', name='+ this.getName() +', super.toString='+ superToString() +']'
    }
    console.log('constructor-invoke: SpecificName ('+ this.instanceId +')');
};

var SpecificNames = function(inFirstName, inLastName) {
    SpecificName.call(this, inLastName +', '+ inFirstName );
    var superToString = this.toString.bind(this);
    this.toString = function() {
        return 'SpecificNames [iid='+ this.instanceId +', name='+ this.getName() +', super.toString='+ superToString() +']'
    }
    console.log('constructor-invoke: SpecificNames ('+ this.instanceId +')');
};

var g = new Generic(); 
var sn = new SpecificName('Run Forest Run');
var sns = new SpecificNames('Forest','Gump');

console.log('g:   '+ g.toString());
console.log('sn:  '+ sn.toString());
console.log('sns: '+ sns.toString());

leads to this output:

constructor-invoke: Generic (1)
constructor-invoke: Generic (2)
constructor-invoke: SpecificName (2)
constructor-invoke: Generic (3)
constructor-invoke: SpecificName (3)
constructor-invoke: SpecificNames (3)
g:   Generic [iid=1]
sn:  SpecificName [iid=2, name=Run Forest Run, super.toString=Generic [iid=2]]
sns: SpecificNames [iid=3, name=Gump, Forest, super.toString=SpecificName [iid=3, name=Gump, Forest, super.toString=Generic [iid=3]]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.