If I have a constructor function in JavaScript I want to be able to explicitly return something so that everything is clear when working in a team.
I read that if you use a function as a constructor in JS that if you return anything then using the new keyword will have been a wasted effort. But I am wondering if you can return this from the constructor function and be safe, for example:
function MyConstructor(val){
this.val = val;
return this; //attention here
}
var example = new MyConstructor(val);
Does this yield the desired behavior?
Let's start with the normal behavior of JavaScript. If you do not return anything from a constructor function, it will work as expected (of course).
Hence
var Dog = function (name) {
this.name = name;
};
var alice = new Dog('Alice');
results in a new object whose name property is set to Alice.
Now what happens if you try to override the implicit return statement of the constructor function by explicitly calling it?
Let's introduce a return statement that returns something else:
var Dog = function (name) {
this.name = name;
return 23;
};
var alice = new Dog('Alice');
Which value is alice now? Probably, you'd expect that it's 23, but actually it isn't. It still is an object with a name property set to Alice.
The problem here is that JavaScript is smarter than you: It sees your return, but realizes that the type of the thing you want to return does not match the fact that the function has been called using new. Hence the return is ignored.
Now what if we try to get smarter than JavaScript and return something whose type matches, i.e. an object?
var Dog = function (name) {
this.name = name;
return { foo: 'bar' };
};
var alice = new Dog('Alice');
In this case, JavaScript thinks that you have a good reason to override the implicit return and actually uses yours. This means that alice now points to an object with a foo property which is set to 'bar'.
So, to cut a long story short: If you explicitly call
return this;
you end up with the last case. You override the object that is implicitly being returned. But since the one you return is actually the same as the one that would have been returned implicitly, there is no difference.
So: Yes, it is the same, but the call to return this; is not required.
Some developers use this behavior to trick JavaScript into always returning a new object, no matter whether you call the constructor function with or without new:
var Dog = function (name) {
return {
name: name
};
};
var alice1 = new Dog('Alice');
var alice2 = Dog('Alice');
Both calls result in a new object with a name property set to Alice, but there are some differences to the previous examples:
constructor property is not set to Dog, neither they use the expected prototype chain.new actually two objects are being created: One by new, the other by you using the object literal syntax. This means more work for the garbage collector.Hence, I think, that you should avoid this technique, and either use constructors correctly or stick to factory functions.
This is the same effect that was made use of in @maboiteaspam's answer:
function DHT (opts) {
var self = this
if (!(self instanceof DHT)) return new DHT(opts)
// ctor body
}
If you call this function with new, this is set to an object whose constructor property points to the DHT function. Hence self instanceof DHT returns true and the actual constructor is run.
If you call this function without new, the if statement detects this and runs it with new for you automatically (which is at least better than the solution described above, where you end up with two disadvantages).
Please note that in strict mode it is not allowed to access this from a function that is not called on an object, hence calling a constructor function without the new keyword would result in an error as soon as you tried to access this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With