I asked the following question on why classes are being used in a typically classless prototypal inheritance language like js: class use in a prototypal inheritance-based language
It seems they're "syntatic sugar" because the masses like classes... and that they're just regular js objects in the background.
Now id like to know what the differences are between js fake "classes" and classical classes?
If I'd compare JS "classes" with classes in Java, the first thing I'd say is that JS "class" is just an object whereas Java class is not.
An object has its own properties/fields/methods. This is also what a JS "class" can have. But a class in Java can not, only instances can.
Some people would probably say "Wait, but how about static fields and methods? I can do a static MyClass.myField field an MyClass.doSomething() method."
Yes, you can. But from my point of view they will just be "placed" in the MyClass namespace, they aren't really properties of the class:
You don't have this in static methods - but you can use this in class-level methods in JS "classes"
You can't make a class with a static method to implement a certain interface - assuming duck-typing as interface this is no problem in JS
So a Java class with static fields or methods is just a namespace for these fields and methods, nothing more. What makes it even more obvious is the fact that in a static method you can't find out which class you're in (without tricks):
Getting the class name from a static method in Java
So in JS pseudoclasses are first-class objects whereas in Java they are not.
I can think of this, in class inheritance, the parent objects are locked up. For instance:
class A
{
};
class B extends A
{
};
Here, A's definition is locked up, you can't add new properties once it is inherited.
In Javascript 'classes', you can:
var o = {x:2};
var b = Object.create(o);
o.y = 5;
b.y
>5
Do you see how we added a property after 'inheriting'? This is one difference, objects aren't really locked up(though you can do the locking up of objects by using Object.preventExtensions, Object.seal, Object.freeze), but by themselves the objects can be modified at any point of time and this link to the prototype object is maintained in the child object.
Related
I have two classes defined, say Animal and Rabbit. Rabbit extends Animal and has some additional methods apart from those defined in Animal.
When the user runs my app, an instance of Animal is created (say myAnimal). Then depending on something that the user does, I may need to "enhance"/cast myAnimal into the inherited class Rabbit. Is this possible in Modern JavaScript so the additional methods defined in Rabbit may now be available to myAnimal?
#Etheryte 's suggestion worked. I defined a static method fromAnimal in Rabbit which creates a new Rabbit, sets properties of given Animal (myAnimal) and returns that instance. It includes all processing that myAnimal has undergone so far.
Thank you.
no you can not.
other way, you can create an instance of Rabbit - myRabbit with properties of myAnimal. (comment of #Etheryte above)
or use decorator of Typescript
I know there are tons of oop posts on here as well as many blogs etc. I'm not posting this because im too lazy to read other posts, I probably read about 100 and still have some questions as many just state things but dont explain them much or certain things have contradicting answers and it would be great if I could get clear answers!
Encapsulation
There are posts that say yes to that because they define it as grouping together properties and functions. If that would be the definition, I totally get why javascript supports encapsulation. However, there also posts about keeping members private. As I understand (dont know java) but in Java thats the concept - you cannot access properties without methods (so only methods can access them) plus you actually have 'private/public' keywords to keep things private.
before ES6 :
Its possible:
function A (name) {
var name = name;
this.getName = function () {
return name;
}
}
var a = new A("mike");
a.getName() //accesses name
a.name //does not --> results in undefined
In es6 its not really possible, because you you would have to add the method accessing the property inside the constructor, which you wouldnt do
class A {
constructor(name) {
var name = name;
this.getName = () => {
return name; // only like this could you have var ...
}
}
}
So my question:
1. What is encapsulation ? Is it about grouping methods/properties or is it about keeping members private (which wouldnt be possible in es6 and before es6 not by default)?
Abstraction
" hiding internal implementation details. It should only reveal operations relevant for the other objects "
I would imagine for example jquery methods to use abstraction and you dont see their inner implemantion, 'just use' them. Could someone please explain and provide an example im vanilla js what abstraction is and if javascript actually makes use of that?
polymorphism
"designing objects to share behaviors and to be able to override shared behaviors with specific ones"
overriding
overloading
Many posts/blogs say polymorphism is NOT used in javascript, but..
Overloading is without argument not possible in javascript. Overriding of methods is?! I can have a parent class and a child class having the same function (same name) doing different things. Is that what you understand under overriding? Also, sharing behaviors is def. possible but only with inheritance.
Is there a way to share behaviors without inheritance, but only with making use of polymorphism? Im generally confused what exactly polymorphism is after reading for a while..
Inheritance
Inheritance is def. supported by js.
I just want to double check about es6 classes that I get it right (i have no experience with java etc).
The difference is that js uses prototypical inheritance and not classical as java etc. The difference is that when I create a new instance/=object from my es6 class, it links to properties/methods of the class that I use to initialize new objects, while in classical inheritance, the engine copies the properties/methods from that class. s that correct? Could someone please explain the difference - resulting - from that difference?
I just finished reading this very good article on prototypal inheritance in JavaScript, but was surprised to see how vehemently the author was against having properties defined in prototypes.
A common mistake when creating objects for the prototype chain, from programmers that come from classical OOP anyway, is to define common properties high up in the chain because they exist for all instances. We feel the need to define the property as if the abstract object described an interface. Yet there is no point in defining in a prototype a property that will be present in objects that descend from it. Javascript is not like Java : you don't declare in the base objects variables that will be different to all instances of the descendants. You declare a variable only on the level where it will be defined.
Take the name property of our animals. Since every animal has a name, it's natural to consider this property as common to all, and define it in the common denominator which is the Animal prototype. The thing is, Animal has no name. A Dog instance has a name.
In Javascript, you cannot say an Animal has a name. Animal is an object, not a definition, even if we use it like so. And that object has no name property. Why then is name referred to in Animal's methods if Animal has no name? Because Animal is abstract : it is not intended to be used by itself. this, in Animal, will never refer to Animal. It will refer to whatever object descends from Animal, dino for example. And dino has a name.
If I have a very complex set of classes that have, dozens of properties in common. I don't see how it's better to duplicate those properties and the work that goes into setting them up on each instantiable derived class when the work can be done once in the base class, even if that base class was meant to be 'abstract'.
For instance:
function Analysis(args){
args = args || {};
// Extract supported init properties from args
this.description = args.description;
this.host = args.host;
this.source = args.source;
this.identifier = args.identifier;
this.vendor = args.vendor;
this.agent = args.agent;
//etc...
}
function PortfolioAnalysis(args){
Analysis.call(this, args);
args = args || {};
this.portfolio = args.portfolio;
this.author = args.author;
//etc...
}
PortfolioAnalysis.prototype = Object.create(Analysis.prototype);
PortfolioAnalysis.prototype.constructor = PortfolioAnalysis;
function TreatyAnalysis(args){
Analysis.call(this, args);
args = args || {};
this.treaty = args.treaty;
this.terms = args.terms;
//etc...
}
TreatyAnalysis.prototype = Object.create(Analysis.prototype);
TreatyAnalysis.prototype.constructor = TreatyAnalysis;
//etc...
So the article is saying I should paste the initialization code for the properties description, host, source, etc. in each of the derived classes, and remove it from the base class.
I don't see why that's better, especially if there's a bunch of complex common logic around constructing these objects using those shared properties, what's so bad about defining them in the base class, and if it's so bad, is there a way around it that doesn't involve code duplication or having to define a separate '.init()' method?
So the article is saying I should paste the initialization code for the properties description, host, source, etc. in each of the derived classes, and remove it from the base class.
No. Your code is perfectly fine, exactly how it should be done.
And that article is saying that the properties like description, host etc should be placed on instances (like a new ThreatAnalysis(…), or even a new Analysis(…)), but not on Analysis.prototype - just what you are doing. There are some people who would "default", e.g. empty, identifiers etc on Analysis.prototype because they want to "declare" that every Analysis instance should have an identifier. That is rubbish, as the article explains.
To share your initialisation behaviour in the Analysis constructor is fine (as the article mentions, shared functions may be placed hight in the prototype chain). There's no need to inline it and make Analysis and empty object, even if it is abstract and will never be instantiated directly.
I don't think you get prototypal inheritance yet. The author is not saying “don't put the initialization code in the base constructor”. What the author is saying is “don't put properties on the base prototype”. It's totally different.
So you are allowed to do what you are currently doing. It's totally fine. What you shouldn't do however is put default values of properties on the prototype as it might cause problems. For example consider:
function Foo() {}
Foo.prototype.data = []; // you shouldn't do this
var a = new Foo;
var b = new Foo;
a.data.push(0);
alert(JSON.stringify(b.data)); // [0]
This is why you shouldn't share properties on the prototype. We modified the value of a.data but since data is shared amongst all instances of Foo we also modified b.data. Hence an invariant was violated.
Think about it like this:
The properties defined on the current object are its public properties. They are not shared.
The properties defined on the prototype of the current object are static properties. They are shared amongst the instances of the prototype.
Hence it's alright to define static properties, like the count of all the instances, on the prototype. However it's not alright to define public properties on the prototype because it may cause problems like the one above.
Dr. Alex Rauschmayer explains this better: http://www.2ality.com/2013/09/data-in-prototypes.html
Your code is fine because the this in your constructors always point to the current object, not the prototype. Hence you are not defining any properties on the prototype.
I think you got confused because of constructors vs prototypes. Perhaps this blog post would elucidate your doubts: http://aaditmshah.github.io/why-prototypal-inheritance-matters/
So the code below reflects the pseudo-classical version of inheritance in JavaScript.
function SynthOne() { // constructor 1
this.sound1 = "piano";
};
function SynthTwo() { // constructor 2
this.sound2 = "bass";
}
SynthOne.prototype = new SynthTwo; // overwrite constructor 1's prototype with constructor 2's
var synthsCombined = new SynthOne; // assign constructor 1 to variable
// this variable now has access to both constructors properties & methods
document.write(synthsCombined.sound1 + " ")
document.write(synthsCombined.sound2)
But let's change this to make sound1 and sound2 to simply sound.
Let's also assume that I really wanted to create an inheritance chain to access both of these "sounds" even if they were named the same thing. Is there a pattern in the JavaScript community or a coding convention that exist to deal with this kind of situation? Or am I just stuck?
Thank you
Child properties hide properties of the same name further up the prototype chain. Technically, you can still get access to the parent property like this:
Object.getPrototypeOf(synthsCombined).sound
Or the non-standard:
synthsCombined.__proto__.sound
But this probably isn't something you want to do. If you need both values, then name them different things.
it was simply something that entered my mind and I was curious about. I can see a situation where at the very least you combine constructors not realizing they have similar property/method names.
You hardly inherit from classes whose set of properties1 you do not know. If you subclass something, you often want to explicitly overwrite properties with more specific values - that's just what the shadowing is for.
In case you want to extend the set, you'd have to choose an unallocated name. In case of interface clashes (e.g. when extending the implementation), that's just a bug and either the base class or the child classes would need to change their identifier. Using descriptive names will lower the risk.
How to deal with this kind of situation?
If it's unwanted, fix the bug (this is not JavaScript-specific). If you deliberately have chosen the same property name, you can access the inherited value by manually ascending the prototype chain with Object.getPrototypeOf().
[1]: Speaking of both attributes and methods, as they're just properties in javascript
You could give one of your constructors a base property, which will get the properties from the inherited constructor:
function SynthOne() { // constructor 1
this.base = {};
this.sound = "piano";
SynthTwo.call(this.base);
};
function SynthTwo() { // constructor 2
this.sound = "bass";
}
SynthOne.prototype = Object.create(SynthTwo.prototype);
var synthsCombined = new SynthOne;
console.log(synthsCombined.sound); //piano
console.log(synthsCombined.base.sound); //bass
But from what it looks like you are trying to accomplish, maybe inheritance is not the right way for you. It might make more sense to create a generic Synth class and maybe a SynthCollection class, to combine different Synths.
I have a JavaScript class, and I would like to make it so it can't be subclassed. (Similar to marking a class with the "final" keyword in Java.) Here's my JavaScript class:
function Car(make, model) {
this.getMake = function( ) { return make; }
this.getModel = function( ) { return model; }
}
The JavaScript Object Oriented paradigm is prototype based, that means that objects "inherit" from other objects, using them as their prototype.
There are no classes, Car is a constructor function, and the language lets you extend any virtually any object.
If you can make a Car object instance, there is no way to prevent this object being used as the prototype of other constructor function.
Given that JavaScript doesn't even actually have classes (it's a prototype-based object system, not a class-based one), and that it is a dynamic language[1], what you want to do is impossible. Further, JavaScript doesn't actually have inheritance/subclassing - it has to be faked by copying and extending objects. There is no way (that I know of) to prevent other code from doing this.
In a dynamic language with metaclass support, it would be possible to implement such a feature. JavaScript is not such a language.
Nope you can't do this directly and don't know that there is a way to do this given Javascript's prototypical inheritance but take a look at Extjs, which is a js framework which has a heavy object oriented type design. Look at the api and more so the source code and you might get closer to where you want to go -- but not totally :)