I was looking at this video explanation(https://www.youtube.com/watch?v=qMO-LTOrJaE) of JS prototypal inheritance.
There's something I don't understand. Let me explain
var Bear = function(type) { //PARENT
this.type;
this.hasFur = true;
}
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type) { //CHILD
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(Bear.prototype); //INHERITING FROM PARENT
var grizzly1 = new Grizzly('grizzly');
console.log(grizzly1.hasFur); //prints undefined //members in parent's constructor not accessible
console.log(grizzly1.kingdom); //prints Animalia //however, members in parent's prototype is accessible
But as soon as you add the following line to the Grizzly constructor,
var Grizzly = function(type){
Bear.call(this, type); //ADDED
this.species = 'Brown Bear';
}
you're able to access everything from the parent, not just it's prototype
console.log(grizzly1.hasFur); //prints true
console.log(grizzly1.kingdom); //prints Animalia
However, inheriting in the below fashion, gives the child access to everything in the parent even without the line //Bear.call(this) in the Child constructor.
Grizzly.prototype = new Bear();
So it truly inherits everything this way. Can someone explain what's this behavior and why it happens ?
Also what are the different ways of inheriting in JavaScript. Which one is the best to use considering best practices and why.
There's something I don't understand. Let me explain
var Bear = function(type) { //PARENT
this.type;
this.hasFur = true;
}
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type) { //CHILD
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(Bear.prototype); //INHERITING FROM PARENT
var grizzly1 = new Grizzly('grizzly');
console.log(grizzly1.hasFur); //prints undefined //members in parent's constructor not accessible
console.log(grizzly1.kingdom); //prints Animalia //however, members in parent's prototype is accessible
In the code snippet shared above, grizzly1.hasFur is undefined as the constructor function for Bear is not yet executed. The line Grizzly.prototype = Object.create(Bear.prototype); just inherits the parent prototypal methods and properties.
But as soon as you add the following line to the Grizzly constructor,
var Bear = function(type) { //PARENT
this.type;
this.hasFur = true;
}
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type) { //CHILD
Bear.call(this, type); //ADDED
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(Bear.prototype); //INHERITING FROM PARENT
var grizzly1 = new Grizzly('grizzly');
console.log(grizzly1.hasFur); //prints undefined //members in parent's constructor not accessible
console.log(grizzly1.kingdom);
grizzly1.hasFur is now true because now within the constructor function of grizzly, the constructor class for Bear is invoked changing its context using a call. The this. hasFur gets its true value assigned in this operation as here due to the changed context, this now refers to the instance of grizzly.
However, inheriting in the below fashion, gives the child access to everything in the parent even without the line //Bear.call(this) in the Child constructor.
Grizzly.prototype = new Bear();
What happens here is, a new instance of the Bear class is created. Now any instance of the class Bear can have access to the prototypal methods and internal properties defined while instantiating the constructor class i.e. function Bear. Now after the instance being created, this gets assigned to the prototypal chain of Grizzly. So any new instance of Grizzly not only access the internal properties of Grizzly, but also behaves as a new instance of the Bear class.
Also what are the different ways of inheriting in JavaScript
I would definitely suggest you to study design patterns. You can google out different books for it. I loved reading JavaScript: The Good Parts and Learning JavaScript Design Patterns. You might love some other books for clearing up your fundamentals. There are few countable things in Javascript like these, closures, etc., which needs crystal clear conceptions.
Which one is the best to use considering best practices and why.
The best practice in prototypal inheritance ,I prefer,is:
In the constructor class say A
function A () {
this.privateProp = something;
}
A.prototype.public = something;
So see declare only those properties and methods inside the constructor class, which you wanna keep private. Rest keep it exposed in prototype chain.
Hope this helps.
Check this out:
var Bear = function(type){ //PARENT
this.type;
this.hasFur = true;
}
alert(new Bear().hasFur);
See how this does gives you true in the alert box. Think, why is this working, and not for your example?
Thought about it?
It's because in this code:
var Bear = function(type){ //PARENT
this.type;
this.hasFur = true;
}
You're assigning the function to Bear, so it's accessible by new Bear() not Bear.prototype. This will work:
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type){ //CHILD
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(new Bear()); // Modified line
var grizzly1 = new Grizzly();
alert(grizzly1.hasFur); // Prints true now.
alert(grizzly1.kingdom);
Related
I have read every article and example on the first page of Google and I still am having a hard to completely understanding how to properly implement Prototypal Inheritance in JavaScript. The biggest challenge I'm facing is I am seeing many different ways to implement the inheritance.
First I will start with what I want to achieve if this was C#:
C#
class Base {
public string UI { get; set; } // Using a string just for simplicity
}
class Book : Base {
public Book(string title) {
this.title = title;
}
private string title { get; set; } // Title of book
}
Then I can instantiate a Book and be able to access UI on each instance:
var myBook = new Book("East of Eden");
myBook.UI = "some string"; // This work.. all Book instances have THEIR OWN UI string
JavaScript
Now lets say I have a base object in JS that I want all other objects to inherit from:
function Base() {
this.UI = {}
}
I then want another object type to inherit this model like this:
function Book(title){
this.title = title;
}
Book.prototype = new Base();
// Sometimes I have seen this line instead... nothing seems to work at all when I use this though, so I don't understand whats happening here
//Book.prototype = Object.create(Base.prototype);
Book.prototype.constructor = Book;
Book.prototype.getTitle = function(){
return this.title;
}
var myBook = new Book("East of Eden");
var anotherBook = new Book("Grapes of Wrath");
console.log(myBook.getTitle()); // East of Eden
myBook.UI.isRead = true;
console.log(myBook.UI);
console.log(anotherBook.getTitle()); // Grapes of Wrath
anotherBook.UI.isHardcopy = true;
myBook.UI.isRead = false;
console.log(anotherBook.UI); // This UI object has isRead on it as well!!! NOOOO
So this doesn't really work because both instances are sharing the same UI object, but what I want is for them to have their OWN instance of the UI object.
Another method I have seen is to not use the 'new' keyword at all and only use Object.create() to get new objects. However, I am not sure how I would implement my Base class with some subclass like Book and then create multiple instances of Book, each with their own UI properties.
Could someone please give me an example of how to inherit a base class and create instances of that subclass with their own UI objects? Thanks
EDIT
So would the "simple" way of achieve what I want just be to do something like:
var Base = {
UI: {}
}
function Book(title){
_.extend(this, Base);
this.title = title;
}
var myBook = new Book("East of Eden");
myBook.UI.prop = 5; // This works now but doesn't utilize true inheritance at all!
Prototypes are linked and not copied. This means that when you did:
function Base(){
this.UI = {}
}
Book.prototype = new Base();
Book.prototype.constructor = Book;
The prototype of your Book constructor will be a new instance of Base. All your instances of Book will have the same prototype, the same instance of Base. Since it's this object which holds the UI property, all Book instances will fallback to the same object property.
Think that your Prototype will be:
var proto = {
UI : { }
}
All your Book instances will have access to this object:
var a = new Book('East of Eden');
var b = new Book('Grapes of Wrath');
a.UI.prop = 'prop'; //proto.UI.prop === 'prop'
b.UI.prop === 'prop'; //because it's also proto.UI.prop
If you actually define a property on Book instances, say on its constructor:
function Book(title){
this.title = title;
this.UI = { };
}
You'll see that they are different objects:
a.UI !== b.UI //true
a.UI.prop = 'prop';
b.UI.prop !== b.UI; //true
Calling the constructor is the most obvious way to also initialize the properties on their children:
function Book(title){
Base.call(this);
this.title = title;
}
Regarding the difference between new Base() and Object.create(Base.prototype).
new Base() will initialize the object and call the constructor, while Object.create(Base.prototype) will do basically the same, except it won't call the constructor. This means, that the prototype won't have the properties set on the constructor (UI).
The biggest challenge I'm facing is I am seeing many different ways to implement the inheritance.
There really is only one correct way.
Use Object.create to establish inheritance:
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
configurable: true,
}
});
Then apply the parent constructor in the child constructor to the child instance:
function Child() {
Parent.call(this);
}
This is basically what happens under the hood if you'd use ES2015's new class syntax.
See Benefits of using `Object.create` for inheritance for more details on Object.create and why you want to use it in this case.
I have read that private state of instance objects is generally not advised, and I would appreciate the help in pointing out the flaws/shortcomings of the following implementation.
Any advise/critique is greatly appreciated.
var namespace = {};
namespace.parent = {
parent_method1 : function () {},
parent_method2 : function () {}
};
namespace.child = function (properties) {
var private="secret";
this.prototype = {
create : function () {
this.unique = 'base';
this.unique += this.properties;
return this.unique;
},
get_private: function () {
console.log(private);
},
set_private: function (val) {
private = val;
}
};
var proto = Object.create(namespace.parent);
var instance = Object.create(proto);
for (var property in this.prototype) {
if (this.prototype.hasOwnProperty(property)) {
proto[property] = this.prototype[property];
}
}
instance.properties = properties;
return instance;
};
var a = namespace.child("a");
console.log(a.create());
a.get_private();
a.set_private("new_a_secret");
a.get_private();
var b = namespace.child("b");
console.log(b.create());
b.get_private();
a.get_private();
I would appreciate the help in pointing out the flaws/shortcomings of the following implementation.
I don't see anything wrong with your implementation of the var private, provided that it does what you expect it to do.
However, the big flaw of the code is: I don't understand it. What is your implementation supposed to do? It does not follow any of the standard patterns. This might be a shortcoming of the pseudo-methods and clear up when implementing a real world model; however as it stands it's quite confusing. Some documentation comments would help as well.
Specifically:
What does namespace.child do? It looks like a factory function, but I'm not sure what "childs" it does produce.
Also, for some reason it does set the namespace.prototype property to a new object on every invocation, which is then mixed into the instance object proto object. However, it leaves the internals (get_private, set_private) of the last created instance in global scope.
Are a and b supposed to be classes? Why do they have .create() methods, that initialise the class (instance?) - and should rather be called .init() if at all? Why do they return the .unique property value?
Why doesn't the child method initialize those factored objects right away?
What is that .properties field that holds a string value?
Why are you using two-level inheritance for those instance objects? Object.create(namespace.parent) is understandable, it inherits from a static object that is shared. But why is then Object.create(proto) used, copying some properties (create, get_private, set_private) on the proto and some properties (properties, unique) on the instance? Why distinguish between them?
I have a javascript scenario where I have created a base class and a derived class and wish to pack the total set of properties into a JSON-string with JSON.stringify().
When I use the equivalent to the code below I only get the child-object's properties when I run "toString()" on one of the DerivedClass instances:
function BaseClass() {
this.version = "0.0.0";
this.time = Date.now();
this.type = this.constructor.name;
}
BaseClass.prototype.BaseClassException = function(message) {
this.message = message;
}
BaseClass.prototype.toString = function() {
return JSON.stringify(this);
}
BaseClass.parse = function(jsonString) {
var json = JSON.parse(jsonString);
switch(json.type) {
case "DerivedClass1":
return new DerivedClass1();
case "DerivedClass2":
return new DerivedClass2();
default:
throw new BaseClassException("No compatible type found when parsing: " + jsonString);
}
function DerivedClass1(prop1, prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
this.type = this.constructor.name;
}
DerivedClass1.prototype = new BaseClass();
DerivedClass1.prototype.constructor = DerivedClass1;
function DerivedClass2(prop3) {
this.prop3 = prop3;
}
DerivedClass2.prototype = new BaseClass();
DerivedClass2.prototype.constructor = DerivedClass2;
// Test
var dc1 = new DerivedClass1("A", "B");
console.log(dc1.toString()); // Returns JSON-string with properties of DerivedClass1, but not BaseClass
There will be several different derived classes. While I do know that js doesn't really support classes I would still like to pack all the properties from the base and child objects in the same JSON-string. The structure is necessary to correlate to the other nodes of the total system, ie all properties need to be present.
If anyone at the same time has the knowledge of nudging me in the correct direction to understand the link between the child object and parent object in order for me to better understand the "inheritance" part of js I'd be really thankful as well. I more used to strict oo-languages so I'd be happy to learn.
There are two things which I can readily suggest.
To invoke the base class constructor, you have to invoke it manually like this
function DerivedClass1(prop1, prop2) {
BaseClass.call(this);
this.prop1 = prop1;
this.prop2 = prop2;
this.type = this.constructor.name;
}
We invoke the parent constructor function, with the current object. The important thing to note here is that, we are setting the current context to the object of type DerivedClass1.
To actually do prototypal inheritance, you need to use the base class's prototype, not the object.
DerivedClass1.prototype = Object.create(BaseClass.prototype);
In your case, BaseClass's constructor doesn't depend on any arguments. So, doing DerivedClass1.prototype = new BaseClass(); will not make a big difference. But it is always better to depend only on the Parent constructor's prototype. Read more about using Object.create for inheritance, in this wonderful answer.
How can I test if a constructor extends another constructor, Backbone.js-style, where inheritance is set up via Backbone's extend method? And don't say instanceof :). I'm not talking about objects. I'm talking about constructors.
E.g.: Take a constructor like the one produced by the following code:
var MyRouter = Backbone.Router.extend();
Now, in another spot in the code, how can you test that somewhere in its prototype chain, var my_router = new MyRouter has the properties of Backbone.Router.prototype?
Here is my solution:
var inherits = function(child, parent) {
if (!_.isFunction(child) || !_.isFunction(parent))
throw new Error('`child` and `parent` must be functions.');
return _.reduce(Object.getPrototypeOf(child.prototype), function(memo, child_prototype__proto__) {
return _.contains(parent.prototype, child_prototype__proto__) && memo;
}, true);
}
So, you can do:
var MyRouter = Backbone.Router.extend();
inherits(MyRouter, Backbone.Router) // true
inherits(MyRouter, Backbone.Model) // false
This works for single-layer Backbone-style inheritance, wherein Backbone's extend function was used as above.
The works because because Backbone's extend does the following when it sets up the prototype chain, where child is the constructor you get at the end and parent is the constructor you're extending:
var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate;
So, a constructor that results from extend has all of its parent's prototype properties on its .prototype.__proto__ property. If this is new or confusing, you can read more about this on John Resig's blog. Essentially, "test".__proto__ === String.prototype.
What on earth is going on here?
How can the Daughter-class contain data that's been set in Brother, and how should I make sure that data set in sibling classes doesn't interfere with eachother?
class Parent
data: {}
class Child extends Parent
age: 10
Son = new Child
Son.data.name = "John Doe"
Daughter = new Child
console.log Daughter.data # => { name: 'John Doe' }
The problem seems to be, that you're not using a constructor to initialize data for each instance. Instead, you're giving it an initial value that happens to sit on Animal which is mutable. Whenever you assign to instance.data.attribute, you are in fact modifying that shared object. If you had used an data: 1 instead, you would not have seen this sharing behavior.
This fixes your problem:
class Parent
constructor: () ->
#data = {}
Disclaimer: I'm not that well versed with JavaScript's prototypal inheritance, so the technical details I provided may not be correct, but the description of the phenomenon seems accurate.
Difference when compiled
class Parent
staticD: {}
constructor: ->
#data = {}
Compiles to:
Parent = (function() {
Parent.prototype.staticD = {};
function Parent() {
this.data = {};
}
return Parent;
})();
As you can see staticD is initalized only once at the creation of the "class", data on the other hand is initialized in the constructor and assigned a new, empty object every time an instance is created.
If you take your CS code and put it in the side-by-side editor on CoffeeScript's site (http://coffeescript.org/), you'll see that data is on the prototype of the Parent "class". Think of that prototype being the template for new functions (classes) that you create. That prototype either contains other functions or it contains variables available to all instances (like an OO static variable).
You're adding name to a "static" variable data. It will then be available to all instances that "derive" from Parent.
I'm not sure of the inner workings that go on there, but coming from an OO world, that's how I interpret it. I hope this helps.
GENERATED CODE VIA COFFEESCRIPT'S SITE
var Child, Daughter, Parent, Son,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Parent = (function() {
function Parent() {}
Parent.prototype.data = {};
return Parent;
})();
Child = (function(_super) {
__extends(Child, _super);
function Child() {
return Child.__super__.constructor.apply(this, arguments);
}
Child.prototype.age = 10;
return Child;
})(Parent);
Son = new Child;
Son.data.name = "John Doe";
Daughter = new Child;
alert(Daughter.data.name);
UPDATE
Just noticed that the CS side-by-side window has a link feature. Here's a link to the side-by-side code.
UPDATE #2
In response to your question in the comments, I'm not sure exactly what you want to do, but you could do something like this:
class Parent
#data: {}
class Child extends Parent
constructor: (#name) ->
age: 10
sayHi: -> alert "Hi " + #name
Son = new Child "John Doe"
Daughter = new Child "Sarah Jane"
Son.sayHi()
Daughter.sayHi()
Perhaps keep the name variable (or the entire data variable) at the parent level and set it via a constructor and access it via a parent function.