What’s happening in this code with Number objects holding properties and incrementing the number?

Javascript

Javascript Problem Overview


A recent tweet contained this snippet of JavaScript.

Can someone please explain what is happening in it step by step?

> function dis() { return this }
undefined
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
> five * 5
25
> five.wtf
"potato"
> five++
5
> five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined
> five
6

In particular, it is not clear to me:

  • why the result of dis.call(5) is a Number with some kind of a [[PrimitiveValue]] property, but the results of five++ and five * 5 appear to just be the plain numbers 5 and 25 (not Numbers)
  • why the five.wtf property disappears after the five++ increment
  • why the five.wtf property is no longer even settable after the five++ increment, despite the five.wtf = 'potato?' assignment apparently setting the value.

Javascript Solutions


Solution 1 - Javascript

OP here. Funny to see this on Stack Overflow :)

Before stepping through the behaviour, its important to clarify a few things:

  1. Number value and Number object (a = 3 vs a = new Number(3)) are very different. One is a primitive, the other is an object. You cannot assign attributes to primitives, but you can to objects.

  2. Coercion between the two is implicit.

    For example:

    (new Number(3) === 3)  // returns false
    (new Number(3) == 3)   // returns true, as the '==' operator coerces
    (+new Number(3) === 3) // returns true, as the '+' operator coerces
    
  3. Every Expression has a return value. When the REPL reads and executes an expression, this is what it displays. The return values often don't mean what you think and imply things that just aren't true.

Ok, here we go.

Original image of the JavaScript code

The pledge.
> function dis() { return this }
undefined
> five = dis.call(5)
[Number: 5]

Define a function dis and call it with 5. This will execute the function with 5 as the context (this). Here it is coerced from a Number value to a Number object. It is very important to note that were we in strict mode this would not have happened.

> five.wtf = 'potato'
'potato'
> five.wtf
'potato'

Now we set the attribute five.wtf to 'potato', and with five as an object, sure enough it accepts the Simple Assignment.

> five * 5
25
> five.wtf
'potato'

With five as an object, I ensure it can still perform simple arithmetic operations. It can. Do its attributes still stick? Yes.

The turn.
> five++
5
> five.wtf
undefined

Now we check five++. The trick with postfix increment is that the entire expression will evaluate against the original value and then increment the value. It looks like five is still five, but really the expression evaluated to five, then set five to 6.

Not only did five get set to 6, but it was coerced back into a Number value, and all attributes are lost. Since primitives cannot hold attributes, five.wtf is undefined.

> five.wtf = 'potato?'
'potato?'
> five.wtf
undefined

I again attempt to reassign an attribute wtf to five. The return value implies it sticks, but it in fact does not because five is a Number value, not a Number object. The expression evaluates to 'potato?', but when we check we see it was not assigned.

The prestige.
> five
6

Ever since the postfix increment, five has been 6.

Solution 2 - Javascript

There are two different ways to represent a number:

var a = 5;
var b = new Number(5);

The first is a primitive, the second an object. For all intents and purposes both behave the same, except they look different when printed to the console. One important difference is that, as an object, new Number(5) accepts new properties just like any plain {}, while the primitive 5 does not:

a.foo = 'bar';  // doesn't stick
b.foo = 'bar';  // sticks

As for the initial dis.call(5) part, please see https://stackoverflow.com/q/3127429/476. Let's just say that the first argument to call is used as the value of this, and that this operation forces the number into the more complex Number object form.* Later on ++ forces it back into the primitive form, because the addition operation + results in a new primitive.

> five = dis.call(5)  // for all intents and purposes same as new Number(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"

A Number object accepts new properties.

> five++

++ results in a new primitive 6 value...

> five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined

...which does not have and does not accept custom attributes.

* Note that in strict mode the this argument would be treated differently and would not be converted to a Number. See http://es5.github.io/#x10.4.3 for the implementation details.

Solution 3 - Javascript

