I was actually practicing creating classes and instances of them using the new keyword and this came to my mind.
Suppose I have a superclass called Customers and I have two subclasses which are newCustomers and specialCustomers.
Suppose that I have a new customer called bob ==> var bob = new newCustomer();
and I have a special customer called smith ==>>
var smith = new specialCustomer();
How can I write a method that when assigned to bob, it moves him from being a newCustomer instance to a specialCustomer instance?
like for example, what code should I write to make this work:
bob.moveToSpecial() //moves bob from being instance of newCust to specialCust
An object is not an instance of a class, an object has a prototype based upon the constructor called.
What you can do (although it may lead to side-effects) is changing the prototype of that object:
bob.__proto__ = specialCust.prototype;
Read about the warnings when doing this here: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
A better way is to create a new object and move all properties from bob there:
newBob = new specialCust();
for(var prop in bob){
newBob[prop] = bob[prop];
}
Be aware that in both cases, bob loses his "inherited" methods and properties from the old prototype, although in the latter case only the non-enumerable ones (as stated in the comments). The enumerable ones will get copied and bound to the new object directly, possibly overriding inherited methods, so be aware of that, too.
Also worth reading: https://reinteractive.com/posts/235-es6-classes-and-javascript-prototypes
[edit] Example code with Object.keys:
newBob = new specialCust();
Object.keys(bob).forEach(function(prop){
newBob[prop] = bob[prop];
});
Related
please help me get it straight, I see every object in javascript leads to object Object in prototype chain and then to null, in console.log we can see properties and methods of objects but never its implementation, i wonder if this Object is a top-level object where all built-in are stored, is that so?
thank you all for answers!
Javascript is an object-based language. Which means that "everything" inherits from an Object, except Object itself, the top of the prototype chain is null. When you declare an array, you can use .lenght because that is defined in the prototype attribute. There are some exceptions, such as int, floats, etc.
In fact, when you run a console, you can see every method from its parents. Try creating a Constructor for a new object, let's say, for example:
var Person = function(name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
Add a method to this Person's prototype:
Person.prototype.calculateAge = function() {
console.log(2016 - this.yearOfBirth);
};
And create an instance of this new "class":
var sarah = new Person('Sarah', 1994, 'programmer');
Now go to the console on your browser and type sarah to see it's methods and variables. You'll notice that variables that are exclusive for John will appear on the first drop-down, but you'll also notice that John does not have calculateAge attached directly to it. That's because it's in its prototype, search for something called _proto_ and you'll see this method and also a construct and guess what else? Another _proto_, this time, it's the proto from Person's parent, or, in other words, the Object.
There you can find most of the methods from the Object itself.
Prototypes are what makes inheritance possible in javascript
Perhaps you want to look at ECMA specifications?
http://www.ecma-international.org/publications/standards/Ecma-262.htm
Each browser may have its own implementation of Javascript. Maybe something like this repo will help.
https://github.com/v8/v8
I've just started to learn Javascript.
As per my understanding so far, you can declare class/static variables in two ways. The 1st way:
Blog.prototype.signature = "By Blogger-Name";
And the 2nd way:
Blog.signature = "By Blogger-Name";
By using the first method, the variable signature is available to all instances of Blog.
However, a variable that remains the same value for all instances of a class should really not be an instance variable. As I see it, class/static variables should be declared using the second method only.
Hence, my question is, is there a scenario where one would be required/forced to declare variables the first way? Or is my understanding of all of this lacking in any way? Please let me know.
EDIT: In what instances is the first method preferred and, similarly, in what instances is the second method preferred?
EDIT 2: So I've learnt that the first method actually adds instance properties with a default value. This can also be achieved by setting a default value in the constructor itself. So when would adding a property this way (i.e. using prototype) be preferred?
Hence, my question is, is there a scenario where one would be required/forced to declare variables the first way?
The only thing that comes to mind would be if you needed to allow for code using an object created via new Blog to access the property without knowing the constructor function's name. E.g.:
function useABlogInstance(blog) {
// Here, assume I don't know that `blog` was created via `new Blog`
console.log(blog.signature);
}
Although a canny user could do
console.log(blog.constructor.signature);
to access Blog.signature (assuming you maintain the constructor backlink), that wouldn't be very clean. :-)
It's important to note that a property on Blog.prototype isn't a "class" or "static" property, it's an instance property (on the Blog.prototype object). While it's true that reading that property from an object created via new Blog will find it on the prototype (if the instance doesn't have its own signature property), the results of writing to the property are very, very different. Consider:
function A() {}
A.prototype.prop = "prototype prop";
var a1 = new A();
var a2 = new A();
snippet.log(a1.prop); // "prototype prop"
snippet.log(a2.prop); // "prototype prop"
a1.prop = "updated";
snippet.log(a1.prop); // "updated" -- because `a1` has its own `prop` property
// now and no longer uses the prototype's
snippet.log(a2.prop); // "prototype prop"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Contrast that with:
function B() {}
B.prop = "B prop";
var b1 = new B();
var b2 = new B();
snippet.log(b1.constructor.prop); // "B prop"
snippet.log(b2.constructor.prop); // "B prop"
snippet.log(B.prop); // "B prop"
b1.constructor.prop = "updated";
snippet.log(b1.constructor.prop); // "updated"
snippet.log(b2.constructor.prop); // "updated"
snippet.log(B.prop); // "updated"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
For "class"-wide information, I would always use Blog.signature, not Blog.prototype.signature. I'd use Blog.prototype.signature for instance-specific default properties where the values are primitives or functions (but not non-function objects or arrays, I'd set those up in the constructor function).
Side note: You're not declaring a variable in either of your code snippets. You're adding a property to an object. In the first snippet, you're adding the property to the object that will get assigned as the prototype of objects created via new Blog. In the second case, you're adding a property to the Blog object (functions are objects). Neither is a variable, in both cases it's a property.
There are no class variables in Javascript. Actually, there are no classes altogether in Javascript. Thinking in terms of classes and static variables (are you a Java dev?) won't let you know what's going on. Even if the concept of "a class" is independent of the programming language to some degree, it is important to understand that it's not a fundamental programming construct - and in fact there are languages without classes, like Javascript.
Javascript is a very simple language: it has functions and dictionaries, and has the syntax to combine both and support programming the object-oriented way. Take this example:
var johnSnow = { first: "John", last: "Snow" };
function fullName(character) {
return character.first + " " + character.last;
}
console.log(fullName(johnSnow));
And now the OO version:
var Character = function(first, last) {
this.first = first;
this.last = last;
}
Character.prototype.fullName = function() {
return this.first + " " + this.last;
}
console.log(new Character("John", "Snow").fullName());
Finally we can answer your question: when should you set a property on a constructor and when you should use an instance?
Set the property on the instance when they should not be shared with other instances (obviously). You recognize these properties because often are used in instance methods and read with this.$name
Set the property on the constructor... never! Properties set on constructors are simply global variables. So just use global variables, possibly namespacing them (but obviously you'll need a global at some point!)
I guess it all depends on how you want to access the signature variable.
If you want an easy access to it from a Blog instance, use the prototype versions. Then you can do:
var blog = new Blog;
console.log(blog.signature);
Otherwise, you'll have to use Blog.signature or blog.constructor.signature.
I wouldn't worry about making signature an instance variable when you put it in the prototype because that's not what you're doing.
Blog.prototype doesn't get copied around -- it's not something every instance would have its own private copy of. It's a shared object that blog objects (=objects created with new Blog) will have set as their __proto__ (=Object.getPrototypeOf(blog)). __proto__ will be used to search for properties (that includes functions) that are not direct attributes of the instance.
A __proto__ can be overriden by setting an actual instance variable:
var Blog = function () {};
Blog.prototype.signature = "Original sig";
var blog = new Blog();
blog.signature === "Original sig"
//^looked up in Blog.prototype === Object.getPrototypeOf(blog) === blog.__proto__
blog.signature = "New sig"
//^set as an instance property
blog.signature === "New sig"
Blog.prototype.signature !== "New sig" //actual instance properties override prototype properties, but they don't over-write them
var blog2 = new Blog()
blog2.signature === "Original sig"
A classical object-oriented programming language such as C++/Java does a very similar thing, actually. Objects in C++/Java have properties and methods, and methods behave as if they were function pointer properties of instances, but they're not. Methods don't add any size to instances. They're all looked up in a shared place--your class's prototype if you will. The difference is, that in C++/Java the link doesn't exist at runtime (it's maintained by the compiler) and is only for methods. In JavaScript, each object has a real link to a class-shared lookup place (the object's constructor's prototype attribute), the link is accessible via either the objet's __proto__ attribute or more standardly via what you get with Object.getPrototypeOf(someobject), and it's not only for methods (like in C++/Java) but for properties as well.
The only difference between foo1 = {} and foo2 = new Bar is the fact that foo1.__proto__ == Object.prototype, whereas foo2.__proto__ == Bar.prototype. In JavaScript there are no classes and no instances, only plan objects.
Now, if you set Bar.prototype.property = "value", then looking up foo2.property first checks, whether foo2 has its own property called property. If it does not, it continues with foo2.__proto__ until it finds an object that does have an own property called property or until it gets to an object, whose __proto__ is null (usually Object.prototype).
It should now be obvious that by declaring Bar.prototype.property, you are setting up the default value, which looking up foo2.property resolves to, when it doesn't have its own property property. Setting up foo2.property in the constructor defines foo2's own property. You could call it an instance variable, but really, it's just a hash map key.
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 was reading a JavaScript book and as I was reading a chapter about inheritance, I wondered if every time you create a instance of a object is it really inheritance that happens, especially since they are similar.
Examples: Prototype Chaining - someObject.prototype = new someOtherObject();
Instantiating an object var myArray = new Array()
Similar right?
Additionally the book(JavaScript for web developers, By:Nicholas Zakas) stated, a link exists between an instance and a constructor's prototype.(The link is usually known as __proto__)
So can one argue that instantiating a object is like inheritance?
No. You are confused because one of the methods of accomplishing inheritance (viz. prototypal inheritance) takes, as the prototype, a given object. And one method of acquiring objects is via constructors.
In other words, there is nothing special about someObject.prototype = new SomeOtherObject(). You could just as well do
someObject.prototype = { myObjectLiteral: "isJustAsGoodAsYourConstructoredInstance" };
or even someObject.prototype = false. The two operations, very literally, have nothing to do with each other.
EDIT To address the quote OP found in his book:
"Recall the relationship between
constructors, prototypes, and
instances: each constructor has a
prototype object that points back to
the constructor, and instances have an
internal pointer to the prototype."
Unfortunately, this is misleading at best, and plain wrong at worst. Consider what "each constructor has a prototype object that points back to the constructor" would mean. It would mean that, for example,
Array.prototype === Array
Function.prototype === Function
function CustomConstructor() { }
CustomConstructor.prototype === CustomConstructor
But all of these statements output false if you type them in your console.
Now consider "instances have an internal pointer to the prototype." This is true, but does not fit with the terminology he is using. What this means is:
var myProto = {};
function CustomConstructor() { }
CustomConstructor.prototype = myProto; // inherit from the myProto object.
var x = new CustomConstructor(); // x is an "instance"
Object.getPrototypeOf(x) === myProto; // Object.getPrototypeOf fetches the "internal pointer"
But as you can see, I didn't inherit using a constructor, as I tried to point out above. Instantiating an object is not inheritance in any way. It is simply that the prototype property of constructors is how prototypal inheritance is accomplished, just like classical inheritance is accomplished by placing extends BaseClass after a class definition in Java. In turn, this difference is present because prototypal inheritance lets you inherit a prototype object instance, not a base class.
The JavaScript Garden has a few good sections that might help if you want more information. Relevant are "The Prototype," "Constructors," and "The instanceof Operator."
Without using objectType.inherits() if I got your concept of inheritance then it is if you take just the right part:
new someOtherObject()
This is instantiation of someOtherObject.
What happens here is you are creating an object of type someOtherObject that inherits structure from an empty object (provided you have not set a prototype on this). Because the default value of prototype is an empty object {}.
You are putting this object as prototype of someObject:
someObject.prototype = new someOtherObject();
Now if you create an instance of someObject this will happen:
You create someObject that inherits the structure of someOtherObject in that point in time, which inherits the structure of (empty)object when it has been instanced.
Maybe a better explanation is saying that the instance gets extended with the structure of its prototype at that point in time, and leave all of the inheriting wording aside, since just using that can mislead. Since classic inheritance uses base classes (types) and proto uses instances of those. Now it all depends on how you look at inheritance, which to argue about does not exists at all in javascript (object types are mutable at runtime) as by Karl Marx argues that real communism is not possible at all in the concept. If you agree with this last statement then comparing and asking about it does not matter, because neithercase is.