seen this JavaScript pattern in some large projects, which "copies" or "implements" ClassA's properties to ClassB, but couldn't figure out what is the purpose of calling ClassA's empty constructor inside ClassB's constructor using ".call()" while passing the ClassB instance as "this" binding?
var ClassA = function() {
//this function is totally empty
};
ClassA.prototype = {
jump: function() {...some code...},
dance: function() {
if (this.canDance) {
alert("dance");
}
}
};
ClassA.implementOn = function(targetClassOrObject) {
for ( var prop in ClassA.prototype ) {
targetClassOrObject[ prop ] = ClassA.prototype[ prop ];
}
};
var ClassB = function() {
this.canDance = true;
ClassA.call(this); // <------------What's the purpose of this line?
};
ClassA.implementOn(ClassB.prototype);
var instanceOfB = new ClassB();
instanceOfB.dance();
If the ClassA constructor is empty, there's no big surprise here -- calling ClassA's empty constructor does absolutely nothing.
The moment you decide you want ClassA's constructor to be non-empty, however, you'll see that line now has a tremendously important effect: constructing a ClassB object also invokes the ClassA-specific constructor behaviors in the context of newly-constructed ClassB object, which is what you'd expect if ClassB is a logical "subclass" of ClassA.
(Of course, JavaScript doesn't have proper "subclasses", but this is obviously an attempt to implement class-based behavior in the language.)
purpose of calling ClassA's empty constructor inside ClassB's constructor using ".call()"
To have the script still working when ClassA will not be empty. Of course, currently it does nothing, but that might change in future. So it is good practise to implement the full inheritance pattern, making it easier to change the code later without introducing bugs.
Once ClassA changes to implement custom instance-specific properties - which are set up in the constructor, you want to have them on ClassB instances as well. Therefore, you invoke the ClassA constructor on ClassB instances as well during their initialisation.
If the ClassA constructor is empty (like in your example code), then yeah, it does nothing.
The reason you see this pattern though, is for the times when it's not. It's analogous to a super call in a class-based OO language.
If you have to do some work in the ClassA constructor to get an object that's in a correct state, it's likely you'll want to do the same work in a "subclass". Just copying the prototype's properties may not be enough.
With .call, you can change the value of this in the called method to the argument you specify. ClassA.call(this) calls the ClassA constructor with ClassB as the context. This allows you to use the properties of ClassB in ClassA methods. The methods are all copied to ClassB via ClassA.implementOn.
You will notice that (new ClassA()).dance() does nothing, but (new ClassB()).dance() alerts "dance" because this.canDance is true.
Demo: http://jsfiddle.net/5v7xh/
Related
I want to pass child class instance to super class using super's constructor but I'm get this error
super(this);
this is not allowed before superclass constructor invocation
Why i'm getting this error , also how could I resolve this issue
class Parent
{
constructor(child)
{
this.child = child;
}
//...somewhere in code
//child.doSomething();
}
class Child extends Parent
{
constructor()
{
super(this); // <==== the error here
}
doSomething = () =>
{
//...
}
}
There's no need to pass this to super() because this inside the superclass constructor will be a reference to the same object. Recall that your class hierarchy will cooperate to perform initialization on a single new object.
Calls to super() must come before any reference to this, including in the super() argument list. Why? Because in order to mimic behavior of other OO languages, it must be the case that the top-most initializer in the class hierarchy gets its hands on the new object first. The parent (or "senior") initializer should be able to assume that prototype methods at that level have the semantics the base class expects, since it doesn't "know" what subclasses might have done with their prototypes etc. If a subclass initializer could modify the new object and override a base class prototype method (or something else of that flavor), it'd be chaos.
In the child's constructor method, the parent's constructor must be called before accessing this. The superclass' constructor will have access to this anyway, since you are constructing an instance of the superclass - though it will not have access to any other initialization that your child constructor may yet do.
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.
I am learning the js prototype, and I am wondering if there are any differences between the following two segment?
Segment1:
function SuperType(){
this.color=["blue","yellow"];
}
function SubType(){
}
Subtype.prototype = new SuperType();
Segment2:
function SuperType(){
this.color=["blue","yellow"];
}
function SubType(){
SuperType.call(this);
}
and if the above two does the same thing, then why some codes bother to do this:
function SubType(){
SuperType.call(this);
}
SubType.prototype=new SuperType();
Yes, there are differences.
In Segment 1, the subclass SubType does not call the constructor of SuperType so it never gets executed. Segment 1 is not a correct general purpose way to inherit from another object.
In Segment 2, the subclass SubType does call the constructor of SuperType so the statement this.color=["blue","yellow"]; gets executed, but the prototype is not set appropriately so any prototype items that SuperType might have had are not inherited. Segment 2 is not a correct general purpose way to inherit from another object.
Segment 1 would work properly if there was no code in the SuperType constructor (not the case in your example). As you show it, because the SuperType() constructor is not called, this.color would only be in the prototype and thus the same array would be shared by all instances which is generally NOT what you want. Calling the constructor properly would give every instance it's own copy of this.color, not a shared copy.
Segment 2 would work properly if nothing was added to the SuperType prototype and there are no constructor arguments for SuperType (happens to be the case in your example, but not a good general practice).
Neither is a good general purpose way of doing things.
Your last option is the proper general purpose way to do things because it both inherits from the prototype AND it executes the constructor of the inherited object.
The most general purpose way also passes any constructor arguments to the inherited object using .apply(this, arguments) like this and initializes its own prototype and sets it's constructor property.
// define base object constructor
function SuperType(){
this.color=["blue","yellow"];
}
// define base object methods on the prototype
SuperType.prototype.foo = function() {};
// ---------------------------------------------------------------------------
// define object that wants to inherit from the SuperType object
function SubType() {
// call base object constructor with all arguments that might have been passed
SuperType.apply(this, arguments);
}
// set prototype for this object to point to base object
// so we inherit any items set on the base object's prototype
SubType.prototype = new SuperType();
// reset constructor to point to this object not to SuperType
SubType.prototype.constructor = SubType;
// define any methods of this object by adding them to the prototype
SubType.prototype.myMethod = function() {};
If you are willing to only support IE9 and above, then you should change this line:
SubType.prototype = new SuperType();
to this:
SubType.prototype = Object.create(SuperType.prototype);
This avoids calling the SuperType() constructor in order to just get an object to use for the prototype. In most cases this really doesn't matter, but in cases where the constructor has side effects outside of just initializing it's own properties, it can matter.
In segment 1 the prototype gets set correctly but the constructor function of SuperType never gets called.
At the start of segment 2 the constructor function of the SuperType gets called but the prototype is not set.
The last example is correct because it sets up the prototype correctly as well as calls the SuperType's constructor function.
function SuperType() {
// Do some stuff.
}
function SubType() {
SuperType.apply(this, arguments);
}
SubType.prototype = new SuperType();
you should not set prototype inheritance with
SubType.prototype=new SuperType ();
because there can be problems.
if you do that like this, the prototype of SubType would also inherit the property color as own property of the SubType prototype, because the constructor is worked through. Every new instance of subType has then a reference to the color property in the prototype and is not an own property of the instance itself, this is finally not what you want because you only want to inherit the prototype. the luck is that after calling the super constructer every instance gets an own color property , but the color property is still also defined in the prototype. there is no need
so to really inherit only the prototype you should use Object.create or do a workaround like this.
function SuperType()
{
if (SuperType.doNotConstruct) return;
this.color=["blue","yellow"];
}
function SubType()
{
SuperType.call (this);
}
SuperType.doNotConstruct=true;
SubType.prototype = new SuperType();
SuperType.doNotConstruct=false;
SubType.prototype.constructor=SubType;
second way - better way - because no if Statement in the constructor is needed
function SuperType()
{
this.color=["blue","yellow"];
}
function SubType()
{
SuperType.call (this);
}
var CLASS=function () {}
CLASS.prototype=SuperType.prototype;
SubType.prototype=new CLASS ();
SubType.prototype.constructor=SubType;
#blake try the following - this will show a problem when people forget to call the super constructor and do inheritation with ...prototype=new constructor
function SuperType()
{
this.color=["blue","yellow"];
}
SuperType.prototype.addColor=function (name)
{
this.color.push ("red");
}
function SubType () {}
SubType.prototype=new SuperType ();
var a=new SubType ();
var b=new SubType ();
a.addColor ("red");
console.log (a.color);
console.log (b.color);
If I have the following:
function Constructor1(data){
...
...
...};
function Constructor2(data){
Constructor1.prototype.constructor.call(this, data);
...
...
...
}
Constructor2.prototype = new Constructor1();
Then how can I later determine the difference between how they were constructed? I know I can do if (testObject instanceof Constructor2) but if I have a LOT of inherited objects I don't want to do that test for everything. Is there any way to get the string 'Constructor2' returned somehow? (Or whatever the first constructor function called) is?
You can call the parent like this: Parent.call(this,args).
You should not create an instance of Parent to set the prototype part of the inheritance in Child.
If you set the prototype without destroying the prototype.constructor in Child you can use the name property of the constructor function:
function Parent(args){
};
function Child(args){
Parent.call(this,args);
};
console.log(Child.prototype.constructor.name);//=Child
//overwrithing Child.prototype so also Child.prototype.constructor
Child.prototype=Object.create(Parent.prototype);
console.log(Child.prototype.constructor.name);//=Parent, needs to be fixed
Child.prototype.constructor=Child;//fixed
var c = new Child();
console.log(c.constructor.name);//=Child
The name property of Function isn't standard so no guarantee about it's behavior:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
You may want to check using the function itself: (this.constructor===Parent)
More on constructor functions and prototype here.
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.