There's Coercion in the JavaScript World - A Detective Story

Nathan, you have no idea what you've uncovered.

I've been investigating this for weeks now. It all started on a stormy night last October. I accidentally stumbled upon the Number class - I mean, why in the world did JavaScript have a Number class?

I wasn't prepared for what I was going to find out next.

It turns out that JavaScript, without telling you, has been changing your numbers to objects and your objects to numbers right under your nose.

JavaScript was hoping no one would catch on, but people have been reporting strange unexpected behavior, and now thanks to you and your question I have the evidence I need to blow this thing wide open.

This is what we've found out so far. I don't know if I should even be telling you this - you might want to turn off your JavaScript.

> function dis() { return this }
undefined

When you created that function, you probably had no idea what was going to happen next. Everything looked fine, and everything was fine - for now.

No error messages, just the word "undefined" in console output, exactly what you would expect. After all, this was a function declaration - it isn't supposed to return anything.

But this was just the beginning. What happened next, no one could have predicted.

> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

Yeah I know, you expected a 5, but that's not what you got, was it - you got something else - something different.

The same thing happened to me.

I didn't know what to make of it. It drove me nuts. I couldn't sleep, I couldn't eat, I tried to drink it away, but no amount of Mountain Dew would make me forget. It just didn't make any sense!

That's when I found out what was really going on - it was coercion, and it was happening right there in front of my eyes, but I was too blind to see it.

Mozilla tried to bury it by putting it where they knew nobody would look - their documentation.

After hours of recursively reading and re-reading and re-re-reading I found this:

> "... and primitive values will be converted to objects."

It was right there plain as can be spelled out in Open Sans font. It was the call() function - how could I be so stupid?!

My number was no longer a number at all. The moment I passed it into call(), it became something else. It became... an object.

I couldn't believe it at first. How could this be true? But I couldn't ignore the evidence that was mounting up around me. It's right there if you just look:

> five.wtf = 'potato'
"potato"

> five.wtf
"potato"

wtf was right. Numbers can't have custom properties - we all know that! It's the first thing they teach you at the academy.

We should have known the moment we saw the console output - this was not the number we thought it was. This was an impostor - an object passing itself off as our sweet innocent number.

This was... new Number(5).

Of course! It made perfect sense. call() had a job to do, he had to invoke a function, and to do that he needed to populate this, he knew he couldn't do that with a number - he needed an object and he was willing to do anything to get it, even if that meant coercing our number. When call() saw the number 5, he saw an opportunity.

It was the perfect plan: wait until no one was looking and swap out our number for an object that looks just like it. We get a number, the function gets invoked, and no one would be the wiser.

It really was the perfect plan, but like all plans, even perfect ones, there was a hole in it, and we were about to fall right into it.

See, what call() didn't understand was that he wasn't the only one in town who could coerce numbers. This was JavaScript after all - coercion was everywhere.

call() took my number, and I wasn't going to stop until I pulled the mask off of his little impostor and expose him to the whole Stack Overflow community.

But how? I needed a plan. Sure it looks like a number, but I know it's not, there's gotta be a way to prove that. That's it! It looks like a number, but can it act like one?

I told five I need him to become 5 times larger - he didn't ask why and I didn't explain. I then did what any good programmer would do: I multiplied. Surely there was no way he could fake his way out of this.

> five * 5
25
> five.wtf
'potato'

Damn it! Not only did five multiply just fine wtf was still there. Damn this guy and his potato.

What the hell was going on? Was I wrong about this whole thing? Is five really a number? No, I must be missing something, I know it, there's something I must be forgetting, something so simple and basic that I'm completely overlooking it.

This was not looking good, I had been writing this answer for hours and I was still no closer to making my point. I couldn't keep this up, eventually people would stop reading, I had to think of something and I had to think of it fast.

Wait that's it! five wasn't 25, 25 was the result, 25 was a completely different number. Of course, how could I forget? Numbers are immutable. When you multiply 5 * 5 nothing gets assigned to anything you just create a new number 25.

