In JavaScript, why typeof Function.prototype is function, not object like other prototype objects?
This seems to be defined in ECMAScript 5:
15.3.4 Properties of the Function Prototype Object
The Function prototype object is itself a Function object (its
[[Class]]
is "Function") that, when invoked, accepts any arguments and returns undefined.
why typeof(Function.prototype) is function
From the specification:
The Function prototype object is the intrinsic object %FunctionPrototype%. The Function prototype object is itself a built-in function object. When invoked, it accepts any arguments and returns undefined. It does not have a [[Construct]] internal method so it is not a constructor.
NOTE
The Function prototype object is specified to be a function object to ensure compatibility with ECMAScript code that was created prior to the ECMAScript 2015 specification.
(my emphasis)
If we go to the ES5 spec, it says:
The Function prototype object is itself a Function object (its [[Class]] is "Function") that, when invoked, accepts any arguments and returns undefined.
...without offering any explanation for why that would be the case. That language is essentially unchanged in ES1, ES2, ES3, and ES5. I think the original idea was basically that that was what gave it its function-ness, although typeof
(even in ES1) didn't look at the internal [[Class]]
, it looked at whether the thing implemented [[Call]]
(as it still does). When something goes back all the way to ES1, one frequently has to just invoke the "because Eich did the first JavaScript in 10 days and yeah, weird stuff happens when you do that" argument. :-)
Side note: By "object literal" I take it you mean "plain object." (An "object literal" — what the specifiation calls an object initializer — is just a way to write an object in source code. There are other ways to create plain objects.)
Function.prototype is a function
The reason is that the ES5 spec says so:
The Function prototype object is itself a Function object (its
[[Class]] is "Function") that, when invoked, accepts any arguments and
returns undefined.
Note it's common in ES5 to make the prototype of some class a member of that class:
Object.prototype
is an Object object.Function.prototype
is a Function object which returnsundefined
when invoked.Array.prototype
is an empty Array object.String.prototype
is a String object whose value is an empty String.Boolean.prototype
is a Boolean object whose value isfalse
.Number.prototype
is a Number object whose value is+0
.Date.prototype
is a Date object whose [[PrimitiveValue]] isNaN
.RegExp.prototype
is a RegExp object whose data properties are likenew RegExp()
's ones.Error.prototype
is an Error object.
I think it was standardized as such because the prototype of a class has the intrinsic properties of that class, as the instances of that class. And if it looks like a duck it should behave as a duck. So calling the methods of the prototype on the prototype itself instead of on an instance should work too.
However, ES6 didn't like this. So it changed the behavior for those:
Boolean.prototype
is an ordinary object with no [[BooleanData]] internal slot.Error.prototype
is an ordinary object with no [[ErrorData]] internal slot.Number.prototype
is an ordinary object with no [[NumberData]] internal slot.Date.prototype
is an ordinary object with no [[DateValue]] internal slot.String.prototype
is an ordinary object with no [[StringData]] internal slot.RegExp.prototype
is an ordinary object with no [[RegExpMatcher]] nor any of the other internal slots of RegExp instance objects.
And also for new "classes" (ES6 objects no longer have a [[Class]]):
Symbol.prototype
is an ordinary object with no [[SymbolData]] internal slot.TypedArray.prototype
is an ordinary object with no [[ViewedArrayBuffer]] nor any other of the internal slots that are specific to TypedArray instance objects.Map.prototype
is an ordinary object with no [[MapData]] internal slot.Set.prototype
is an ordinary object with no [[SetData]] internal slot.WeakMap.prototype
is an ordinary object with no [[WeakMapData]] internal slot.WeakSet.prototype
is an ordinary object with no [[WeakSetData]] internal slot.ArrayBuffer.prototype
is an ordinary object with no [[ArrayBufferData]] nor [[ArrayBufferByteLength]] internal slots.DataView.prototype
is an ordinary object with no [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], nor [[ByteOffset]] internal slots.GeneratorFunction.prototype
is an ordinary object with no [[ECMAScriptCode]] nor any other of the internal slots listed in Table 27 or Table 56.Promise.prototype
is an ordinary object with no [[PromiseState]] nor any of the other internal slots of Promise instances.
However, the old behavior remains for those:
Function.prototype
is itself a built-in function object.Array.prototype
is an Array exotic object and has the internal methods specified for such objects.
So now the reason is backwards compatibility:
The Function prototype object is specified to be a function object to
ensure compatibility with ECMAScript code that was created prior to
the ECMAScript 2015 specification.
Note this doesn't make Function.prototype
a special function. Only constructors have the prototype
property:
Function instances that can be used as a constructor have a
prototype
property.
There are multiple examples of non-constructor functions apart from Function.prototype
, such as
Methods in
Math
object:typeof Math.pow; // "function
'prototype' in Math.pow; // falseSome host objects:
typeof document.createElement('object'); // "function
'prototype' in document.createElement('object'); // falseIn ES6, arrow functions:
typeof (x => x * x); // "function
'prototype' in (x => x * x); // false
ES 5 - Why Function.prototype object does not have property prototype?
Why function type object
Function.prototype
does not have its own propertyprototype
, in the below visualisation?
Why would it, what would you expect it to point to? It's not a constructor function. (In fact, with ES6, many functions don't have a .prototype
method).
It's rather quite weird that Function.prototype
is a callable object (function), there's actually no benefit from that. It could've been a plain object just as well. "The spec said so" is all we have (see also these three questions).
Any object usually inherits from an object type object, but the
Function
object andPerson
object inherit from function type objectFunction.prototype
?
Well yes, why wouldn't they? As you say yourself, functions are just objects, and every object inherits from another object (or null
). That some objects are callable (and typeof
yields "function"
for them) does not make any difference for inheritance.
Is Object.prototype an object and is prototype somehow not?
If an Object has a prototype, the prototype is also an Object. These Objects all chain together until you reach null, which is the end of the prototype chain.
// Object is a constructor
Object.prototype; // Object {}, will be the prototype of `new Object`s
// Object.prototype is an Object
Object.getPrototypeOf(Object.prototype); // null, we are at the end of the chain
You should also note, however, that you can't keep accessing the obj.prototype
property, as this is only applicable to Constructors, consider
function Foo() {
}
Foo.prototype; // Foo {}
// vs
(new Foo).prototype; // undefined
The correct way to find the prototype of an Object is by using Object.getPrototypeOf(obj)
,
Object.getPrototypeOf(new Foo) === Foo.prototype; // true
It may also be of note that legacy browsers may not support Object.getPrototypeOf
, in which case many offer the property obj.__proto__
. However, try to avoid using __proto__
outside of a shim for such browsers if you need to access the prototype chain.
Finally, using new
with a Constructor isn't the only way to create this chain, you can set them up using Object.create
var a = Object.create(null),
b = Object.create(a), // b will inherit from a
c = Object.create(b); // c will inherit from b, hence also a
a.foo = 'foo';
b.bar = 'bar';
a instanceof Object; // false
a.bar; // undefined
c.foo + c.bar === 'foobar'; // true
Also consider
c.prototype; // undefined
// vs
Object.getPrototypeOf(c) === b; // true
Is `Object` a function in JavaScript?
You seem to be confused between "object" (the data structure) and Object
(the function).
An object is a concept in JavaScript that is a generic container for some data. An object contains properties with keys and associated values.
In JavaScript, everything that is not a primitive is an object. This includes functions, which are basically a special type of object that can be "called" with the ()
syntax.
JavaScript provides a number of built-in functions that have various purposes. Two such functions happen to be called Object
and Function
. So in other words Object
is a function and thus also an "object" (data structure).
Let's take your function Foo
as an example:
function Foo() {
var a = "3";
}
Foo
is a function. This means that Foo
can be called, eg. var f = Foo()
. In this case f
will be undefined
since Foo
doesn't return anything.
Because Foo
is a function, it is also an object. This means we can also add and read properties from it:
Foo.bar = 5;
Foo.bar++;
console.log(Foo.bar); // prints 6
Please note that this "object" part of Foo
is not related to the contents of the function. That means that the code you declared (var a = "3"
) is irrelevant. You cannot access var a
in any way here because it does not exist until you call the function. If you were to do Foo.a
, you are not manipulating var a
inside the function; you are working with the property a
on the object Foo
.
You can however do it the other way around and access properties on Foo
inside of the function:
function Foo() {
var a = "3"; // a is local to this scope, you cannot get to it from outside
console.log(a); // prints 3 - local variable a is accessible inside the scope of this function
console.log(Foo.a); // prints 5 - a is a property on object Foo, and is accessible here
}
// var a inside Foo cannot be accessed here
Foo.a = 5;
Foo();
Edit: Re. your question regarding "this" in the comments. this
is a special keyword in JavaScript that refers to an object. However, this object is not the function itself, it is a new object that is created when you call a function using the new
keyword:
function Bar() {
this.a = 10;
console.log(this == Bar); // prints false
}
var bar = new Bar();
console.log(bar.a); // prints 10
A function that is meant to be called with the new
keyword is referred to as a "constructor function". Object
and Function
are both examples of constructor functions, which is why their names start with an uppercase letter (a convention in JavaScript).
When you create an object with a constructor function, the property prototype
of this function is used as the prototype (accessible through __proto__
) of the created object.
console.log(bar.constructor == Bar) // prints true
console.log(bar.__proto__ == Bar.prototype) // prints true
this
is also used for other things, but that is a broad subject and way out of scope for this question.
Related Topics
How to Skip Over an Element in .Map()
Get Path Params in React-Router V4
Copy a Variable's Value into Another
Getting How Many People Are in a Chat Room in Socket.Io
Get Decimal Portion of a Number with JavaScript
How to Read a Text File from Server Using JavaScript
How to Trigger a Bootstrap Modal Programmatically
Create an Empty Object in JavaScript with {} or New Object()
How to Get the First Element of an Array
Jslint Is Suddenly Reporting: Use the Function Form of "Use Strict"
How to Import a CSS File in a React Component
JavaScript Equivalent of Jquery's Extend Method
How to Create a Jquery Clock/Timer
Promise Constructor with Reject Call VS Throwing Error
Puppeteer - Scroll Down Until You Can't Anymore