Why {}.toString can check data type? - javascript

Can anyone explain a bit about why these codes can check data type? They does not make sense to me. I cannot understand what the codes do behind the scene. Thanks in advance!
var toClass = {}.toString // {} is for what? toString is a method?
alert(toClass); // alert it I get a function? = > function toString() {[native code]}
alert( toClass.call( [1,2] ) )
alert( toClass.call( new Date ) )

var toClass = {}.toString;
is equivalent to
var toClass = Object.prototype.toString;
because
{}
as an expression (Object initialiser) is equivalent to
new Object()
where Object is “the standard built-in constructor with that name” (ECMAScript Language Specification, 5.1 Edition, section 11.1.5; and earlier Editions).
So {} stands in for a reference to a new Object instance. Object instances by default inherit properties from the object initially referred to by Object.prototype through the prototype chain (section 15.2.5), including the built-in property Object.prototype.toString. The property value is initially a reference to a Function instance, i.e. the property is a method that you can call (section 15.2.4.2).
alert is actually window.alert (and should be written so). window is a property of the ECMAScript global object; the object referred to by that property is a host object in the scope chain which has the alert method. Neither of those is specified in ECMAScript, but they are provided by some host environments (usually by browsers) as allowed by the Specification (section 15.1).
Because it is designed to display alert messages, the alert host method displays the string representation of its first argument. For objects, that includes calling their toString or valueOf method, whichever is supported first (section 9.8). Function instances, such as that referred to by {}.toString, inherit themselves a toString method that returns the implementation-dependent representation of the function (section 15.3.4.2).
There are no classes, though, and the ECMAScript concept of [[Class]] is somewhat different from that of "data type" (see typeof and instanceof). These are languages using prototype-based inheritance (section 4.2.1).

This is equivalent to:
Object.prototype.toString.call([1, 2]);
Object.prototype.toString.call(new Date);
Here, Object.prototype.toString is the default toString method that all objects inherit by default. When invoked it prints something like this:
[object XXX]
{}.toString is similar here, because {} is short for new Object().
Derived objects are free to override the toString method to suit their needs, for example:
> [1, 2].toString()
"1,2"
> (new Date).toString()
"Wed Feb 27 2013 17:03:42 GMT+0800 (Malay Peninsula Standard Time)"
However, you can still use the "primitive" method by using .call() on either Object.prototype.toString or {}.toString whereby the first parameter to .call() is used to define what this refers to inside the method you're calling.

Related

Why does __proto__ not update when prototype is set to null [duplicate]

Why is it that setting the prototype property of a constructor function to null does not prevent objects created from that function from calling through to methods on Object.prototype, in the same way that setting the prototype to Object.create(null) does?
That is, why is this the case:
function Foo(){}
Foo.prototype = null;
console.log(new Foo().toString); //outputs function toString() { [native code] } (or whatever)
function Foo(){}
Foo.prototype = Object.create(null);
console.log(new Foo().toString); //output undefined
In short
Yes, your observation is correct - a function constructed with the new operator will always have an object prototype in this case Object.prototype and this is indeed unlike a function created with Object.create.
On why
One can see this behavior completely specified in the ES5 language specification on which JavaScript is based on. Let's see this.
In new:
Quoting the specification of the [[Construct]] method of functions that indicates how object creation using the new operator is performed we can see that the following is specified:
If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.
In Object.create:
On the other hand, if we check out The spec for Object.create we can see that Object.create(o) specifies:
Set the [[Prototype]] internal property of obj to O.
Which means we can set it, it also explicitly checks that it is null or Object in that algorithm (please do follow the link to the spec and read it :))
So the prototype of the objects called with new Foo is Object.prototype and not null. It is impossible to create objects with no prototype without Object.create using standard methods only.

why typeof(Function.prototype) is function

