Stoyan Stefanov in his excellent book 'Object-Oriented JavaScript' says:
Any value that doesn't belong to one of the five primitive types listed above is an object.
With five primitive types he means Number
, String
, Boolean
, Undefined
and Null
. However in Google Chrome console it seems like number is not primitive type at all (compared to C
primitive types like int
). It looks like the primitive number has methods:
var a = 2.2;
console.log(a.toFixed()); // logs "2"
Thus I assumed that I can work with number as with an object, so I tried to assign a property to it:
var a = 2;
a.foo = 'bar';
console.log(a.foo); // logs undefined
I don't understand that behavior. If number has a method, it should behave like object, shouldn't it? It even has a prototype:
Number.prototype.foo = 'bar';
var a = 2;
console.log(a.foo); // logs 'bar'
So what is the magic behind this? How JavaScript treats objects versus primitive types? I would rather not use the word primitive and substitute it with simple objects. As I see it those are objects which can't be extended with new properties, however they are constructed through their constructor and also have prototype which can be extended like with normal objects.
The variable can be reassigned a new value but the existing value of the primitive cannot be changed like we do with arrays or objects. So this is one of the main differences between both types: Primitive Types are immutable and Object Types are mutable.
Primitives are passed by value, i.e. a copy of the primitive itself is passed. Whereas for objects, the copy of the reference is passed, not the object itself. Primitives are independent data types, i.e. there does not exist a hierarchy/super class for them. Whereas every Object is descendent of class "Object".
Primitive data types are number, string, boolean, NULL, Infinity and symbol. Non-primitive data types is the object. The JavaScript arrays and functions are also objects.
Java Type System Java has a two-fold type system consisting of primitives such as int, boolean and reference types such as Integer, Boolean. Every primitive type corresponds to a reference type. Every object contains a single value of the corresponding primitive type.
[...] It looks like the primitive number has methods
The primitive, does not actually has its own properties. It gets coerced to an object in order to be able to access "its" properties. The coerced object is not accessable outside the called Method *(In strict mode even not inside the method)*. As such, the referenced variable is always a primitive.
Consider this simple example:
Number.prototype.myTypeInAMethod = function () {
console.log (typeof this.valueOf ()) //"number" => The primitive is wrapped in an object.
return typeof this;
}
var num = 123;
typeof num; //number
num.myTypeInAMethod () //object
side note: In ES5s strict mode,this
would be a primitive and the type would be number
Since the variable num
is a primitive, you can not assign values to it.
num.foo = "bar";
num.foo //undefined
If you instead create a number (or string) via its object constructor, its type indeed is an object. A quick check by adding a property shows it can actually be assigned.
var objNum = new Number(123);
typeof objNum ; //"object"
objNum.foo = "bar";
objNum.foo //"bar"
So what is the magic behind this? How JavaScript treats objects versus primitive types?
This process is described in ES5 §8.7.1 GetValue
For an object:
Type(V)
is not Reference, return V.GetBase(V)
.IsUnresolvableReference(V)
, throw a ReferenceError exception.IsPropertyReference(V)
, then
HasPrimitiveBase(V)
is false, then let get be the [[Get]] internal method of base, otherwise let get be the special [[Get]] internal method defined below.GetReferencedName(V)
for the argument.GetBindingValue
(see 10.2.1) concrete method of base passing GetReferencedName(V)
and IsStrictReference(V)
as arguments.For a primitive:
The following [[Get]] internal method is used by GetValue when V is a property reference[1] with a primitive base value. It is called using base as its this value and with property P as its argument. The following steps are taken:
ToObject(base)
.IsDataDescriptor(desc)
is true, return desc.[[Value]].IsAccessorDescriptor(desc)
must be true so, let getter be desc.[[Get]].NOTE The object that may be created in step 1 is not accessible outside of the above method. An implementation might choose to avoid the actual creation of the object. The only situation where such an actual property access that uses this internal method can have visible effect is when it invokes an accessor function.
[1] IsPropertyReference(V)
. Returns true if either the base value is an object or HasPrimitiveBase(V)
is true; otherwise returns false.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With