Override an array in prototypal inheritance - javascript

I am working on a feature which requires inheritance as follows:
function parent() {}
parent.prototype.someProperty = ['common'];
var child1 = new parent();
I want to override some of the properties. If this was a primitive data type, it was easy but someProperty is an array.
Here child1 has a few other values in someProperty like ['common', 'common2', 'common3'].
Now this is an array, so if I push elements like child1.someProperty.push('common2'); they will end up in the parent as well by reference.
What is the best way to achieve this?
Things that I have thought of
copy the array from the prototype and then attach it to child1. The problem is here that I will have to run through the whole array and then copy it. I was wondering if there is a more elegant solution to this.
Have something like function parent() { someProperty = ['common'];}. This will give someProperty to all children so then any value can be easily pushed into it without disturbing other children objects.
I am inclined towards the second approach but I just want to make sure if there are better approaches out there.

if you have properties that will change per instance they are better off living on the instance itself, not the prototype. if you have data that needs to be shared by all instances of a certain class you have two options.
1) Slap the property on the prototype like you have been doing. This works really well for functions but I almost never put data / non function references on the prototype. This is partly for style and partly for consistency.
2)Attach the property 'statically' to the constructor function and access it like Circle.PI instead of cirlceInstance.PI
In your case it seems like this array should be an instance property.
var Thing1 = function() { this.property = []; }

Related

Best (most performant) way to declare (class) properties with unknown values in v8

So I learned a bit about the hidden class concept in v8. It is said that you should declare all properties in the constructor (if using prototype based "pseudo classes") and that you should not delete them or add new ones outside of the constructor. So far, so good.
1) But what about properties where you know the type (that you also shouldn't change) but not the (initial) value?
For example, is it sufficient to do something like this:
var Foo = function () {
this.myString;
this.myNumber;
}
... and assign concrete values later on, or would it be better to assign a "bogus" value upfront, like this:
var Foo = function () {
this.myString = "";
this.myNumber = 0;
}
2) Another thing is with objects. Sometimes I just know that an object wont have a fixed structure, but I want to use it as a hash map. Is there any (non verbose) way to tell the compiler I want to use it this way, so that it isn't optimized (and deopted later on)?
Update
Thanks for your input! So after reading your comments (and more on the internet) I consider these points as "best practices":
Do define all properties of a class in the constructor (also applies for defining simple objects)
You have to assign something to these properties, even if thats just null or undefined - just stating this.myString; is apparently not enough
Because you have to assign something anyways I think assigning a "bogus" value in case you can't assign the final value immediatly cannot hurt, so that the compiler does "know" ASAP what type you want to use. So, for example this.myString = "";
In case of objects, do assign the whole structure if you know it beforehand, and again assign dummy values to it's properties if you don't know them immediatly. Otherwise, for example when intending to use the Object as a hashmap, just do: this.myObject = {};. Think its not worth indicating to the compiler that this should be a hashmap. If you really want to do this, I found a trick that assigns a dummy property to this object and deletes it immediatly afterwards. But I won't do this.
As for smaller Arrays it's apparently recommended (reference: https://www.youtube.com/watch?v=UJPdhx5zTaw&feature=youtu.be&t=25m40s) to preallocate them especially if you know the final size, so for example: this.myArray = new Array(4);
Don't delete properties later on! Just null them if needed
Don't change types after assigning! This will add another hidden class and hurt performance. I think thats best practice anyways. The only case where I have different types is for certain function arguments anyways. In that case I usually convert them to the same target type.
Same applies if you keep adding additional properties later on.
That being said, I also think doing this will lean to cleaner and more organized code, and also helps with documenting.
Yeah, so one little thing I am unsure remains: What if I define properties in a function (for example a kind of configure() method) called within the constructor?
Re 1): Just reading properties, like in your first snippet, does not do anything to the object. You need to assign them to create the properties.
But for object properties it doesn't actually matter much what values you initialise them with, as long as you do initialise them. Even undefined should be fine.
The concrete values are much more relevant for arrays, where you want to make sure to create them with the right elements (and without any holes!) because the VM tries to keep them homogeneous. In particular, never use the Array constructor, because that creates just holes.
Re 2): There are ways to trick the VM into using a dictionary representation, but they depend on VM and version and aren't really reliable. In general, it is best to avoid using objects as maps altogether. Since ES6, there is a proper Map class.

Javascript - Prototyping on DOM elements

