问题
I have a rather academic question that doesn't particularly apply to anything I'm doing, I just really want to know the answer!
Say we have a simple object definition in the global namespace as such:
TestObject = function(){};
It has a method added to it's prototype that can be instantiated into a new object itself:
TestObject.prototype.AnotherObject = function() {};
Instantiate the first object:
var myObject = new TestObject();
Now my question is this:
How does
myObject.myProperty = new myObject.AnotherObject();
differ to
myObject.myProperty = new TestObject.prototype.AnotherObject();
Or are they exactly the same?
The difference I see is this: I could use the second method to instantiate objects within the TestObject context without knowing the name of the instantiated object itself, i.e.
TestObject.prototype.createAnObject = function() {
this.anotherProperty = new TestObject.prototype.AnotherObject();
}
And finally:
What are the implications of using a prototype method to instantiate an object of the same name? Why do this result in an infinite loop? (What actually happens inside..)
TestObject.prototype.AnotherObject = function () {
this.AnotherObject = new TestObject.prototype.AnotherObject();
};
myObject.AnotherObject();
Yet this does not...
TestObject.AnotherObject = function() {};
TestObject.prototype.createAnObject = function() {
this.AnotherObject = new TestObject.prototype.AnotherObject();
};
myObject.createAnObject();
...
I have a deep desire to understand the relationships between objects here! Thank you!
The reason I ask these questions is because I want to make something like so where there is a 1:1 relationship between objects:
ClientObject = function () {
this.objectname = "a client class";
}
ClientObject.prototype.loginUser = function(name) {
this.loggedin = true;
if (typeof this.User === 'undefined') {
this.User = new ClientObject.User(name);
}
}
ClientObject.User = function (name) {
this.username = name;
}
ClientObject.User.prototype.getProfile = function() {
return 'user profile';
}
var testClient = new ClientObject();
console.log('testClient.User = ' + (typeof testClient.User)); // should not exist
testClient.loginUser('Bob'); // should login 'bob'
console.log('testClient.User = ' + (typeof testClient.User)); // should exist now Bob is logged in
console.log(testClient.User.username); // should be bob
testClient.loginUser('Tom'); // should not do anything as User object already created
console.log(testClient.User.username); // bob still
console.log(testClient.User.getProfile()); // new functionality available
I am just not sure if I'm breaking any best practises or conventions here unwittingly.
回答1:
myObject.myProperty = new myObject.AnotherObject();
differ to
myObject.myProperty = new TestObject.prototype.AnotherObject();
There's no difference at all. Remember, objects in JavaScript have a prototype chain. When you call new myObject.AnotherObject();
the engine will first check for a AnotherObject
on myObject
itself. Failing to find it, it will check on myObject
's prototype, which it will find. The second version
myObject.myProperty = new TestObject.prototype.AnotherObject();
Just goes right to the place where AnotherObject
is defined.
TestObject.prototype.AnotherObject = function () {
this.AnotherObject = new TestObject.prototype.AnotherObject();
}
myObject.AnotherObject();
Just walk through the code. When you say: myObject.AnotherObject();
, AnotherObject
will be called, with this
set to myObject
. The first line of that will attempt to create a new property on myObject
(which is this
) by setting it to the result of
new TestObject.prototype.AnotherObject();
which will then re-enter the very same AnotherObject
function, but this time with this
set to a new object whose prototype is set to TestObject.prototype.AnotherObject
's prototype. And so on ad infinitum
Finally,
TestObject.prototype.createAnObject = function() {
this.AnotherObject = new TestObject.prototype.AnotherObject();
}
myObject.createAnObject();
Will not cause an infinite loop, so far as I can tell, and as far as I can test: FIDDLE
Basically, createAnObject
will enter with this
set to myObject
. Inside of which a brand new property called AnotherObject
will be created on myObject, which will be set to a new invocation of the AnotherObject
function you previously set up.
Note that after this call is made, the AnotherObject
function will still exist, but, it will be shadowed by the AnotherObject
property you just created. So now you'll never ever be able to say
var f = new myObject.AnotherObject()
Because you now have a AnotherObject
property sitting right on myObject, which will be found and returned before anything on the prototype is ever checked.
Well, I mean, you could always say delete myObject.AnotherObject
and remove that property from the object, which would then open you up to the AnotherObject
being found on the prototype, but really, you should avoid name conflicts like this to begin with.
Regarding your last bit of code
A) Why not make User
its own function?
B) Why not set up this.User = new ...()
right in the ClientObject constructor function? That way you wouldn't need the undefined
check
C) ClientObject
should be defined as
function ClientObject(){...`
the you have it now seems to be creating an implicit global.
来源:https://stackoverflow.com/questions/16889166/javascript-creation-of-object-from-an-already-instantiated-object-versus-the-pr