5

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 ?

Tomasz Zieliński
  • 16,136
  • 7
  • 59
  • 83
  • You *can* "return" from a ctor in JavaScript to return a different value -- some build-in functions (e.g. Date) work like this. I'm not sure where it's documented. –  Nov 19 '10 at 01:01
  • 2
    The `a.__proto__ = A.prototype;` is not quite what Gecko does. If there is a setter defined for `__proto__` on `Object.prototype` it will not be triggered. And changing `Function.prototype.call` or `A.call` will not change how the constructor is invoked. – Mike Samuel Nov 19 '10 at 02:00
  • @pst, See EcmaScript 5 Chapter 13.2.2 [[Construct]]. See http://ecma262-5.com/ELS5_Section_13.htm – Mike Samuel Nov 19 '10 at 02:08
  • @All: Thank you very much, it was very refreshing to read all the answers. I wish I could mark answers with gold, silver and bronze medals – Tomasz Zieliński Nov 19 '10 at 14:09

6 Answers6

3

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.

Community
  • 1
  • 1
bobince
  • 528,062
  • 107
  • 651
  • 834
  • Although, for a "quick hack that got way out of hand", it did better than a number of "long-designed" languages ;-) –  Nov 19 '10 at 18:29
2

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)".

Community
  • 1
  • 1
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
1

You can tell from the constructor whether you've been called with new or not - if new, this instanceof MyClass; if not new, this === window (provided it's a top-level object - as gnarf points out, for Namespace.MyClass(), this == Namespace).

It's quite possible (some people like it more than others) to then put at the top of the constructor if (this instanceof MyClass) return new MyClass(); (taking into account arguments, naturally); then the constructor can be called with or without new with the same result.

One question discussing this is Is JavaScript 's “new” Keyword Considered Harmful?. There are others, too.

Community
  • 1
  • 1
Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
1

You can "return" from a ctor in JavaScript to return a different value -- some built-in functions (e.g. Date) work like this (as does Function, but it works differently than Date :-). I'm not sure where it's documented -- in ECMA 262, see other answers.

Here is a contrived example showing how one could create a ctor that works like 'Function' (in FF):

function X() {
  // but this has issues with nesting in some cases
  if (!(this instanceof X)) {
    return new X()
  } else {
    this.y = 2
  }
}
X().y // => 2

However, I do not know how this is defined by the ECMA specification... anyway, the results returned are entirely depending upon the function being invoked/new'ed. -- See ECMA 262 again.

0

This is because Function() returns a function, and new Function() constructs a function hence you get the same output.

Darko
  • 38,310
  • 15
  • 80
  • 107
0

Not sure what your question is... What I can tell you is that the basic objects have code in them to allow you to call it with new and without new, but they behave a little differently.

typeof Number(5) == "number"
typeof new Number(5) == "object"

typeof Boolean(0) == "boolean"
typeof new Boolean(0) == "object"

Calling new on the basic types returns the primitives wrapped as objects.

I've written a blog about creating constructors that work with or without the new operator http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html I don't use it, but it's interesting stuff. It'll give you insight on how you can change the behavior of the function based on whether it's called with new or not....

Even after this ranting, I'm still not sure what your question is...

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217