I am aware of the fact that Prototypes are object literal. So methods and properties can be defined on them. Function.prototype has some method like apply, call, bind, toString etc. So I thought a function's prototype should be a object literal. But I ran following code and encountered that Function.prototype is of type function !
console.log(typeof(Function.prototype)); // function
How come it is not a object literal itself ?
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.)
An object literal is some JavaScript syntax for creating objects. It isn't a data type.
Functions are just a specific type of object in JavaScript. Anywhere you can have an object, you can have a function.
Let's say you have declared an array,
let arr = [ 1 , 2 ];
So, internally it will be created as
let arr = new Array ( 1, 2 );
This is the function constructor.
Have you ever thought about how the array got all functions like concate, map, filter, reduce etc.?
Internally when we create an instance from a function constructor, the prototype property of a function will be set to the prototype property of that newly created instance. Hense, this concate, map, filter, reduce get automatically associated with that function constructor. So that's how we can use that array properties by arr.map, arr.concate.
Actually the prototype property of a function is visible but the prototype property of an instance which is created by a function constructor is hidden. If you want to check then you can check it by obj_name.proto. It's a pointer towards that prototype property.
Now, you can see that the array "arr" is not the array internally. It's an instance of a function constructor. That's why if you check the type of the array, you will get the answer as object and also if you check the typeof(Array), you will get the answer as Function.
If you find it useful then please like it on
https://www.linkedin.com/posts/sh-jay_javascript-array-prototype-activity-6951547190049677312-Dqbn?utm_source=linkedin_share&utm_medium=member_desktop_web
Well, I don't think you mean object literal, as alluded to by other answers and comments.
alert(Function.prototype instanceof Object) // true
alert(Function.prototype instanceof Function) // true
alert(typeof Function.prototype) // function
It is an object. It's also a function. Also, all functions are objects. They're all following the rules just fine.
alert((function(){}) instanceof Object) // true
alert((function(){}) instanceof Function) // true
alert(typeof (function(){})) // function
One big happy we-all-derive-from-Object family. Why should the prototype of Function not be a function?
Now if you wanna get weird... let's get weird.
var notAFn = Object.create(Function.prototype);
alert(notAFn instanceof Function); // true
alert(typeof notAFn); // object
And no, you can't call notAFn(). Not until they add a call Symbol for that. :)
Oh hey, feel free to tell me why this isn't a good answer. I'll try to improve it.

Function.prototype is a function

I'm digging into the Javascript prototype chain.
In order to document my findings, I've drawn the following scheme:
Although most of the concepts are clear, I'm left with just two related questions. Rather than splitting them up, I guessed that centralising them in this question might be better:
Is there a reason for Function.prototype to be of type function, instead of object?
typeof Function.prototype; //"function"
Is Function.prototype a 'unique function' in JS since it doesn't have a prototype property of its own like other functions do? (is there a generally accepted 'name' to refer to it?)
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 returns undefined 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 is false.
Number.prototype is a Number object whose value is +0.
Date.prototype is a Date object whose [[PrimitiveValue]] is NaN.
RegExp.prototype is a RegExp object whose data properties are like new 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; // false
Some host objects:
typeof document.createElement('object'); // "function
'prototype' in document.createElement('object'); // false
In ES6, arrow functions:
typeof (x => x * x); // "function
'prototype' in (x => x * x); // false
In answer to your questions:
1) Function.prototype is a type of function because, according to ECMAScript 2015:
The Function prototype object is the intrinsic object %FunctionPrototype%. The Function prototype object is itself a built-in function object.
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.
So the Function prototype object is only defined as a Function object to ensure compatability with older ECMAScript standards. The function doesn't actually do anything:
When invoked, it accepts any arguments and returns undefined.
http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-prototype-object
2) Regarding the prototype property:
The Function prototype object does not have a prototype property.
Same Source
This is unique since all functions usually possess a prototype property, however since the Function prototype object is only specified as a Function object to maintain compatability, it's behaviour is unlike that of regular functions.
I've created a JSFiddle with various tests in case it helps anyone:
http://jsfiddle.net/Ld0b39xz/
// We'll use 'Object.getPrototypeOf' to access [[prototype]]
// As you know, [[prototype]] of Object.prototype returns 'null'.
console.log(Object.getPrototypeOf(Object.prototype));
// null
////////////////////////////////////////////////////////
// Let's take a closer look at Function.prototype
console.log(Function.prototype);
// Output:
// function(){}
// This is what the specs say should happen:
// "The Function prototype object is itself a built-in function object."
/////////////////////////////////////////////////////
// Let's see if this function has a 'prototype' property.
// All functions normally have a prototype property that initially
// references an empty object...except this one.
var fn = Function.prototype;
console.log(fn.prototype);
// Output:
// undefined
// This is expected, according to the specs:
// "The Function prototype object does not have a prototype property."
// It does have some properties such as 'name' and 'length',
// but not 'prototype'.
////////////////////////////////////////////////////////
// Let's see what [[prototype]] of Function.prototype returns.
console.log(Object.getPrototypeOf(Function.prototype));
// Output:
// Object{}
// Again this is expected:
// "The value of the [[Prototype]] internal slot of the
// Function prototype object is the intrinsic object %ObjectPrototype%"
/////////////////////////////////////////////////////////
// Now lets see what the [[Prototype]] of this object is:
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function.prototype)));
// Output:
// null
// We've come full circle since all the statement above is
// doing is looking for the prototoype of the native Object,
// which we already know is 'null' from our first test.
In replacement of a previous answer which I could not stand by. With thanks to Oriol. The head scratching is mine.
In regards the first question the Function object it not particularly different simply because Function.prototype is a function. Other built in constructors use prototype objects of their own type. What draws attention to the Function case is that the typeof operator treats function objects diffently to other objects by returning "function" instead of "object".
Global constructors listing themselves as constructors of their prototype objects:
var BuiltIn = Function; // for example
BuiltIn.prototype.constructor == BuiltIn // true
is more or less documentary. Prototype objects of built in constructors generally have methods which interface with the javascript engine and are not created using a javascript call to their listed constructor as it appears at run time: Function.prototype instanceof Function is false with similar results for other built in constructors such as Array, RegExp etc tested.
The global Function object is unique, however, in that it lists itself as is its own constructor (Function.constructor == Function is true), and that it is an instance of itself (Function instanceof Function is true as well). The latter result indicates that Function.prototype is in the prototype chain of Function. Function.prototype itself is prototyped on Object.prototype.
Another reason to think Function.prototype is not a Function object in the usual sense (apart from saying so in the documentation) is that it cannot be called as a constructor and throws an error if an attempt is made to do so. Since the prototype property of a function is used when the function is called as a constructor, it makes sense for Function.prototype not to have this property.

