I have a simple inheritance issue in JavaScript where a Child class inherits from a Parent class. However, in using Object#create to establish the inheritance, it seems that it must come before instantiation of the Child class:
function Child() {}
function Parent() {}
Parent.prototype.sayhello = function () {
console.log("hello world");
}
// Apparently, this must precede instantiation:
// Child.prototype = Object.create(Parent.prototype); //works, console logs "hello world"
var c = new Child();
// We get a TypeError: c.sayhello is not a function
Child.prototype = Object.create(Parent.prototype);
c.sayhello(); //TypeError: c.sayhello is not a function
My thinking was that even if Child.prototype = Object.create(Parent.prototype); came after the instantiation, we are still setting the Child class's prototype to point to the Parent's prototype, so when sayhello is called, the prototypal chain is searched until the method is found. Why doesn't this work? I must be misunderstanding something fundamental.
When you write new Child(), the returned object is linked (via __proto__) to the current value of Child.prototype.
When you assign a new object to Child.prototype after that, that does not affect the existing instance (which still points to the old prototype object).
When you declare var c = new Child() you are constructing a new Child object. A prototype has not yet been declared for this constructor when the c object is made, so its prototype is undefined and remains undefined. It does not update when you declare prototype properties of the Constructor after the fact. That c object remains frozen with regard to its prototype as it has already been made.
Remember that Javascript is pseudoclassical. Everything is an object, there are no real classes.
Related
I'm reading through Crockford's "Javascript: The Good Parts". Early on he introduces the Object.create() function, and it seems to be redundant. Why is Object.create() preferred to assigning an object to the prototype of a new object the good ol' fashioned way? What's the difference between these two statements? I certainly prefer the Object.create() syntax, but I'd like to understand the fundamentals here:
var bar = Object.create(foo);
and
var bar = {};
bar.prototype = foo;
How it works is ,
function createObject(proto) {
function ctor() { }
// assigns prototype of Person to ctor's prototype
ctor.prototype = proto;
// return new instance of ctor
return new ctor();
}
// Usage:
Student.prototype = createObject(Person.prototype);
So, it creates new object constructor with prototype assigned as prototype of Person.
When you try to add a new function in Student's prototype object, it is not available in Person's prototype
ex -
Student.prototype = createObject(Person.prototype);
Student.prototype.newFunc1 = function() { console.log('hello from new world');}
//Person.prototype will not have newFunc1.
In case of where you directs assigns prototype of Person to prototype of Student like
And when you add a new function into prototype of Student like
Student.prototype = Person.prototype;
Student.prototype.newFunc1 = function() { console.log('hello from new world');}
//When you check Person.prototype, it will have newFunc1 function.
prototype object is not assigned, only the reference is assigned.
In object oriented programming, the child class has properties of parent as well as its own.
If we don't do Object.create() and directly assign prototype of parent to the prototype of child , whatever new property we add to the child, will get reflected in parent too.
To avoid that, Object.create() is preferred.
If I have the following:
function Constructor1(data){
...
...
...};
function Constructor2(data){
Constructor1.prototype.constructor.call(this, data);
...
...
...
}
Constructor2.prototype = new Constructor1();
Then how can I later determine the difference between how they were constructed? I know I can do if (testObject instanceof Constructor2) but if I have a LOT of inherited objects I don't want to do that test for everything. Is there any way to get the string 'Constructor2' returned somehow? (Or whatever the first constructor function called) is?
You can call the parent like this: Parent.call(this,args).
You should not create an instance of Parent to set the prototype part of the inheritance in Child.
If you set the prototype without destroying the prototype.constructor in Child you can use the name property of the constructor function:
function Parent(args){
};
function Child(args){
Parent.call(this,args);
};
console.log(Child.prototype.constructor.name);//=Child
//overwrithing Child.prototype so also Child.prototype.constructor
Child.prototype=Object.create(Parent.prototype);
console.log(Child.prototype.constructor.name);//=Parent, needs to be fixed
Child.prototype.constructor=Child;//fixed
var c = new Child();
console.log(c.constructor.name);//=Child
The name property of Function isn't standard so no guarantee about it's behavior:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
You may want to check using the function itself: (this.constructor===Parent)
More on constructor functions and prototype here.
I've created an example to illustrate:
// this is the parent class
function animal() { console.log('animal constructor') }
// allow animals to walk
animal.prototype.walk = function() { console.log('animal walking') }
// create child class
function cat() { console.log('cat constructor') }
// cat inherits from animal
cat.prototype = Object.create(animal.prototype);
// let cats meow
cat.prototype.meow = function() { console.log('meow') }
// create a cat object
var myCat = new cat();
/* output: cat constructor */
// yet, the constructor that ran is different than what the prototype for cat reports
console.log(cat.prototype.constructor);
/* output: function animal() { console.log('animal constructor') } */
So note how inheritance mostly worked as expected, cat inherited the method 'walk' from its parent dog class, and adding further methods to the child class such as meow works as expected. However, when I create an instance of cat, the constructor for cat runs, whereas cat.prototype.constructor points to the constructor "inherited" from dog.
Isn't the purpose of object.prototype.constructor to allow us to modify the constructor of an object after the object has been declared without wiping out the prototype for the object? In the above example, shouldn't the constructor stored in cat.prototype.constructor point to the same constructor that runs when creating a cat object? Does this apparent ambiguity have something to do with how in this source code this statement is run:
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
The constructor property is just a simple property of the prototype object. There is nothing magically happening with it behind the scenes. It's a property that can be overridden and reset, but it doesn't affect anything else.
So when you do this:
cat.prototype = Object.create(animal.prototype);
you are overriding the entire prototype property of the function cat with a complete new object derived from the prototype object of animal. But since the constructor property is just a normal property of the prototype object, it will get overridden as well.
And yes, when implementing inheritance, the line
Class.prototype.constructor = Class;
is commonly added to restore the constructor property to its original value and to kind of undo the "damage" that was done by this inheritance pattern.
So in your case, you would need to add the following line:
cat.prototype = Object.create(animal.prototype);
cat.prototype.constructor = cat; // <---- add this
Think about the line:
cat.prototype = Object.create(animal.prototype);
Object.create(animal.prototype) will simply return an object that has no properties itself but whose prototype is given by animal.prototype. Therefore looking up the constructor property on this object will simply return the value held in animal.prototype.constructor.
Since the above line is assigning a reference to this newly created object to cat.prototype (and hence overwriting whatever was previously held in cat.prototype), of course you'd expect cat.prototype.constructor to be equal to animal.prototype.constructor.
As you mentioned above, you can side-step this 'issue' using something like:
cat.prototype.constructor = cat;
reference for Object.create(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
I am learning javascript and got puzzled. An example over here which has example as below:-
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
// inherit Person
Student.prototype = new Person(); //<---- Confusion
// 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');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Now, I am confused (<----) in these two lines. When I say Person.call(this);, this is simply stating to Inherit properties of Person class... Right?
Then what is this doing?
// inherit Person
Student.prototype = new Person(); //<---- Confusion
As per my knowledge, .prototype also inherits all properties?
To explain it, first let's remember how constructor functions work in JavaScript:
function Guide(a) {
this.a = a;
}
Guide.prototype.q = "Life, the Universe, and Everything";
var g = new Guide(42);
console.log(g.q); // "Life, the Universe, and Everything"
console.log(g.a); // 42
When we do new Guide(42), the new operator creates a new object and assigns it a prototype using the Guide.prototype property. Then new calls Guide, passing in that new object as this. Guide uses this to add properties to the new object that aren't on its prototype. Then the new expression completes and its result is the new object that it created.
When we look at g.q, since the g object doesn't have its own property called q, the JavaScript engine looks at g's prototype, which (again) it got assigned when it was created. That prototype has a q property, and so the engine uses its value.
In contrast, when we look at g.a, the g object has its own property called a, and so the value is used directly.
With that foundation in place, let's look at Student and Parent:
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
When we call new Student(), within the call to Student, this is (again) the new object created by the new operator, which has Student.prototype as its underlying prototype. But the Parent function hasn't had a chance to do anything with this new object. So what that line does is give Parent a chance to do whatever it needs to do to new objects that it can't do via the prototype, like our Guide function earlier assigning to this.a. In technical terms, Parent.call(this); calls the Parent function, ensuring that this within the call to Parent is the value passed into call (which is, in this case, the this of the call to Student — e.g., the new object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor: It gives the base constructor a chance to initialize the object.
// inherit Person
Student.prototype = new Person(); //<---- Confusion
Since Student is supposed to inherit from Person, what that code is doing is creating the prototype that will be assigned to objects created via new Student. The object it's creating is a Person object.
FWIW, that code isn't quite implementing the construction chain correctly (it's calling Person more often than it should [both when creating Student.prototype and when Student is called], and failing to set constructor).
The more correct way to create Student's prototype property, if we're going to call Parent from within Student, looks like this:
function derive(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
derive(Student, Parent);
That way, we get a prototype based on Parent.prototype but without calling Parent. It's an either-or: Either call Parent to create Student.prototype, or call Parent within Student, but don't do both. When building hierarchies with constructor functions, typically you want to call the parent from the child constructor, rather than when creating the child prototype. When using direct object inheritance (without constructor functions), of course you do it the other way.
If you're interested in inheritance in JavaScript, I've written a helper script called Lineage you might want to look at, and in particular even if you don't use Lineage, this discussion on its wiki page may be useful for understanding inheritance hierarchies.
I asked the question:
Why cant I declare a constructor instantiate an object and then access the prototype?
And you can see that I have marked the answer. I understand the response but Im a bit confused as to what he means by:
The prototype belongs to the class, not the instance:
Does this mean that javascript has a class in this example? I thought javascript was classless? It only has function constructors... At what point does a function constructor become a class? Is it when you add other members to it using the .prototype accessor?
Actually class is an OOP term, not really javascript. What is meant is that the prototype belongs to the constructor. So in
function MyConstructor(prop){
this.foo = prop || 'foo';
}
MyConstructor.prototype.bar = 'allways bar';
var mc1 = new MyConstructor('I am mc1'),
mc2 = new MyConstructor('I am mc2');
alert(mc1.bar) ; //=> allways bar
alert(mc2.bar) ; //=> allways bar
alert(mc1.foo) ; //=> I am mc1
alert(mc2.foo) ; //=> I am mc2
bar belongs to the constructors (MyConstructor) prototype. It will always be 'allways bar', for every instance. foo is an instance property (with a default value 'foo') and can be assigned with a different value for every instance.
Ya prototype of JavaScript is a concept quite similar to class but not exactly the same. Read the article below, it offers one of the best explanations available on internet on this issue.
http://www.crockford.com/javascript/inheritance.html
There are no classes in javascript.
Constructors are functions and have a prototype property that references an object. You can add functions to that object, or assign a new object to the prototype property to create an inheritance chain:
function MyConstructor () {
// initialise instance
}
MyConstructor.prototype.someMethod = function() {
// ...
};
MyConstructor.prototype.anotherMethod = function() {
// ...
};
or replace it with an instance of another constructor:
MyConstructor.prototype = new SomeOtherConstructor();
MyConstructor.prototype.constructor = MyConstructor;
and so on. Now when an instance of MyConstructor is created:
var anInstance = new MyConstructor();
The object returned by the constructor has MyConstructor.prototype as its internal [[prototype]] property and "inherits" its methods and properties (and those on its entire [[prototype]] chain).
So each instance of MyConstructor has its MyConstructor.prototype on its prototype chain. Note however that MyConstructor doesn't inherit from it's own prototype, it is only used by instances created by new MyConstructor.