That must be what's happening here. Somehow when I multiply five * 5, five must be getting coerced into a number and that number must be the one used for the multiplication. It's the results of that multiplication that gets printed to the console, not the value of five itself. five never gets assigned anything - so of course it doesn't change.

So then how do I get five to assign himself the result of an operation. I got it. Before five even had a chance to think, I yelled "++".

> five++
5

Aha! I had him! Everybody knows 5 + 1 is 6, this was the evidence I needed to expose that five was not a number! It was an impostor! A bad impostor that didn't know how to count. And I could prove it. Here's how a real number acts:

> num = 5
5
> num++
5

Wait? What was going on here? sigh I got so caught up in busting five that I forget how post operators work. When I use the ++ at the end of five I'm saying return the current value, then increment five. It's the value before the operation occurs that gets printed to the console. num was in fact 6 and I could prove it:

>num
6

Time to see what five really was:

>five
6

...it was exactly what it should be. five was good - but I was better. If five were still an object that would mean it would still have the property wtf and I was willing to bet everything it didn't.

> five.wtf
undefined

Aha! I was right. I had him! five was a number now - it wasn't an object anymore. I knew the multiplication trick wouldn't save it this time. See five++ is really five = five + 1. Unlike the multiplication, the ++ operator assigns a value to five. More specifically, it assigns it the results of five + 1 which just like in the case of multiplication returns a new immutable number.

I knew I had him, and just to make sure he couldn't squirm his way out of it. I had one more test up my sleeve. If I was right, and five was really a number now, then this wouldn't work:

> five.wtf = 'potato?'
'potato?'

He wasn't going to fool me this time. I knew potato? was going to be printed to the console because that's output of the assignment. The real question is, will wtf still be there?

> five.wtf
undefined

Just as I suspected - nothing - because numbers can't be assigned properties. We learned that the first year at the academy ;)

Thanks Nathan. Thanks to your courage in asking this question I can finally put all this behind me and move on to a new case.

Like this one about the function toValue(). Oh dear god. Nooo!

Solution 4 - Javascript

01 > function dis() { return this }
02 undefined
03 > five = dis.call(5)
04 Number {[[PrimitiveValue]]: 5}
05 > five.wtf = 'potato'
06 "potato"
07 > five.wtf
08 "potato"
09 > five * 5
10 25
11 > five.wtf
12 "potato"
13 > five++
14 5
15 > five.wtf
16 undefined
17 > five.wtf = 'potato?'
18 "potato?"
19 > five.wtf
20 undefined
21 > five
22 6

01 declares a function dis that returns the context object. What this represents changes depending on whether you're using strict mode or not. The entire example has different results if the function were declared as:

> function dis() { "use strict"; return this }

This is detailed in section 10.4.3 in the ES5 specification

> 1. If the function code is strict code, set the ThisBinding to thisArg. > 1. Else if thisArg is null or undefined, set the ThisBinding to the global object. > 1. Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).

02 is the return value of the function declaration. undefined should be self explanatory here.

03 the variable five is initialized with the return value of dis when called in the context of the primitive value 5. Because dis is not in strict mode, this line is identical to calling five = Object(5).

04 The odd Number {[[PrimitiveValue]]: 5} return value is the representation of the object that wraps the primitive value 5

05 the five object's wtf property is assigned a string value of 'potato'

06 is the return value of the assignment and should be self explanatory.

07 the five object's wtf property is being examined

08 as five.wtf was previously set to 'potato' it returns 'potato' here

09 the five object is being multiplied by the primitive value 5. This is no different from any other object being multiplied and is explained in section 11.5 of the ES5 specification. Of particular note is how objects are cast to numeric values, which is covered in a few sections.

9.3 ToNumber:

> 1. Let primValue be ToPrimitive(input argument, hint Number). > 2. Return ToNumber(primValue).