Null prototype, Object.prototype and Object.create

Why is it that setting the prototype property of a constructor function to null does not prevent objects created from that function from calling through to methods on Object.prototype, in the same way that setting the prototype to Object.create(null) does?
That is, why is this the case:
function Foo(){}
Foo.prototype = null;
console.log(new Foo().toString); //outputs function toString() { [native code] } (or whatever)
function Foo(){}
Foo.prototype = Object.create(null);
console.log(new Foo().toString); //output undefined
In short
Yes, your observation is correct - a function constructed with the new operator will always have an object prototype in this case Object.prototype and this is indeed unlike a function created with Object.create.
On why
One can see this behavior completely specified in the ES5 language specification on which JavaScript is based on. Let's see this.
In new:
Quoting the specification of the [[Construct]] method of functions that indicates how object creation using the new operator is performed we can see that the following is specified:
If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.
In Object.create:
On the other hand, if we check out The spec for Object.create we can see that Object.create(o) specifies:
Set the [[Prototype]] internal property of obj to O.
Which means we can set it, it also explicitly checks that it is null or Object in that algorithm (please do follow the link to the spec and read it :))
So the prototype of the objects called with new Foo is Object.prototype and not null. It is impossible to create objects with no prototype without Object.create using standard methods only.

Is a constructor always a function object?

I'm reading the latest ECMA-262 reference, edition 5.1 June 2011.
In section 8.6.2 table 9 we have in regard to the [[Construct]] internal property:
Creates an object. Invoked via the new operator. The
arguments to the SpecOp are the arguments passed to the
new operator. Objects that implement this internal method
are called constructors.
The standard doesn't say that a constructor has to be a Function object. So can we have a constructor object that is not a function object?
Link to the standard as requested
The answer is extremely simple. ES5 § 4.3.4 says:
Constructor
Function object that creates and initialises objects.
So there you have it, by definition only a Function can be a constructor. However, likely there are host objects that behave like constructors that do not have any of the other attributes of native Function objects (e.g. the original XMLHttpRequest object in IE that was implemented in ActiveX).
While the term "Constructor" is defined (as #RobG pointed out), there is nothing that prevents a non-"Constructor" object from having a [[Construct]] method.
This is a bit confusing. It means you can use the new operator on an object that is not a Function (thus not a "constructor" as per 4.3.4
), but does indeed provide a [[Construct]] method.
Note that none of the standard objects qualify for that, but host objects may indeed. A browser plugin such as Java may expose some object like so:
new java.lang.String(); // it works, so java.lang.String has a [[Construct]] method
java.lang.String instanceof Function // false
Object.prototype.toString.call(java.lang.String).indexOf('Function') // -1
Note that typeof java.lang.String returns "function" even though java.lang.String is not a function. This is correct according to 11.4.3 (it is a host object with a [[Call]] method)
To add to Pumbaa80's answer (this would be too long for a comment).
The confusion is increased by 13.2.2 according to which when a function's construct is executed its call operation has to be executed(but it doesn't say what has to be done when the construct of an object that isn't a function is executed). Now, objects who implement call are callable function objects according to 9.11.
Also according to 4.2 "a function is a callable object". But of course this doesn't imply that every callable object is a function.
So if I got this right non Function objects can have a Construct method and also a Call method. java.lang.String would be one such example.

Categories

Resources