The reason you're seeing "Y"
at the end is that you're overwriting the value you've put on Object.prototype.getName
. When you call new X()
, you're putting a getName
property on prototypeX
, which is a reference to (not a copy of) Object.prototype
. So now Object.prototype
has a getName
which returns "X"
. When you call objectX.getObject()
, that's doing a new Y()
call, which involves setting getName
on prototypeY
. prototypeY
is also a reference to (not a copy of) Object.prototype
, and so the value set by Y
overwrites the value set by X
.
The solution is don't change Object.prototype
. Adding properties to Object.prototype
is generally a bad idea. Adding enumerable properties (ones that show up in for...in
loops) like your getName
and getObject
properties is always a bad idea.
Below you've said:
I have a background in java and i would like to do that :
class Y, class X ( public Y getY() ( return new Y )
That's dramatically simpler than what you have:
// Constructor function X
function X() {
}
// Add some things to the prototype it assigns objects created via `new`.
// Note that the object `X.prototype` refers to has `Object.prototype` as
// its prototype, that's already been set up for you.
X.prototype.getName = function() {
return "X";
};
X.prototype.getObject = function() {
return new Y();
};
// Constructor function Y
function Y() {
}
// Add something to the prototype it assigns objects created via `new`.
// `Y.prototype` also refers to an object that uses `Object.prototype` as
// its prototype.
Y.prototype.getName = function() {
return "Y";
};
Or if you want to use named functions for debugging purposes, or have information that is only available to code within the various functions related to X
and Y
(like statics in Java), you might do this:
// Define X
var X = function() {
// If you had `var` statements here, the vars would be accessible to
// the code within this anonymous function, kind of like Java static
// variables within a class.
// Constructor function X
function X() {
}
// Add some things to the prototype it assigns objects created via `new`.
// Note that the object `X.prototype` refers to has `Object.prototype` as
// its prototype, that's already been set up for you.
X.prototype.getName = X$getName;
function X$getName() { // There's nothing special about this name
return "X";
}
X.prototype.getObject = X$getObject;
function X$getObject() {
return new Y();
}
return X;
}(); // () at the end runs the above, assigns its result to our variable
// Define Y
var Y = function() {
// Constructor function Y
function Y() {
}
// Add something to the prototype it assigns objects created via `new`.
// `Y.prototype` also refers to an object that uses `Object.prototype` as
// its prototype.
Y.prototype.getName = Y$getName;
function Y$getName() {
return "Y";
}
return Y;
}();
At one point I thought your goal was to set up an inheritance hierarchy where Y
is derived from X
, using constructor functions. According to your comment you don't, but I'll leave this in case others do want to. Here's how you'd do that hierarchy:
// Set up X
function X() {
}
X.prototype.getName = function() {
return "X";
};
X.prototype.getObject = function() {
return new Y(); // <== But this is usually a bad idea from an OOP perspective,
// base classes really shouldn't refer to subclasses
};
X.prototype.answer = function() { // Something for Y objects to inherit
return 42;
};
// Set up Y, where Y objects have a prototype that in turn has X.prototype
function Y() {
X.call(this); // Chain to base constructor function
}
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
Y.prototype.getName = function() {
return "Y";
};
var x = new X();
console.log(x.getName()); // "X"
console.log(x.answer()); // "42"
var y = new Y();
console.log(x.getName()); // "Y", because Y overrides the X version of `getName`
console.log(x.answer()); // "42", because Y inherits the X version of `answer`
Object.create
was added in ES5, but can be partially shimmed/polyfilled for older browsers (sufficient for our use above); here's MDN's version but with a different name for a variable where the MDN version used Object
, which makes no sense:
if (typeof Object.create != 'function') {
Object.create = (function() {
var ctor = function() {};
return function (prototype) {
if (arguments.length > 1) {
throw Error('Second argument not supported');
}
if (typeof prototype != 'object') {
throw TypeError('Argument must be an object');
}
ctor.prototype = prototype;
var result = new ctor();
ctor.prototype = null;
return result;
};
})();
}