I'm building custom libraries to handle GUI and creating divs and stuff programatically. I also want to extend these objects with children and methods to do something like this:
Function CustomElement() {
this = document.createElement('div');
///--------
Some custom properties
///--------
}
CustomElement.prototype.customMethod = function(args) {
///--------
Some code here
///--------
};
var elem = new CustomElement();
document.body.appendChild(elem);
elem.customMethod(args);
I've thoroughly searched for an answer but found none. How can I accomplish this?
Note: I'm posting from my cell phone. Please excuse me if the code looks awful. I'll correct it as soon as I have access to a PC.
I appears you are confused between classical languages such that you are probably use to, and prototypical like languages such as Javascript.
Also, in your example, assigning the value of this is an invalid statement.
In Javascript, instead of creating children of a super class, we create objects that inherit the properties of other objects through the prototype chain. Still with me? This means that your customMethod is not technically a method, rather it is a property called customMethod which has the value of a function object.
Every constructor object (which is just a fancy name for your CustomElement function) has a magical property named prototype as you have discovered. Objects don't have this property, but they do have an implicit reference to their constructor's prototype object. This means you can call your customMethod as if it were a property of elem, but it is really a property of the constructors prototype object. So I guess you could say the prototype object is kind of like a parent and the object is kind of like a child (although this is incorrect terminology). This prototype object may also again have an implicit reference to it's constructor prototype, which may reference it's constructor prototype... and so on. That's why its called the prototype chain.
So to answer your question:
I also want to extend these objects with children and methods... How can I accomplish this?
For a suggestion to emulate child like inheritance, see below. However, your library requires a different approach...
A common angle of attack is to create a constructor which creates a new object, with a new Element object as a property of that object. For example:
function CustomElement(doesLikeTrains) {
// keep element in this property
this.nativeElement = document.createElement('div');
// other properties are separate
this.likesTrains = doesLikeTrains;
}
// these are also separate
CustomElement.prototype.doesLikeTrains = function() {
return this.likesTrains;
};
// Lets make objects!
var elem1 = new CustomElement(true);
var elem2 = new CustomElement(false);
// use object property and inherited properties
// we can still use the element ok
document.body.appendChild(elem2.nativeElement);
elem1.doesLikeTrains(); // prints true
elem2.doesLikeTrains(); // prints false :(
The DOM element assigned to the nativeElement property. This means you may add other properties without changing the native element object, but still have access to them. Both elem1 and elem2 inherit the same doesLikeTrains property with the same value, but each have their own likesTrains property, which is initialised in the constructor, and can keep a value specific to the object instance.
The advantage of this is that you could change the doesLikeTrains function to always return true, and because all objects created using your CustomELement constructor inherit the same prototype, all objects would then like trains regardless!
How would one create children like objects?
To emulate a child structure, consider...
function CustomOtherElement(likesTrains, runsOnCoal) {
// create new object and inherit from CustomElement
function EmptyConstructor() {}
EmptyConstructor.prototype = new CustomElement(likesTrains);
// add extra stuff to CustomOtherElements only
EmptyConstructor.runsOnCoal = runsOnCoal;
EmptyConstructor.isTrainSuperFan = function () {
return "Hoot hoot, chugga chugga!";
}
// return the new object
return new EmptyConstructor();
}
// now you can do
var elem3 = CustomOtherElement(true, true);
document.body.appendChild(elem3.nativeElement);
elem3.doesLikeTrains(); // true
elem3.isTrainSuperFan(); // "Hoot hoot, chugga chug!"
The above uses this new CustomOtherElement constructor to make an object that inherits CustomeElement and then add some new properties to this new object. Now you can use both the inherited properties from CustomElement and the new ones created on elem3! Happy Javascripting!
Resource: ECMAScript Language Specifications 5.1 section 4.2.1 (Objects)
Consider the approach sometimes called "parasitical inheritance". In this pattern, you write a constructor function, but return something else after adding methods/properties to it, such as
function CustomElement() {
var elt = document.createElement('div');
///--------
Some custom properties
///--------
elt.customMethod = function(args) {
///--------
Some code here
///--------
};
return elt;
}
var myCustomElement = new CustomElement();
This can be simpler, and more reliable, than trying to subclass HTMLElement, which can be a delicate operation, or wrapping the underlying HTML element, as other answers suggest.
Some might complain that the above approach is fat or slow because the "prototype" methods are being placed on each instance. However, that's something that's not really an issue on modern machines and browsers.
In any case, once we've come this far, we need to ask why we are trying to use constructors and new at all, when we can simply say:
function makeCustomElement() {
var elt = ...;
// set custom properties
// set custom methods
return elt;
}
var myCustomElement = makeCustomElement();
Defining a "subclass" is as simple as:
function makeCustomElementSubclass() {
var elt = makeCustomElement();
// set custom properties and methods
return elt;
}
In none of the cases above are prototypes being used (except methods on the built-in prototype such as HTMLElement). They're not really necessary. As I understand it, this is the direction in which mega-guru Douglas Crockford has gravitated in his style. Many cases where we see people using prototypes, it is a matter of "let me figure out a way to do this using prototypes, because they exist and I sort of think I'm supposed to be using them", or "let me figure out a way to do this using prototypes because they sort of behave like the classes I'm used to from C++/Java/C#", or "let me use prototypes to do this because putting methods once on prototypes is so much more efficient than putting them on each object"--but none of these are compelling reasons.

How to obtain true de-referenced object instances in javascript

