Reputation: 2500
Here is my superclass:
function Element() {
var name;
this.setName(n) = func()...{};
this.getName() = func()..{return name};
}
My another child class:
Select = null;
...
Select =
function (n) {
if (typeof n !== "undefined")
this.setName(n);
...
}
Select.prototype = new Element();
Select.prototype.constructor = Select;
So, what kind of "weird moment" am I talking about? Here it is:
var e1 = new Select("element1");
e1.getName(); // return "element1"
var e2 = new Select(); // WITHOUT NAME
e2.getName(); // return "element1"!!! should be ""!
This is a fairly predictable behavior, but how to get around this?
Of course, i can make something like a this.clear()
in Element
, that will clear properties and put this method in Select
function, but maybe there is a proper solution?
Upvotes: 0
Views: 115
Reputation:
You should add this line Element.call(this, n)
into Select
. It's quite hard to explain and I feel grumpy because I don't like fake private properties in javascript, but well, I must provide some details in order for you to understand what you are currently doing, otherwise I will not be able to get to sleep.
So, doing new Element()
creates a new context where name
can live without disturbing anyone. Additionally, two new functions called setName
and getName
are created, and bound to the prototype
object of Select
.
From now on, if you create a new instance of Select
, you can call these functions since they are available in the prototype of the instance. This actually happens doing new Select("element1")
. Indeed, n
is defined, so, setName
is called from this
, which refers to the instance.
But most importantly, calling setName
with n
set to "element1"
will also set name
to "element1"
. Then, if you create a second instance of Select
, without defining n
, setName
is not called, so, name
remains set to "element1"
, for both instances.
Why for both instances? Because both instances share the same setName
method, the one bound to the prototype, and this method refers to a unique name
variable - remember that Element
was called only once.
Finally, why this new line Element.call(this, n)
prevents name
from being shared? Because each call to Element
creates a new context, that is to say, a new name
, a new setName
and a new getName
, and binds these two methods to the newly created instance.
Well, hope this is the morning for you, I would be sorry if you get into sleeping disorders by my fault...
As mentionned by Bergi and HMR, this way of creating the prototype - Child.prototype = new Parent
- is out of fashion and will lead you to a dead end. Keep in mind that the prototype is kind of a template for creating instances. Knowing this and considering your code, we can make at least two observations :
Element
- is unnecessarily executed since the goal is currently to set the template upon which instances will be created.name
is required in new Element(name)
, otherwise your program crashes. What kind of name would you give to the prototype? This question is obviously useless, since you would not want to give a name to a template.To bypass these problems you need a middleman as shown in the below code (copied from the link shared by Bergi). As you can see, the creation of the prototype is delegated to a "dummy" constructor which is empty. Doing so allows to resolve the two problems raised above.
function Dummy () {}
Dummy.prototype = Element.prototype;
Select.prototype = new Dummy();
Select.prototype.constructor = Select;
Alternatively, you could use the built-in Object.create()
:
Select.prototype = Object.create(Element.prototype);
Select.prototype.constructor = Select;
Further reading :
Upvotes: 3
Reputation: 14492
You should use the prototype of Element
so the variables are not shared between the instances:
function Element() {}
Element.prototype.setName = function(n) { this.name = n; };
Element.prototype.getName = function() { return this.name; };
In this case e2.getName()
will return undefined
.
Upvotes: 2