Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript - behaviour of Function core object

Tags:

javascript

As far as I understand, in JavaScript (Gecko variant) this:

var a = new A();

is a syntactic sugar for something like this:

var a = {};
a.__proto__ = A.prototype;
A.call(a);

Because of that, A() (which is equivalent to A.call()?) and new A() should produce two different results, like these:

>>> new Date()
Fri Nov 19 2010 01:44:22 GMT+0100 (CET) {}
>>> typeof new Date()
"object"

>>> Date()
"Fri Nov 19 2010 01:44:42 GMT+0100 (CET)"
>>> typeof Date()
"string"

So far so good.

But, core object Function behaves differently:

>>> Function('return 123;')
anonymous()
>>> typeof Function('return 123;')
"function"
>>> Function('return 123;')()
123
>>> new Function('return 123;')
anonymous()
>>> typeof new Function('return 123;')
"function"
>>> new Function('return 123;')()
123

Am I missing some trivial thing here ?

like image 832
Tomasz Zieliński Avatar asked Nov 19 '10 00:11

Tomasz Zieliński


2 Answers

JavaScript at a language level doesn't specify a particular ‘standard’ way of using constructors. When you define your own constructor function, you can choose to have it callable as a constructor (with new), as a function (returning a new object), or make it work with either.

Am I missing some trivial thing here?

Not really. The Function constructor function is defined to be usable as a constructor even without new, by ECMAScript section 15.3.1:

When Function is called as a function rather than as a constructor, it creates and initialises a new Function object. Thus the function call Function(...) is equivalent to the object creation expression new Function(...) with the same arguments.

The Date function, on the other hand, is defined (by ECMAScript section 15.9.2) to return a string:

When Date is called as a function rather than as a constructor, it returns a String representing the current time (UTC).

NOTE: The function call Date(...) is not equivalent to the object creation expression new Date(...) with the same arguments.

The NOTE is there because so many constructor functions can also be used without new. That's not because of any over-arching thinking that all constructor functions should be allowed to work as plain functions, but because this is just what JavaScript has always done since the early Netscape days. Netscape couldn't think of anything special for Function() to do, so it just reproduced the new functionality. They didn't pay too much attention to making the language consistent.

You wouldn't design a language's default class library like that if you were sane. But JavaScript isn't a sane language. It's a quick hack that got way out of hand, achieving mass popularity way before anyone spent any time refining its design. Expect it to behave consistently and you will only be disappointed.

like image 188
bobince Avatar answered Sep 28 '22 14:09

bobince


The Function constructor called as a function is just equivalent as using it in an expression with the new operator, the case is described in the specification.

From § 15.3.1: The Function Constructor Called as a Function

...

Thus the function call Function(...) is equivalent to the object creation expression new Function(...) with the same arguments.

There are other built-in constructors that behave just like this, for example, the Array constructor called as a function:

Array(1,2,3);     // [1,2,3]
new Array(1,2,3); // [1,2,3]

Other constructors like the ones that create primitive value wrappers (Boolean, String, Number and Date) behave differently.

The first three if you use call them without the new operator, they just perform type conversion, for example:

typeof Number("20"); // "number"
typeof String(0xFF); // "string"
typeof String({toString: function () { return 'foo' }}); // "string"
typeof Boolean(""); // "boolean"
typeof Boolean(0); // "boolean"

While if you use them with the new operator, they will return wrapper objects:

typeof new Number(20); // "object"
typeof new String('foo'); // "object"
typeof new Boolean(true); // "object"

This kind of objects are called primitive wrappers, they have an internal property named [[PrimitiveValue]] where they store their underlying value (more on Objects vs Primitives).

Objects created with the Date constructor are also primitive wrappers their underlying value is a numeric representation of the time value.

The semantics of the Date constructor are also fully described, if it's called as a function, it will return a "string representing the current time (UTC)".

like image 37
Christian C. Salvadó Avatar answered Sep 28 '22 14:09

Christian C. Salvadó