What is the reason to use the 'new' keyword at Derived.prototype = new Base
WeatherWidget.prototype = new Widget;
The new
keyword calls Widget
as a constructor and the return value is assigned to the prototype
property. (If you would omit new
, you would not call Widget
unless you added an argument list, ()
. However, calling Widget
that way might not be possible. It would certainly have the potential to spoil the global namespace if it is not strict mode code and the implementation is conforming to ECMAScript Ed. 5.x there, because then this
in the constructor would refer to ECMAScript’s global object.)
But this approach actually comes from a really viral bad example in the old Netscape JavaScript 1.3 Guide (mirrored at Oracle, formerly Sun).
This way, your WeatherWidget
instances will all inherit from the same Widget
instance. The prototype chain will be:
[new WeatherWidget()] → [new Widget()] → [Widget.prototype] → …
This can be useful, but most of the time you would not want it to happen. You should not do that here unless you want all your WeatherWidget
instances to share among them the property values they inherit from this Widget
instance, and only through it, from Widget.prototype
. Another problem is that you need to call the parent constructor this way, which may not allow to be called without arguments as you do, or would not initialize properly. It certainly has nothing to do with emulation of class-based inheritance as known, e.g., from Java.
The proper way to implement class-based inheritance in these prototype-based languages is (originally devised by Lasse Reichstein Nielsen in comp.lang.javascript
in 2003, for cloning objects):
function Dummy () {}
Dummy.prototype = Widget.prototype;
WeatherWidget.prototype = new Dummy();
WeatherWidget.prototype.constructor = WeatherWidget;
The constructor
prototype property should be fixed as well, so that your WeatherWidget
instances w
would have w.constructor === WeatherWidget
as expected, and not w.constructor === Widget
. However, be aware that it is enumerable afterwards.
This way, WeatherWidget
instances will inherit properties through the prototype chain, but will not share property values among them, because they inherit from Widget.prototype
through Dummy
which has no own properties:
[new WeatherWidget()] → [new Dummy()] → [Widget.prototype] → …
In implementations of ECMAScript Ed. 5 and later, you can and should use
WeatherWidget.prototype = Object.create(Widget.prototype, {
constructor: {value: WeatherWidget}
});
instead. This has the additional advantage that the resulting constructor
property is not writable, enumerable, or configurable.
The parent constructor will only be called if you call it explicitly, from WeatherWidget
, for example with
function WeatherWidget (…)
{
Widget.apply(this, arguments);
}
See also Function.prototype.extend()
in my JSX:object.js for how to generalize this. Using that code, it would become
WeatherWidget.extend(Widget);
My Function.prototype.extend()
takes an optional second argument with which you can easily augment the prototype of WeatherWidget
instances:
WeatherWidget.extend(Widget, {
foo: 42,
bar: "baz"
});
would be equivalent to
WeatherWidget.extend(Widget);
WeatherWidget.prototype.foo = 42;
WeatherWidget.prototype.bar = "baz";
You will still need to call the parent constructor explicitly in the child constructor, though; that part cannot reasonably be automated. But my Function.prototype.extend()
adds a _super
property to the Function
instance which makes it easier:
function WeatherWidget (…)
{
WeatherWidget._super.apply(this, arguments);
}
Other people have implemented similar extensions.
Why would using new and constuctor functions in JavaScript be wrong
using new and constructor functions is wrong and should not be used.
Read Is JavaScript's "new" keyword considered harmful? - No, it is not. A few (correct) arguments are
It's confusing to newbies because of hiding the prototypical concept. To quote @Aadit:
[With
new
] the constructor function becomes simpler. However it becomes very
difficult to explain prototypal inheritance to a person who knows
nothing about it. It becomes even more difficult to explain it to a
person who knows classical inheritance.- Constructors do silently fail when forgetting
new
- In a few instances, the pure
Object.create
approach is cleaner - Building a class hierarchy is complicated and often done wrong
However, once you understand these, new
is harmless. Actually, every time you need instance initialisation plus prototypical inheritance, constructors with new
are the way to go.
They go against the prototype nature of JavaScript.
This will never change. I hardly can imagine why anyone would criticise this, prototypical inheritance is far more powerful than class inheritance. Probably they are only arguing against the syntax.
Could someone please enlighten me and show a situation where using new and constructor functions is so bad it should never be used?
It should not be used when not needed. Singletons can easily be created using the module pattern and object literals; inheritance does not help here. See Is it right to think of a Javascript Function Expression that uses the 'new' keyword as 'static' for an example.
inheritance using prototype in javascript
An explanation would be:
Prototypes are live chains between objects. Because B's prototype is a single tone instance of A, the array prop is passed by reference. This means that for each B instance we have access to the same A instance on the prototype. This might sound confusing at first but that's the magic of prototypes in JavaScript.
This is the caveat of prototypal inheritance. Anything on the prototype will be passed down to each instance. To maintain different instances of the attribute we initialise our object's attributes in the constructor.
When working with objects in JS (like arrays), they are passed by reference.
To make use of JS's prototype system I would suggest something like so:
function A(){
this.text = "";
this.action = function(){
this.text+="z";
this.arr.push(1);
}
this.test = function(){
console.log(this.text+"|"+this.arr);
}
}
function B(){
this.arr = [];
}
B.prototype = new A();
This way we reuse the methods from the "parent" and have a localised array in our "child". At a first glance this might look as a classic OOP inheritance case but it is a bit different.
If you want to read more about prototypes in JS I recommend this article
Hope this helps.
Trying to understand inheritance in JavaScript -- what's going on here?
Object.create(Animal); // set Cat's prototype to Animal
Yes, but to the Animal
constructor function (or, to be exact: to a new object inheriting from that function object - check the docs for Object.create
). That's hardly what you want - and explains your curious result of saying "Animal"
, as that's the Animal
function's name
property.
Instead, you want to build a prototype chain, so that cat instances inherit from Cat.prototype
which inherits from Animal.prototype
(which inherits from Object.prototype
):
Cat.prototype = Object.create(Animal.prototype);
Also, for prototypical inheritance, you should but the sayName
and sayType
methods on the prototype object (and only once):
Animal.prototype.sayType = function() {
alert(this.type);
};
Cat.prototype.sayName = function() { // after creation of that object, of course
alert(this.name);
};
Why are the object and constructor.prototype set to Base in JavaScript?
Have a look at Why [not] to use the new
keyword here?. You might not use it and create a new instance of it, but rather just inherit from Base.prototype
.
Also the constructor.prototype is Base. Why not Shape?
I'm not sure which constructor
you are referring to here:
The
constructor
property of all your objects isBase
, as all of them inherit this prototype from theBase.prototype
object. You did not overwrite it after setting up the inheritance chains. It is not really necessary, but good style:Shape.prototype.constructor = Shape
andRectangle.prototype.constructor = Rectangle
- where those prototype objects are the overwritten ones which inherit fromBase
.The
constructor
parameter of yourinstanceOf
function. You pass inRectangle
there, soconstructor.prototype
is the prototype object ofRectangle
, which inherits fromBase
but is different.
When I check the value of rec in the debug mode, the object is Base { x=0, y=0, w=10, more...}
Usually not. Is Base
something special, e.g. a host object? Your rec
object is an instance of Base
, so it might be displayed differently because of that.
rec
is just an object which inherits from Rectangle.prototype
which inherits from Shape.prototype
which inherits from Base.prototype
which inherits from… Assuming Base
is the function you defined, from Object.prototype
which inherits from null
.
B extends A, but B.add populates A.prototype.property
There is only one children array created in your script, but it is referenced by each instance (and even B's prototype) due to inheritance. When you push to it, you will see the changes from everywhere as well.
Instead, give every instance its own array:
function A() {
this.children = [];
}
And also, don't create only one array for all B instances to inherit from with new A
- instead, use
function B() {
A.call(this); // do everything the A constructor does on this instance
}
B.prototype = Object.create(A.prototype);
B.prototype.addChild = function(Child) {
this.children.push(Child);
};
What is a practical advantage of Object.create over Constructor function?
Calling a constructor function:
const child = new Human();
is (nearly) the same as:
const child = Object.create(Human.prototype);
Human.call(child);
therefore I would not see Object.create
as a language feature, but rather as a way to understand prototypal inheritance in JS.
There are very very limited usecases for prototype chains without constructors. One example would be the deserialization of a Human
:
const serialized = JSON.stringify(child); // Human inheritance gets lost, its a plain object now
const child2 = Object.assign(Object.create(Human.prototype), JSON.parse(serialized));
What is the correct prototype affectation in javascript inheritance?
Derived.prototype = new Base();
This does call the Base
constructor just for setting up the prototype chain. While sometimes working and giving equivalent results to Object.create
, it is error-prone and should be avoided. Read What is the reason to use the 'new' keyword at Derived.prototype = new Base (and why it should not be used).
Derived.prototype = Object.create(Base.prototype);
This is state of the art - Correct javascript inheritance so to say.
Derived.prototype = Base.prototype;
This is plain wrong. Do not use. It lets Base
and Derived
instances inherit from the same object - while it (seldom) can be helpful to have multiple constructors for a "class", this is not "subclassing".
Is
Derived.prototype.constructor = Derived;
really needed? Why?
It can be omitted and your script will work nonetheless, but for convenience you would expect that (new Derived).constructor === Derived
. Also have a look at JavaScript inheritance and the constructor property
Related Topics
How to Check That a Number Is Float or Integer
What Do Parentheses Surrounding an Object/Function/Class Declaration Mean
How to Interpolate Variables in Strings in JavaScript, Without Concatenation
Usage of the Backtick Character (') in JavaScript
How to Check That a Number Is Nan in JavaScript
How to Get the Difference Between Two Arrays in JavaScript
Use Dynamic Variable Names in JavaScript
$(Document).Ready Equivalent Without Jquery
How to Add a Delay in a JavaScript Loop
Scroll to an Element With Jquery
What Do Multiple Arrow Functions Mean in JavaScript
Do You Recommend Using Semicolons After Every Statement in JavaScript
Location of Parenthesis For Auto-Executing Anonymous JavaScript Functions
Addeventlistener Calls the Function Without Me Even Asking It To
React Setstate Not Updating State
How to Completely Uninstall Node.Js, and Reinstall from Beginning (Mac Os X)