denysdovhan / wtfjs

🤪 A list of funny and tricky JavaScript examples
http://bit.ly/wtfjavascript
Do What The F*ck You Want To Public License
34.97k stars 2.55k forks source link

multiple assignement with objects #90

Closed arouene closed 3 years ago

arouene commented 5 years ago
var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2}

foo.x // undefined
foo    // {n: 2}
bar    // {n: 1, x: {n: 2}}

foo.x == undefined, but bar.x == foo

tammorelli commented 5 years ago

I will try to explain to the best of my knowledge. I reserve the right to be completely wrong ;D

var foo = {n: 1}; --> this is placing content in some point A in memory, "foo" is the address to point A. var bar = foo; --> "bar" has the same address as "foo", so it points to the same content in point A. foo.x = foo = {n: 2}; --> this is worked right to left, so first:

foo = {n: 2}; --> this is placing content in some point B in memory, "foo" has a new address, now to point B. Note that "bar" is unaltered, it stills point to content in address A.

Then: foo.x = foo; --> To my understand, while the line is processed right to left, all references in it are set before the process start, like "foo.x" here "foo" is the address of point A in memory(effective being "bar.x"), while the "foo" on the right has the address to the new point B in memory.

I do not think that is a strange behavior to js, just that pointers are somewhat counterintuitive.

Sanva commented 5 years ago

@tammorelli

To my understand, while the line is processed right to left, all references in it are set before the process start ...

That would be indeed a very strange behavior — it's simply that the member access operator (the dot [.]) has higher precedence and the assignment operator returns the same value it just assigned, so

foo.x = foo = {n: 2}; is not the same as foo = {n: 2}; and then foo.x = foo; — it is fooX = address_of(foo.x), then foo = {n: 2}; and then fooX = {n: 2};.

By the way, you couldn't do this in two lines without my fictional address_of because the foo.x expression doesn't return the same in a = foo.x than in foo.x = a. In the first case foo.x means rvalue of foo.x, and in the second one it means it's lvalue.

When you have pointers (e.g. int *p), basically you decide whether you are using the address of the pointer as an lvalue (p = malloc(...) is using the lvalue of p), the address of the pointed thing as an lvalue (*p = 5 is using the lvalue of *p), the rvalue of the pointed thing (int a = *p uses the rvalue of *p)...

In some languages, like C++, you can even do this: ((i < 3) ? i : j) = 7;, because the conditional operator return an lvalue.

arouene commented 5 years ago

@tammorelli

I do not think that is a strange behavior to js, just that pointers are somewhat counterintuitive.

I agree with your analysis, but I believe it could have it's place in the examples of wtfjs !

denysdovhan commented 5 years ago

PR is welcome.