A recent tweet contained this snippet of JavaScript.
Can someone please explain what is happening in it step by step?
> function dis() { return th
5
is a number, a primitive value
Number {[[PrimitiveValue]]: 5}
is an instance of Number (let's call it object wrapper)
Whenever you access a property/method on a primitive value, the JS engine will create an object wrapper of the appropriate type (Number
for 5
, String
for 'str'
and Boolean
for true
) and resolve the property access/method call on that object wrapper. This is what happens when you do true.toString()
for example.
When performing operations on objects, they are converted to primitive values (by using toString
or valueOf
) in order to resolve those operations - for example when doing
var obj = { a : 1 };
var string = 'mystr' + obj;
var number = 3 + obj;
string
will hold the string concatenation of mystr
and obj.toString()
and number
will hold the addition of 3
and obj.valueOf()
.
five = dis.call(5)
dis.call(5)
behaves just like (5).dis()
if 5
actually had the method dis
. In order to resolve the method call, the object wrapper is created and the method call is resolved on it. At this point five points to an object wrapper around the primitive value 5.
five.wtf = 'potato'
Setting a property on an object, nothing fancy here.
five * 5
This is actually five.valueOf() * 5
obtaining the primitive value from the object wrapper. five
still points to the initial object.
five++
This is actually five = five.valueOf() + 1
. Before this line five
holds the object wrapper around the value 5, while after this point five
holds the primitive value 6
.
five.wtf
five.wtf = 'potato?'
five.wtf
five
is no longer an object. Each of those lines creates a new instance of Number in order to resolve the .wtf
property access. The instances are independent, so setting a property on one will not be visible on another. The code is completely equivalent to this one:
(new Number(6)).wtf;
(new Number(6)).wtf = 'potato?';
(new Number(6)).wtf;