9.1 ToPrimitive:

> Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

8.12.8 [[DefaultValue]]:

> Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf". > > 1. If IsCallable(valueOf) is true then, > > 1. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list. > 2. If val is a primitive value, return val.

This is all a roundabout way of saying that the object's valueOf function gets called and the return value from that function is used in the equation. If you were to change the valueOf function you could change the results of the operation:

> five.valueOf = function () { return 10 }
undefined
> five * 5
50

10 as fives valueOf function was unchanged, it returns the wrapped primitive value 5 so that five * 5 evaluates to 5 * 5 which results in 25

11 the five object's wtf property is evaluated again despite having been unchanged from when it was assigned on 05.

12 'potato'

13 the Postfix Increment Operator is called on five, which gets the numeric value (5, we covered how earlier), stores the value so that it can be returned, adds 1 to the value (6), assigns the value to five, and returns the stored value (5)

14 as before, the returned value is the value before it was incremented

15 the wtf property of the primitive value (6) stored at the variable five is accessed. Section 15.7.5 of the ES5 specification defines this behavior. Numbers get the properties from Number.prototype.

16 Number.prototype doesn't have a wtf property, so undefined is returned

17 five.wtf is assigned a value of 'potato?'. Assignment is defined in 11.13.1 of the ES5 specification. Basically the value assigned is returned but not stored.

18 'potato?' was returned by the assignment operator

19 again five, which has a value of 6 is accessed, and again Number.prototype doesn't have a wtf property

20 undefined as explained above

21 five is accessed

22 6 is returned as explained in 13

Solution 5 - Javascript

It's pretty simple.

function dis () { return this; }

This returns the this context. So, if you do call(5) you're passing the number as an object.

The call function doesn't supply arguments, the first argument you give is the context of this. Usually if you want it on it's on context, you give it {} so dis.call({}), which means this in the function is an empty this. However, if you pass 5 it seems it will be converted to an object. See .call

So the return is object

When you do five * 5, JavaScript sees the object five as the primitive type, so is equivalent to 5 * 5. Interestingly, do '5' * 5, it still equals 25, so JavaScript is clearly casting under the hood. No changes to the underlying five type is done on this line

But when you do ++ it will convert the object to the primitive number type thus removing the .wtf property. Because you are affecting the underlying type

Solution 6 - Javascript

The primitive values can't have property. But when you try to access to a property on primitive value, it transparently transtype to a temporary Number object.

So:

> function dis() { return this }
undefined
// Like five.dis(), so dis return the temporaty Number object and 
// reference it in five
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

// Write the wtf attribut on the Number object referenced by five
> five.wtf = 'potato'
"potato"
// Read the wtf attribut on the Number object referenced by five
> five.wtf
"potato"

// Return 5*5 but dont change the reference of five
> five * 5
25
// Read the same wtf attribut on the Number object referenced by five
> five.wtf
"potato"

// Change the five reference to a new primitive value (5+1). Five
// reference a primitive now.
> five++
5

// Read the wtf attribut on a new temporary Number object construct from
// the primitive referenced by five. So wtf does not exist.
> five.wtf
undefined

// Write the wtf attribut on a new temporary Number object construct from
// the primitive referenced by five. But this object not referenced by
// five. It will be lost.
> five.wtf = 'potato?'
"potato?"

// Read the wtf attribut on a new temporary Number object construct from
// the primitive referenced by five. So wtf does not exist.
> five.wtf
undefined
> five
6

Solution 7 - Javascript

Declare function dis. Function returns its context

function dis() { return this }
undefined

Call dis with context 5. Primitive values are boxed when passed as context in strict mode (MDN). So five now is object (boxed number).

five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

Declare wtf property on five variable

five.wtf = 'potato'
"potato"

Value of five.wtf

five.wtf
"potato"

five is boxed 5, so it's number and object at the same time (5 * 5 = 25). It doesn't changes five.

