Reputation: 305
I understand that writing
var x = Number("7"); // makes a number, a primitive
var y = new Number("7"); // makes a Number object
and I'm aware of the usual cautions against option 2, but what is going on behind the scenes? I was under the impression if a function is a constructor, it should not return a value via a return statement: it just sets up its implicit object, this, and returns it.
So how come Number, String, and Boolean constructors are able to return either a primitive or an object? Does the JavaScript engine parse those expressions differently as a special feature in the language? Or can a programmer also "overload" a constructor function to either return a primitive or an object, depending on whether the constructor is called with/without "new"?
Upvotes: 2
Views: 55
Reputation: 33726
Using the constructor the Number
object will be an object, using the function Number
instead will return the conversion of an object to its representation as a numeric value.
So, basically within the Number
object, the function is validating how was called. This is possible by checking the object this
.
Something interesting is coercing the Number
object to a numeric value as follow:
var x = Number("7"); // makes a number, a primitive
var y = new Number("7");
console.log(x === +y)
Go and read about the specification
https://www.ecma-international.org/ecma-262/5.1/#sec-15.7
Upvotes: 2
Reputation: 413826
It has nothing to do with syntax and there's nothing special about those constructors. The Number()
and other constructors simply test to see whether this
is bound before proceeding.
You can do it too:
function MyConstructor() {
if (!this) return new MyConstructor();
// stuff ...
}
Now calling MyConstructor()
will behave exactly like new MyConstructor()
.
Also, a constructor can return something. If it returns an object, then that's used instead of the implicitly-constructed object that new
creates. Thus you could also implement a "new-is-optional" constructor another way:
function MyConstructor() {
let object = this || Object.create(MyConstructor.prototype);
// stuff ...
return object;
}
So the Number()
constructor takes a different tack. In most runtimes it may or may not actually be implemented as JavaScript, but if it were it might look something like this:
function Number(n) {
if (this) {
// invoked with "new"
this.fantasyValueSetter(n); // cannot really do this
return this;
}
return +n; // plain number primitive if not invoked with "new"
}
Upvotes: 1