2

Javascript seems to take a few liberties when it comes to its built-in types and objects.

To get at the functions inside the Array type you can do this:

> Array().slice
  function slice() {
     [native code]
  }

So here Array looks like a standard function that is being used as a constructor. Except... slice is not a member function of the Array() function, it's a member function of the Array object.

Another unusual thing about Array() is it seems to return an Array object whether you call it with new() or not:

> var a = Array()
undefined
> a
[]
> a.length
0

> var b = new Array()
undefined
> b
[]
> b.length
0

Math on the other hand seems to be a built in singleton object that is always present (ie: no need to instantiate). So you would use Math.min.apply while with Array using Array().slice.apply.

My question is what makes Array() so different than either a constructor you would write yourself and the other built-in objects of Javascript.

2 Answers 2

6

I'll make some comments inline, quoting your question:

Except... slice is not a member function of the Array() function, it's a member function of the Array object.

More exactly, slice is a member of the Array.prototype object, by executing Array(), you are creating a new array object, that inherits from Array.prototype, that's why slice is available.

Another unusual thing about Array() is it seems to return an Array object whether you call it with new() or not:

This behavior is shared also by other built-in constructors, for example Function:

var fn = Function('return "foo";');

Is equivalent to:

var fn = new Function('return "foo";');

The cases are described in the specification (The Array constructor called as a function vs new Array), although other constructors present a different behavior when you use them with or without new, for example, the primitive wrappers:

new Number("20");        // produces a Number object
typeof new Number("20"); // "object"

Number("20");            // makes type conversion
typeof Number("20");     // "number"

Math on the other hand seems to be a built in singleton object that is always present (ie: no need to instantiate). So you would use Math.min.apply while with Array using Array().slice.apply.

Yes, Math is a simple object, not a function like Array.

It inherits from Object.prototype and IIRC the only peculiar difference that it has with a simple user-defined object is that it's internal [[Class]] property contains "Math", e.g.:

Object.prototype.toString.call(Math); // "[object Math]"

My question is what makes Array() so different than either a constructor you would write yourself and the other built-in objects of Javascript.

Array isn't that different, you could write a constructor that behaves the same way if invoked with new or not, for example:

function Foo (arg) {
  if (!(this instanceof Foo)) { return new Foo(arg); }
  this.foo = arg;
}

new Foo('bar'); // { foo: 'bar' }
Foo('bar');     // { foo: 'bar' }
Sign up to request clarification or add additional context in comments.

Comments

3

You're writing

 Array().slice()

What that means is:

  1. Call the "Array" function
  2. Look for a property called "slice" on the return value
  3. Treat the value of that property as a reference to a function, and call it

The "slice" function is defined on the Array prototype object, which means that every instance of Array has access to it via that property name. The key here is that the "Array function" as you call it is referenced by the symbol "Array". When you write "Array()", that means to call the function, and thus that expression refers to an array instance. There's not really much difference between a constructor and a regular function; really, it's the new keyword that makes a difference by altering the way that the function is invoked (that is, with a freshly-created Object instance as the this context value). A function is free to check to see if this refers to the global object, and if so to return a newly-created object on its own initiative.

The "Math" object is just an object; you can think of it as being defined like this:

var Math = {
  min: function(n1, n2) { ... },
  max: function(n1, n2) { ... },
  // ...
};

5 Comments

Math is, at least in Chrome, an instance. On Firefox it wraps directly to native code, it's not even usable in a for in loop.
Yes I'm sure it's not really defined thusly - what I meant is that that's just an illustration of the object's nature.
@Ivo, you can't enumerate the properties of the Math object with a for-in loop because they are described as non-enumerable, e.g.: Math.propertyIsEnumerable('max'); produces false
@CMS Ah ok. But Opera is strange to, you can call Math's constructor, only to get back a useless object with no prototype and therefore no functions.
@Ivo, really bad thing, must be reported, it's completely against the spec: "The Math object does not have a [[Construct]] property; it is not possible to use the Math object as a constructor with the new operator.", also: "The Math object does not have a [[Call]] property; it is not possible to invoke the Math object as a function."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.