five * 5
25

Value of five.wtf

five.wtf
"potato"

Unboxing five here. five now is just primitive number. It prints 5, and then add 1 to five.

five++
5

five is primitive number 6 now, there are no properties in it.

five.wtf
undefined

primitives cannot have properties, you can't set this

five.wtf = 'potato?'
"potato?"

you can't read this, because it was not set

five.wtf
undefined

five is 6 because of post incrementing above

five
6

Solution 8 - Javascript

First off it looks like this is being run through the nodejs console.

    function dis() { return this }

creates the function dis(), but because it wasn't set as a var there was no value to return so undefined was the output, even though dis() was defined. On a sidenote, this wasn't returned because the function wasn't executed.

    five = dis.call(5)

This returns javascript's Number object because you just set the function dis()'s this value to the primitive five.

   five.wtf = 'potato'

The first returns "potato" because you just set the property wtf of five to 'potato'. Javascript returns the value of a variable you set, making it easy to chain multiple variables and set them to the same value like this: a = b = c = 2.

    five * 5

This returns 25 because you just multiplied the primitive number 5 to five. The value of five was determined by the value of the Number object.

    five.wtf

I skipped this line before because I would be repeating it here. It just returns the value of the property wtf that you set above.

    five++

As @Callum said, ++ will convert the type to number from the same value from the object Number {[[PrimitiveValue]]: 5}}.

Now because five is a number, you can't set properties to it anymore until you do something like this:

    five = dis.call(five)
    five.wtf = "potato?"

or

    five = { value: 6, wtf: "potato?" }

Also note that the second way will have different behavior than using the first method because it is defining a generic object instead of the Number object that was created before.

I hope this helps, javascript likes to assume things, so it can get confusing when changing around from the Number object to a primitive number. You can check what type something is by using the typeof keyword, writing typeof five after you initialize it returns 'object', and after you do five++ it returns 'number'.

@deceze describes the difference between the Number object and the primitive number extremely well.

Solution 9 - Javascript

JavaScript scopes are made of Execution Contexts. Each Execution Context has a Lexical Environment (external/globally scoped values), a Variable Environment (locally scoped values), and a this binding.

The this binding is a very important part of the Execution Context. Using call is one way to alter the this binding, and doing so will automatically create an object to populate the binding with.

Function.prototype.call() (from MDN)

> Syntax
> fun.call(thisArg[, arg1[, arg2[, ...]]]) > > thisArg
> The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object and primitive values will be converted to objects. (emphasis mine)

Once it is evident that 5 is being converted into new Number(5), the rest should be rather obvious. Note that other examples will also work so long as they are primitive values.

function primitiveToObject(prim){
  return dis.call(prim);
}
function dis(){ return this; }

//existing example
console.log(primitiveToObject(5));

//Infinity
console.log(primitiveToObject(1/0));

//bool
console.log(primitiveToObject(1>0));

//string
console.log(primitiveToObject("hello world"));

<img src="http://i.stack.imgur.com/MUyRV.png" />

enter image description here

Solution 10 - Javascript

A couple of concepts explain what happens

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().

Now to put it all together

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;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNathan LongView Question on Stackoverflow
Solution 1 - JavascriptMatthewView Answer on Stackoverflow
Solution 2 - JavascriptdecezeView Answer on Stackoverflow
Solution 3 - JavascriptLuis PerezView Answer on Stackoverflow
Solution 4 - JavascriptzzzzBovView Answer on Stackoverflow
Solution 5 - JavascriptCallum LiningtonView Answer on Stackoverflow
Solution 6 - JavascriptTechnivView Answer on Stackoverflow
Solution 7 - JavascriptMaxxView Answer on Stackoverflow
Solution 8 - JavascriptPatrick BarrView Answer on Stackoverflow
Solution 9 - JavascriptTravis JView Answer on Stackoverflow
Solution 10 - JavascriptTibosView Answer on Stackoverflow