function Member(){
this.x="hello";
};
var test = new Member();
Member.prototype.x = "test";
console.log(test.x);
//hello
I originally wrote like this for making a constructor expecting its output would be "test". But it didn't work, the result was "hello". But when I made the constructor to the below one, it worked.
function Member(){
Member.x="hello";
};
I want to know how it was worked. Thanks.
When you perform new Member()
, a couple of things happen, MDN described these steps quite nicely:
Creates a blank, plain JavaScript object. For convenience, let's call it
newInstance
.Points
newInstance
's [[Prototype]] to the constructor function'sprototype
property, if the prototype is anObject
. Otherwise,newInstance
stays as a plain object withObject.prototype
as its [[Prototype]]. ...Executes the constructor function with the given arguments, binding
newInstance
as thethis
context (i.e. all references tothis
in the constructor function now refer tonewInstance
).If the constructor function returns a non-primitive, this return value becomes the result of the whole
new
expression. Otherwise, if the constructor function doesn't return anything or returns a primitive,newInstance
is returned instead. (Normally constructors don't return a value, but they can choose to do so to override the normal object creation process.)
That means that in your examples:
test
is the this
object created in your Member
constructor function when called with new
(ie: the "instance").test
's [[Prototype]]1 points to the object Member.prototype
. Meaning that all properties on the object Member.prototype
can be access via test
(if not "shadowed" on test
)When you use test.x
, we first look for x
on the instance created by new Member()
(ie: the this
object that was created in your function and returned). If x
cannot be found on the instance itself, then the prototype (object stored at the __proto__
property) is checked for x
(and then if it can't be found on the prototype we then check the prototype's prototype and so on).
In your first example, since we're able to find x
on the object instance itself with the value of "hello"
it logs "hello"
and doesn't check the prototype (the x
on the instance "shadows" the x
on the prototype).
In your second example, since your function doesn't add any properties to this
, the instance returned by new Member()
doesn't have an x
property like the first example did (its an empty object {}
), and so we check the prototype (which from step 2 above we see is Member.prototype
), which does have an x
property set to "test"
, and so it logs "test"
. Performing Member.x
adds x
as a property to your function object, but doesn't impact the instance created by using new
.
1 Note that as RobG pointed out, the use of __proto__
is deprecated. The spec uses an internal slot, [[Prototype]]
, on the constructed object instance and is used to point to the constructor function's .prototype
property. Avoid using __proto__
and instead use methods such as Object.getPrototypeOf()
, Object.create()
or Object.setPrototypeOf()
when you need to access / set the object for the [[Prototype]]
slot (although, the use of setPrototypeOf()
should still be used sparingly due to performance reasons)