Constructors are ordinary functions that are called using the new operator. What happens if you forget to add the new operator when calling the constructor?
This will not be interpreted by the interpreter as an error, but may lead to a logical error and unexpected results. If you call the constructor without the new operator, the this inside the constructor will point to the global object. (In browsers, this will point to a window object.)
If a new property is created in the constructor, such as this.member, then when the constructor is called without the new operator, a new member property of the global object will be created, which can be accessed like this: window.member or just member.
This constructor behavior is highly undesirable because you should always fight for the cleanliness of the global namespace: (you can change the code in the sandbox below and then press execute button):
This unwanted behavior is eliminated in the ECMAScript 5 standard, and in strict mode, this no longer points to a global object.
But if the ES5 implementation is not available, you can still take certain actions, thanks to which the function will always act as a constructor, even when called without the new operator.
Naming conventions
The easiest option is to use naming conventions, according to which the names of the constructors begin with an uppercase character (MyConstructor), and the names of "ordinary" functions and methods with a lowercase character (myFunction).
Using that
Following naming conventions is, of course, useful, but conventions are just a hint and not ensuring correct behavior. The following describes a template that ensures that your constructors always behave like constructors. The bottom line is, instead of the this, add new members to the that and return it explicitly.
function Car() {
var that = {};
that.color = “red”;
return that;
}
When creating simple objects, you don’t even need a local variable, like that in our example, you can simply return an object defined as a literal:
When calling the constructor function with the new operator, the following happens inside the function:
function Car() {
return {
color: 'red'
};
}
Any of the above Car() implementations will always return an object no matter how this function is called: (you can change the code in the sandbox below and then press execute button):
The problem with this approach is that the connection with the prototype will be lost, so all members added to the Car() function`s prototype will be inaccessible to objects.
Note that the variable name that is only selected for convenience - it is not part of the language. As well you can use any other name. Common names include self and me.
Here is the preferred solution - Constructors calling themselves
To get rid of the drawback inherent in the previous template, and to ensure the availability of prototype properties in instances of the object, you can use the following solution.
In the constructor, you can check whether the this reference is an instance of the constructor, and if not, call the constructor again, but with the new operator (you can change the code in the sandbox below and then press execute button):
Another common way to validate an instance is to compare, not with a specific constructor name, but with a property arguments.callee.
if (!(this instanceof arguments.callee)) {
return new arguments.callee();
}
This template uses the fact that an object called arguments is created inside each function, containing all the parameters passed to the function when called.
The arguments object has a callee property that refers to the called function. However, keep in mind that the arguments.callee property is not available in ES5 strict mode, so it`s best to refrain from using it in the future.