I'm trying to get a better understanding of object oriented patterns in JavaScript. I particulary like the way EmberJS implements their classes with .extend and .create from Parent class Objects.
I've tried to implement a basic version of this on my own, but to no success, my newly instantiated Objects reference the same Object. I.e If I increment a private counter var in instance a via a public method, then separately do the same to instance b, b will reflect both increments.
I was able to achieve a de-referenced object via Object.create(myClass), however this is undesirable as I'd like to achieve this internally and also not rely on client support for that native method.
Here's a jsbin of what I've got: http://jsbin.com/zepaju/6/edit?js,console
Thanks for any help!
This is a pretty big subject, because there isn't a perfect way to make JavaScript work like Java-- you'll always have to invent some new coding idiom, and different people have different preferences.
Looking at your linked code, it's hard to be sure what you're gunning for but it looks like the problem is that you're thinking of an object's prototype as a "class", which is copied into each "instance" (like in Java)-- this isn't the case.
Your create() function is creating each "instance" by doing Object.create(Poll), which makes a new object with the Poll object as its prototype. When you refer to properties of the resulting objects, and those properties are not directly defined on the object, what you get is a reference to a property of the single Poll object.
The fact that you've sealed the Poll object's internal variables within a closure doesn't make any difference to this; the closure variables are hidden from the outside world, but they are accessible to the methods of the Poll object, and those methods are shared between all "instances".
If you want a function that spits out objects with a particular set of methods, and which hide their internal data in a closure, that might look like:
function Poll(challenger,incumbent) {
var challengerVotes=0;
var incumbentVotes=0;
return {
voteForChallenger: function() {challengerVotes++},
voteForIncumbent: function() {incumbentVotes++},
winner: function() {return challengerVotes>incumbentVotes ? challenger : incumbent}
}
}
var poll1 = Poll("Edward","Jacob");
var poll2 = Poll("Vanilla","Stilton");
poll1 and poll2 would not affect one another, and there would be no way to access the vote counts of either except through the supplied methods. I appreciate you're looking for a more generic approach but this is an example of how you might start.

How to deal with and discern inheritance conflicts in JavaScript?

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.

What is the use of creating a class in javascript, if I can insert any attritube to an object any time

Consider the below code.
I created an empty object. And am adding var1,var2,var3 without declaring them.
var har = new Object();
har.var1 = "Var1";
har.var2 = "Var1";
har.var3 = "Var1";
alert( har.var1 );
If I can do this, then why do I need to create a Class and fix the attributes when I can introduce new attributes anytime?
Why would you even need to use objects in the first place? Non-object-oriented languages are already Turing-complete, so everything you can accomplish with objects you can also do without them.
What you're showing in your example is not really an object, but just a dictionary. In cases like this, where you only need to keep several related properties together, anonymous unprototyped objects like the one you're using are the de-facto standard approach (though it is customary to initialize them with the shorthand syntax, e.g. var har = {}). It is an object, since it uses the object data structure, but it is not object-oriented.
Actual objects, in contrast, not only define data, but also the operations that you can perform on that data. Objects have not only properties, but also methods which work on these properties. These properties are usually defined in the object prototype (which you're calling "class", but Javascript is not a class-based language, but a prototype-based one). All methods defined in the prototype are shared between all instances of that prototype.
function Counter() {
this.counter = 0;
}
Counter.prototype.increment = function() {
this.counter++;
alert(this.counter);
}
var c1 = new Counter();
var c2 = new Counter();
c1.increment(); // alerts 1
c1.increment(); // alerts 2
c2.increment(); // independent from c1: alerts 1 again
Each instance is still a dictionary, as in your example (and you can even still add more properties to them, they are not "fixed" by having a constructor and prototype), but now it can also perform tasks on its properties. This can be done your way as well:
c1 = {
counter: 0,
increment: function() {
this.counter++;
alert(this.counter);
}
}
c2 = {
counter: 0,
increment: function() {
this.counter++;
alert(this.counter);
}
}
You can see, however, that if you need two counters, without using prototypes you will need to duplicate your entire object definition. This will be cumbersome to write and maintain, and each increment function will be defined separately, thus it will also waste memory.
That said, in cases where you need an object that you know you'll only ever need one instance of, it makes no sense to define a constructor and a prototype for it. Such objects are usually regarded as namespaces instead of actual objects.
Appendix: Dictionaries vs Objects
A dictionary is a data structure which holds named elements. Besides "dictionary", they are also called associative arrays or hashmaps. Objects in Javascript are implemented as dictionaries — each property is a named element in the dictionary. In addition to a plain dictionary, objects also have a prototype, which is kind-of like a parent object — when you look up a named element in the dictionary and it is not there, it is automatically searched for in the prototype as well. This way, default properties and methods are defined only once in the prototype, and do not need to be copied into each instance. (The prototype of an object is often visible as the instance.__proto__ property, though this is non-standard and deprecated even in browsers that support it; the actual prototype is defined as an internal, non-accessible property by the standard)
So, Javascript objects are actually dictionaries. When you want to use a plain dictionary to store some related properties together, there is no separate syntax in Javascript to create a dictionary that is not an object, so you create an instance of the base Object type to hold your dictionary (it does not matter if you do var dict = new Object or var dict = {}, the result is the same); thus, dictionaries that you use in your code are also objects.

Categories

Resources