In JavaScript what is the difference between these two examples:
Prerequisite:
function SomeBaseClass(){
}
SomeBaseClass.prototype = {
doThis : function(){
},
doThat : function(){
}
}
Inheritance example A using Object.create:
function MyClass(){
}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
Inheritance example B using the new keyword
function MyClass(){
}
MyClass.prototype = new SomeBaseClass();
Both examples seem to do the same thing. When would you chose one over the other?
An additional question:
Consider code in below link (line 15), where a reference to the the function's own constructor is stored in the prototype. Why is this useful?
https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js
Excerpt (if you don't want to open the link):
THREE.ImageLoader.prototype = {
constructor: THREE.ImageLoader
}
In your question you have mentioned that Both examples seem to do the same thing, It's not true at all, because
Your first example
function SomeBaseClass(){...}
SomeBaseClass.prototype = {
doThis : function(){...},
doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
In this example, you are just inheriting SomeBaseClass' prototype but what if you have a property in your SomeBaseClass like
function SomeBaseClass(){
this.publicProperty='SomeValue';
}
and if you use it like
var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);
The obj object won't have publicProperty property like in this example.
Your second example
MyClass.prototype = new SomeBaseClass();
It's executing the constructor function, making an instance of SomeBaseClass and inheriting the whole SomeBaseClass object. So, if you use
var obj=new MyClass();
console.log(obj.publicProperty); // SomeValue
console.log(obj);
In this case its publicProperty property is also available to the obj object like in this example.
Since the Object.create is not available in some old browsers, in that case you can use
if(!Object.create)
{
Object.create=function(o){
function F(){}
F.prototype=o;
return new F();
}
}
Above code just adds Object.create function if it's not available so you can use Object.create function and I think the code above describes what Object.create actually does. Hope it'll help in some way.
Both examples seem to do the same thing.
That's true in your case.
When would you chose one over the other?
When SomeBaseClass has a function body, this would get executed with the new keyword. This usually is not intended - you only want to set up the prototype chain. In some cases it even could cause serious issues because you actually instantiate an object, whose private-scoped variables are shared by all MyClass instances as they inherit the same privileged methods. Other side effects are imaginable.
So, you should generally prefer Object.create. Yet, it is not supported in some legacy browsers; which is the reason you see the new-approach much too frequent as it often does no (obvious) harm. Also have a look at this answer.
The difference becomes obvious if you use Object.create() as it is intended. Actually, it does entirely hideout the prototype word from your code, it'll do the job under the hood. Using Object.create(), we can go like
var base = {
doThis : function(){
},
doThat : function(){
}
};
And then we can extend/inherit other objects from this
var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally
So this is another concept, a more "object oriented" way of inherting. There is no "constructor function" out of the box using Object.create() for instance. But of course you could just create and call a self defined constructor function within those objects.
One argument for using Object.create() is that it might look more natural to mix/*inherit* from other objects, than using Javascripts default way.
I am not an expert in java script but here is a simple example to understand difference between "Object.create" and "new" ..
step 1 : create the parent function with some properties and actions..
function Person() {
this.name = 'venkat';
this.address = 'dallas';
this.mobile='xxxxxxxxxx'
}
Person.prototype.func1 = function () {
return this.name + this.address;
}
step 2 : create a child function (PersonSalary) which extends above Person function using New keyword..
function PersonSalary() {
Person.call(this);
}
PersonSalary.prototype = new Person();
PersonSalary();
step 3 : create second child function (PersonLeaves) which extends above Person function using Object.create keyword..
function PersonLeaves() {
Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);
PersonLeaves();
// Now check both child functions prototypes.
PersonSalary.prototype
PersonLeaves.prototype
both of these child functions will link to Person(parent function) prototype and can access it's methods but if you create child function using new it will return a brand new object with all parent properties which we don't need and also when you create any object or function using "New" that parent function is executed which we don't want to be.
Here are the takeaways
if you just want to delegate to some methods in parent function and don't want a new object to be created , using Object.create is best way.
A couple of additions to this answer set, mindful that JS obviously now has native classes:
In both Example A and Example B the static inheritance chain is not configured.
In Example B the superclass constructor is run at the "wrong time". It is run before the call to instantiate an instance of the subclass, before any arguments are known and perhaps before you have decided to instantiate an instance of the subclass. Note that constructors can contain any logic they like, including side-effectful logic, so this can be impactful.
Post-ES6 the inheritance chain can be configured in a standardised way using the class and extends keywords (which solve both of these issues).
See also.
Related
When using inheritance, what is the difference and which approach would be better between ChildObject.prototype = new ParentObject(); or ChildObject.prototype = ParentObject.prototype;.
I have seen ChildObject.prototype = new ParentObject(); in a Douglas Crockford example.
Neither of those.
Instead:
ChildObject.prototype = Object.create(ParentObject.prototype);
ChildObject.prototype.constructor = ChildObject;
combined with this line at the beginning of ChildObject:
ParentObject.call(this/*, appropriate args if any*/);
or if passing along all args:
ParentObject.apply(this, arguments); // `arguments` literally -- it's provided by the JavaScript engine
The problem with ChildObject.prototype = new ParentObject(); is that it won't work if ParentObject expects arguments, as many (most?) constructors do. So the pattern doesn't work in a common (possibly majority) case.
The problem with ChildObject.prototype = ParentObject.prototype; is that then you have both of them pointing at the same object. So setting a property on ChildObject.prototype makes it show up on instances of ParentObject (since you've just set it on ParentObject.prototype as well).
The Object.create version defers calling ParentObject until you have an object to initialize, but gives you an object on which you can put the things specific to ChildObject instances. (The constructor backlink is to make the replacement object look like the default one ChildObject originally had; that didn't used to matter much, but it's actually used now by ES6 in some cases, and some libs used it before even if ES5 and earlier didn't [they just put it there].)
Finally: The single-argument version of Object.create can be shimmed for obsolete browsers from before 2009 when it was added in ES5, or you can use a factory function instead if you don't like partially-shimming things:
function objectCreate(proto) {
function ctor() { }
ctor.prototype = proto;
return new ctor;
}
We usually use prototypes to supply methods - to avoid duplicating the same function for each instance of class. In other words, for something like...
ChildObject.prototype.foo = function() {
console.log('foo');
};
Now you probably see the problem with the second approach: modifying ChildObject.prototype will modify ParentObject.prototype as well (it's the same object after ChildObject.prototype = ParentObject.prototype line). That means all ParentObject in this example will have foo method available to them. Actually, it's not even correct to say that ParentObject is parent of ChildObject - both have the same prototype chain.
Yet there's another nasty side effect. Consider this:
function ParentObj() {}
function ChildObj() {}
ChildObj.prototype = ParentObj.prototype;
var i = new ParentObj();
console.log(i); // ParentObj {}
var j = new ChildObj();
console.log(j); // ParentObj {}
See, both prototypes, as they are the same object, have the same constructor property. So to distinguish between those, we'll have to introduce some flags in the constructor functions, essentially overriding the already existing mechanism.
If you do
ChildObject.prototype = ParentObject.prototype;
then your parent and child have the same prototype. With the latter,
ChildObject.prototype = new ParentObject();
the child's prototype is the parent itself.
In Simple words why we use prototype.constructor. I am reading an article about inheritance where I saw prototype.constructor. I see no difference in result when I comment that code. So my question why and when to use it practically.
function Mammal(name){
this.name=name;
this.action= function (){
alert('0')
}
}
function Cat(name){
this.name=name;
}
Cat.prototype = new Mammal();
//Cat.prototype.constructor=Cat; // Otherwise instances of Cat would have a constructor of Mammal
Cat.prototype.action=function(){
alert('1')
}
var y= new Mammal()
var x= new Cat()
y.action()
x.action()
It's mostly convention. Although nothing in JavaScript itself uses the constructor property, sometimes people use it in their code, assuming that it will refer back to the object's constructor. It's not just convention anymore, see ¹ for details.
When you create a function:
function Cat() {
}
The function starts out with an object on its prototype property that has a property called constructor that points back to the function:
console.log(Cat.prototype.constructor === Cat); // true
This is in the specification. (It's also the only place in the specification that property is mentioned — e.g., JavaScript, itself, makes no use of this property at all. Not anymore.¹)
Consequently, instances created with that prototype (whether created via the constructor function or other ways) inherit that constructor property:
var c = new Cat();
console.log(c.constructor === Cat); // true
var c2 = Object.create(Cat.prototype);
console.log(c2.constructor === Cat); // true, even though Cat wasn't used
When you replace the prototype property on a function, as you typically do when building hierarchies:
Cat.prototype = new Mammal(); // This is an anti-pattern, btw, see below
...you end up with an object on Cat.prototype where constructor points to Mammal. Since that's not what one normally expects, it's customary to fix it:
Cat.prototype.constructor = Cat;
Although nothing in JavaScript itself uses the property (it does now¹), sometimes people use it in their code, assuming that it will refer back to the object's constructor.
Re the anti-pattern in that code: When using constructor functions to build a hierarchy, it's not best practice to actually call the "base" constructor to create the "derived" constructor's prototype. Instead, use Object.create to create the prototype:
Cat.prototype = Object.create(Mammal.prototype);
Cat.prototype.constructor = Cat;
...and then chain to Mammal in Cat:
function Cat() {
Mammal.call(this);
// ...
}
Why do it that way? Consider: What if the base requires arguments you won't get until construction-time to meaningfully initialize an instance? You can't pass it arguments until you have them. The pattern above allows you to handle that situation.
Note that Object.create was added in ES5 and so is missing from some old browsers (like IE8). The single-argument version of it can be shimmed/polyfilled trivially, though:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw new Error("The second argument of Object.create cannot be shimmed.");
}
function f() { }
f.prototype = proto;
return new f;
};
}
I'll just note that constructor functions are just one way of building object hierarchies in JavaScript. They're not the only way, because JavaScript uses prototypical inheritance. JavaScript is so powerful you can use constructor functions to get something similar to class-like inheritance, but it also lets you do more traditional prototypical-style inheritance directly.
¹ "Although nothing in JavaScript itself uses the constructor property..." That's not true anymore as of ES2015 (aka "ES6"). Now, the constructor property is used in a couple of places (such as the SpeciesConstructor and ArraySpeciesCreate abstract operations), which are used in various classes that have methods returning new instances of the class, such as Array#slice and Promise#then. It's used in those places to ensure that subclasses work correctly: E.g., if you subclass Array, and use slice on an instance of the subclass, the array returned by slice is an instance of your subclass, not a raw Array — because slice uses ArraySpeciesCreate.
The other day I was fiddling with Javascript, and I noticed that I can't write a prototype to an object within a prototype function. Like this:
var obj = function() { }
obj.prototype.First = function() {
this.prototype.Second = function() {
alert("Second Prototype");
}
}
obj.First();
obj.Second();
For some reason, the second prototype won't work and the code doesn't run. Is my syntax wrong or are there some prototype limitations that I don't know about? Thanks!
Edit:
I'm not trying to add a prototype to a prototype... that wouldn't make much sense. This is what I'm trying to do: Add two separate prototypes to obj. Prototype 2 is defined when prototype 1 is called. I thought that this would contain a reference to object, so this.prototype would be the same as obj.prototype, but it doesn't work as expected.
This is an old question, but I thought I'd add my two cents.
This code is trying to add functions on 'prototype'. However, this can only be done on the class name. What you have is a variable pointing to an anonymous class. To access the variable of an anonymous variable use 'proto'. The below is the same as your example, except, using proto it is 'successful'. Although, I don't see the benefit of using prototypes like this as the prototype added methods only apply to the anonymous instance 'obj'. http://jsbin.com/zapocamipi/edit?js,console
var obj = function() { }
obj.__proto__.First = function() {
console.log("First Prototype");
this.__proto__.Second = function() {
console.log(this);
}
}
obj.First();
obj.Second();
Maybe this could help you out understanding the role of a constructor function and the prototype.
Depending on what you're trying to do (obj, First and Second doesn't really show your intention) you could do:
A Person has Eyes. This can be done through composition.
An Employer is a Person but a Person is not necessarily an Employer (can be Client or Consultant too). This could be done through inheritance.
A Cat can move. In a Class based language Cat has to implement Movable but in JavaScript you can use mix ins and leave the implementation to the default implementation that Movable provides or override it. JavaScript does not compile time check if you do implement certain things.
If you would like to change the type of the object instance after calling a certain function then it's dangerous to meddle with the prototype because that will affect all instances of that type.
Maybe you should return an instance of another type.
var Customer = function(name) {
this.name=name || 'unknown';
};
Customer.createVipCustomer = function() {
return new VipCustomer(this);
}
var VipCustomer=function(customer){
//re use Customer constructor
Customer.call(this,customer.name);
this.isVip=true;
}
//inherit the protype defined members
VipCustomer.prototype=Object.create(Customer.prototype);
VipCustomer.prototype.constructor=VipCustomer;
VipCustomer.prototype.second=function(){
console.log('this is second');
}
var aCustomer = new Customer('Ben');
//update to VipCustomer
aCustomer = Customer.createVipCustomer(aCustomer);
aCustomer.second();
this.prototype doesn't exist.
If you want to add a property to the instance, use this.
If you want to add a property to the prototype, use Constructor.prototype.
Also, obj is a function (class), not an instance,
You want to create an instance using the new keyword, and you should name the constructor function as UpperCamelCase.
I was wondering - what's the difference between JavaScript objects, classes and functions?
Am I right in thinking that classes and functions are types of objects?
And what distinguishes a class from a function? Or are they really the same thing, just the term for them changes according to how they are used?
function func() { alert('foo'); } // a function
func(); // call the function - alerts 'foo'
var func2 = function () { alert('hello'); } // acts the same way as 'func' surely?
func2(); // alerts 'hello'
var Class = function() { alert('bar'); }; // a class
var c = new Class(); // an istance of a class - alerts 'bar'
Sure, classes have methods and properties and can be instantiated - but then, I could do the same with any old function - or not?
As you must already be aware by now there are no classes in JavaScript. Instead functions in JavaScript may be made to behave like constructors by preceding a function call with the new keyword. This is known as the constructor pattern.
In JavaScript, everything is an object except for the primitive data types (boolean, number, and string), and undefined. On the other hand null is actually an object reference even though you may at first believe otherwise. This is the reason typeof null returns "object".
Functions in JavaScript are similar to functables in Lua (i.e. they are callable objects). Hence a function can be used in place of an object. Similarly, arrays are also objects in JavaScript. On the other hand, objects can be thought of as associative arrays.
The most important point however is that there are no classes in JavaScript because JavaScript is a prototypal object-oriented language. This means that objects in JavaScript directly inherit from other objects. Hence we don't need classes. All we need is a way to create and extend objects.
Read the following thread to learn more about prototypal inheritance in JavaScript: Benefits of prototypal inheritance over classical?
Update 2015
There are classes in JavaScript they just aren't used on older browsers:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
It has constructors, extensions, and the like.
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
A Class in JS:
function Animal(){
// Private property
var alive=true;
// Private method
function fight(){ //... }
// Public method which can access private variables
this.isAlive = function() { return alive; }
// Public property
this.name = "Joe";
}
// Public method
Animal.prototype.play = function() { alert("Bow wow!"); }
// .. and so on
Now when you create it's object
var obj = new Animal();
You can expect anything of this object as you would from objects in other language. Just the efforts to achieve it, was a bit different. You should also be looking at inheritance in JS.
Getting back too your question, I'll reword it as:
//Class : A representation of a set with common properties.
//object : One from the set with the same properties.
var Class = function() {alert('bar');}; // A set of function which alert 'bar'
var object = new Class(); // One of the functions who alert's 'bar'.
JavaScript does not have classes, and functions are actually objects in JavaScript (first-class citizens).
The only difference that function objects have is that they are callable.
function func() { alert('foo'); } // a function - Correct
func(); // call the function - alerts 'foo' - Correct
var func2 = function () { alert('foo'); } // same as 'func' surely? - Nope, func2 is a different object, that apparently does the same thing when called.
var Class = function() { alert('bar'); }; - It's a function with no name stored in variable Class.
var c = new Class(); - Calls function stored in Class supplying new empty object as this and returning that object. Functions called as new functionA() are expected to work as constructors and prepare a newly created object (this). In your case - constructor does nothing with the object and just alerts bar.
You also get classes in ES6 that look like this:
//class
class Cat {
//constructor
constructor() {
this.name = 'Snowball';
}
//method
meow() {
console.log('Hello, nyah! My name is ' + this.name + ' nyah!~');
}
};
There are no classes in javascript. But, there are ways to make a function to behave like a class in other languages.
A very good explanation is given here 3 way to define a class in js
Also, found a very good reference for OOP in Javascript
Object is the base type in JavaScript i.e. all the user defined data types inherits from Object in one way or another. So if you define a function or a class [note as of now JS doesn't support class construct, but its proposed in ECMAScript version 6], it will implicitly inherit from Object type.
Classes are really used for encapsulating logical functions and properties into one type / entity and you can 'new' it up using constructor syntax. So if you define a 'Customer' class, you can instantiate it multiple times and each instance / object can have different values. They can even share the values if you define class level value using prototype.
Since JS doesn't support class construct at the moment, functions can really act as individual method as well as container for other functions or types.
I hope with ECMAScript 6 we will have clear separation between these constructs similar to what we have in other languages like C#, Java etc.
If I have a function say:
var my_function = function()
{
}
If the function is not called, it is not taking up memory, it is just text sitting in memory.
However if you call it by say...
function_instance = new my_function();
It is instantiated is a sort of way, and the variables and methods it contains are loaded into memory.
Is this a way to represent a class/object model similar to C++?
Is my interpretation correct?
In javascript, the class concept does not exist. Everything is an object. When you use the new operator it copies the prototype of that function into a new object. In other words, you can emulate what class can do in c++, but it's not a class.
"a way to represent a class/object model similar to C++" would be through the use of prototypes.
As Kevin M pointed out, you can use the this keyword to create instance variables in a function, like so:
var my_function(foo)
{
this.foo = foo;
this.bar = function()
{
// bar-ing here
}
}
The problem however, that whenever you instantiate my_function(), a new instance of the my_function.bar function is also created. Enter prototypes:
var barPrototype = { "bar" : function()
{
// bar-ing here
}
};
var my_function(foo)
{
this.foo = foo;
}
my_function.prototype = barPrototype;
So, to sum it all up, the prototype keyword can be used to create function-specific, inheritable properties that are analoguous to C++'s member functions. Member functions of C++ aren't instantiated for each instance of a class. Instead, the compiler adds a this pointer to the function's parameters; this pointer points to the instance that the member function is called on.
More JSey fun to be had here: http://javascript.infogami.com/Javascript_in_Ten_Minutes
In JavaScript a new class is defined by creating a function. The function may contain other functions (methods), properties, etc.
When a function is called using the new operation the function becomes a constructor for that class. Inside the constructor the variable " this " is created and points to the object.
function Man(){
this.name = 'John';
}
var person = new Man;
console.log(person.name);
As mentioned, Javascript functions can act as objects so Javascript can be object oriented but object inheritance is prototypical and not like C++. John Resig, the creator of jQuery, has done some work on emulating traditional classes and inheritance in javascript. You could take a look at his blog for an interesting example:
http://ejohn.org/blog/simple-javascript-inheritance/