This question already has answers here:
Why can't I access a property of an integer with a single dot?
(5 answers)
Closed 5 years ago.
If you look at the ECMAScript 3 specification you will see that primitive value types Null and Undefined don't have accompanying Null and Undefined Objects.
>> Null
ReferenceError: Null is not defined
The other primitive value types Number, String and Boolean types do have accompanying Number, String and Boolean objects which you can reference from global scope.
>>Number
function Number() { [native code] }
>>Boolean
function Boolean() { [native code] }
The purpose for these primitive value types is to provide methods such as toString and valueOf for their respective primitive value types:
>>var n = 1;
>>n.toString();
"1"
is the same as
>>var n = 1;
>>Number.prototype.toString.call(n);
"1"
Booleans and strings also work that way:
>>var b = true;
>>b.toString();
"true"
>>Boolean.prototype.toString.call(b);
"true"
You can see that the primitive value objects are using the methods of their accompanying object when you try to mix types:
>>Boolean.prototype.toString.call(n);
TypeError: Boolean.prototype.toString is not generic
>>Number.prototype.toString.call(b)
TypeError: Number.prototype.toString is not generic
Interestingly enough for boolean and string literal types, you can call these methods directly from the literal:
>>true.toString();
"true"
>>Boolean.prototype.toString.call(true)
"true"
>>"moo".toString();
"moo"
>>String.prototype.toString.call("moo")
"moo"
Primitive values null and undefined, since they don't have accompanying Null and Undefined objects cannot do these things:
>>Null
ReferenceError: Null is not defined
>>null.toString()
TypeError: Cannot call method 'toString' of null
Primitive value type number behaves like a mix of the two. You can call toString on a literal if you directly use the Number's prototype object's method:
>>Number.prototype.toString.call(1);
"1"
But you cannot access the method from the literal itself like you can with strings and booleans:
>>1.toString()
SyntaxError: Unexpected token ILLEGAL
Why is it that number literals behave differently from boolean and string even though there's a Number object?
You can access it the same way, it's a different parsing issue here, to do it, use a slightly different syntax:
(1).toString()
Numbers can have decimals, so the syntax for ending in a decimal is a bit ambiguous when you go to parse the code, use parenthesis to be valid. It's a bit clearer when you see that this is also valid:
(1.).toString()
However with just 1.toString() it's trying to parse as a number with a decimal, and it fails.
I think you'll find an answer to your question in this answer to another Stack Overflow question. To summarize Theo's answer:
[T]he parser expects a number followed
by a dot to be a floating point
literal. [...] [Y]ou only have to add another dot to make it work[.]
Null (capital N) is a variable name. Reserved words are case sensitive. null is the object null. typeof null === "object" //true
Related
As per MDN the in operator returns true if the property exists and accordingly the first example logs true. But when using a string literal, why is it throwing an error instead of logging false?
let let1 = new String('test');
console.log(let1.length);
console.log('length' in let1)
var let1 = 'test';
console.log(let1.length);
console.log('length' in let1);
In a sense it is a matter of timing. String literals do not have any properties. The reason that you can call methods and lookup properties on primitive strings is because JavaScript automatically wraps the string primitive in a String object when a method call or property lookup is attempted. JavaScript does not interpret the in operator as a method call or property lookup so it does not wrap the primitive in an object and you get an error (because a string primitive is not an object).
See Distinction between string primitives and String objects
Also, the same docs referenced in your question specifically note that using in on a string primitive will throw an error.
You must specify an object on the right side of the in operator. For
example, you can specify a string created with the String constructor,
but you cannot specify a string literal.
It throws an error because in is an operator for objects:
prop in object
but when you declare a string as `` (` string(template) literals) or "" '' (",' string literals) you don't create an object.
Check
typeof new String("x") ("object")
and
typeof `x` ("string").
Those are two different things in JavaScript.
JavaScript operator in only applicable to an Objects instances.
When you using constructor new String('abc') this will causing creating of a String object instance.
In other side, when you using only string literals or call function String('abc') without new it creates an string primitive. (like Number and Boolen)
Some behaviour of primitives and objects is differrent, look at this simple example's output:
console.log(typeof (new String('ddd'))) // "object"
console.log(typeof ('ddd')) // "string"
console.log(eval('1 + 2')) // 3
console.log(eval(new String('1 + 2'))) // {"0":"1","1":" ","2":"+","3":" ","4":"2"}
In code where you use methods on string primitives javascript engine automatically wraps primitives with corresponding objects to perform methods call.
But in it is not an method call, its language operator an in this case wrapping is not applied.
PS: Sorry for my english.
typeof('test') == string (string literal)
typof(new String('test')) == object (string object)
you can't use in with a string literal.
The in operator returns true if the specified property is in the specified object or its prototype chain.
The in operator can only be used to check if a property is in an
object. You can't search in strings, or in numbers, or other primitive
types.
The first example works and prints 'true' because length is a property of a string object.
The second example doesn't work and gives you an error because you are trying to look for a property length in something (a string) that is not an object.
Please help me understand prototype inheritance in this case:
Why does 'abc'.hasOwnProperty('length') return true but 'length' in 'abc' throws an error?
The expression 'abc'.hasOwnProperty('length') is interpreted by JavaScript as
(new String('abc')).hasOwnProperty('length')
Every (capital-S) String instance has its own length property, which gives the length of the string.
JavaScript (lower-case s) string instances are primitives and do not have any properties at all. The use of a string primitive as the left-hand side of the . operator causes the string primitive to be implicitly wrapped in a String object (at least conceptually; the runtime doesn't really have to instantiate a transient object) and that's where the .length property comes from.
The expression length in 'abc' throws an exception because there's no implicit promotion of the primitive 'abc' to a String instance with the in operator. Thus since a primitive cannot have any properties, and the concept makes no sense, it's an exception.
There are plenty of discussions about what null in JavaScript actually is. For example, Why is null an object and what's the difference between null and undefined?.
MDN lists null among primitive values and states that it is:
a special keyword denoting a null value; null is also a primitive
value
(The above emphasis is mine)
My last reference will be to Programming JavaScript Applications book by Eric Elliott, which in its Chapter 3. Objects says the following:
In JavaScript, ... even primitive types
get the object treatment when you refer to them with the property
access notations. They get automatically wrapped with an object so
that you can call their prototype methods.
Primitive types behave like objects when you use the property access notations, but you can't assign new properties to them. Primitives
get wrapped with an object temporarily, and then that object is
immediately thrown away. Any attempt to assign values to properties
will seem to succeed, but subsequent attempts to access that new
property will fail.
And indeed the following statements will execute without a problem:
"1".value = 1;
(1).value = "1";
false.value = "FALSE";
while his one
null.value = "Cannot set property of null";
throws Uncaught TypeError. See JS Fiddle.
So at least in this regard, null behaves differently than other primitives.
Is null considered a regular primitive in JavaScript?
Yes it's an actual primitive.
The exceptions for property access are null and undefined, because they have no wrapper type like strings, booleans and numbers do.
ECMAScript 5, Section 4.3.2 primitive
value
member of one of the types Undefined, Null, Boolean, Number, or String
as defined in Clause 8.
NOTE A primitive value is a datum that is represented directly at the
lowest level of the language implementation.
in firebug console :
>>> a=12
12
>>> a.__proto__
Number {}
>>> (12).__proto__
Number {}
>>> a.constructor.prototype === (12).__proto__
true
>>> a.constructor.prototype.isPrototypeOf(a)
false
the final line causes me a great confusion as compared to the other lines. also see Constructor.prototype not in the prototype chain?
When you use the . operator with a primitive, the language auto-boxes it with the appropriate Object type (in this case, Number). That's because simple primitive types in JavaScript really are not Object instances.
Thus, the actual left-hand side of
a.__proto__
is not the number 12 but essentially new Number(12). However, the variable "a" continues to be the simple number value 12.
edit — Section 8.7 of the spec "explains" this with typical ECMA 262 moon language. I can't find a clear paragraph that describes the way that a primitive baseValue is treated as a Number, Boolean, or String instance, but that section directly implies it. I think that because those non-primitive synthetic values are ephemeral (they're only "real" while the . or [] expression is being evaluated) that the spec just talks about the behavior without explicitly requiring that an actual Number is constructed. I'm guessing on that however.
#Pointy has explained it very well. Basically, if you want your last statement to be true, you would have to write it like:
a.constructor.prototype.isPrototypeOf(new Number(a));
In JavaScript primitives do not have a prototype chain. Only objects do. A primitive value includes:
Booleans
Numbers
Strings
Null
Undefined
Hence if you call isPrototypeOf with a primitive value then it'll always return false.
If you try to use a boolean, number or string as an object then JavaScript automatically coerces it into an object for you. Hence a.constructor evaluates to new Number(a).constructor behind the scenes. This is the reason you can use a primitive value as an object.
If you wish to use a variable storing a primitive value as an object often then it's better to explicitly make it an object. For example in your case it would have been better to define a as new Number(12). The advantages are:
JavaScript doesn't need to coerce the primitive to an object every time you try to use it as an object. You only create the object once. Hence it's performance efficient.
The isPrototypeOf method in your case will return true as a will be an instance of Number. Hence it will have Number.prototype in its prototype chain.
Would someone explain the difference between an undefined value and Undefined type, and similarly the same for null values and Null types?
Bonus: why do boolean, string, and number have values, types, and objects, and null and undefined have only values and types (no objects)? If "everything is an object", then one would assume we have objects for all available values, yes? Where's my Infinity and NaN objects?
null and undefined are values. Coincidentally (or just a wise choice), their types are null respectively undefined, as defined null value/type, undefined value/type in the specification. This can also be shown by using the typeof operator:
typeof undefined; // "undefined"
typeof null ; // "null" (in ES6) and "object" in <=ES5 (bug)
A value is associated with a type, which indicates the "kind" of a value.
To give an answer to the question "What is the difference between a value and a type?":
Think of a type as some kind of category and a value is a concrete instance in that category.
For example, we have the type String and a concrete value would be "foo". There can be many different values of type String, but there are only one possible value for the Null and Undefined types, which are null and undefined respectively.
Section 4.3 of the specification is most helpful IMO. Here you find for example the information about strings and the difference between value, type and object.
4.3.16 String value
primitive value that is a finite ordered sequence of zero or more 16-bit unsigned integer.
NOTE: A String value is a member of the String type. Each integer value in the sequence usually represents a single 16-bit unit of UTF-16 text. However, ECMAScript does not place any restrictions or requirements on the values except that they must be 16-bit unsigned integers.
4.3.17 String type
set of all possible String values.
4.3.18 String object
member of the Object type that is an instance of the standard built-in String constructor.
NOTE: A String object is created by using the String constructor in a new expression, supplying a String value as an argument. The resulting object has an internal property whose value is the String value. A String object can be coerced to a String value by calling the String constructor as a function (15.5.1).
It's similar for null and undefined, though they don't have equivalent objects. Why? For that you'd have to ask those who define that language ;)
If "everything is an object", then one would assume we have objects for all available values, yes?
A more correct statement would be "nearly everything is an object", primitive values are not objects obviously, but most of them have an object equivalent (which should actually not be used) and for the others we don't care. Fact is that JavaScript is mainly object oriented.
Where's my Infinity and NaN objects?
Infinity and NaN are values of type Number, so you could create Number objects, like so:
new Number(1/0) // Infinity
new Number("a") // NaN
but you rarely use Number objects anyway.
typeof null === "object"
just to rule that out. null gets treated as an object. Not everything in ECMAscript is an object. The "other side" are the such called "primitive values". Primitive values are, simply spoken, plain values which were not created by any Object constructor. For instance:
var prim = 23;
prim.foo = true;
console.log( 'prim is: ', prim, 'prim.foo is: ', prim.foo ); // "prim is 23, prim.foo is: undefined"
On the other hand
var prim = new Number(23);
prim.foo = true;
console.log( 'prim is: ', +prim, 'prim.foo is: ', prim.foo ); // "prim is 23, prim.foo is: true"
Notice, that I explicitly cast the prim on the second snippet with the plus operator. The second we operate on such a "primitive value", ECMAscript (or more precisely, its engine) will convert that value into its Object representation internally anyway. So you point was actually pretty much correct, "everything is an object".
undefined is a defined value (even if it sounds silly):
'undefined' in window // true
whereas null is a type, which is just part of the language.