Letās ride on some WTF with JavaScript Arrays.
[] ==Ā ![]
This happens because of [precedence](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)
and [coercion](https://www.safaribooksonline.com/library/view/you-dont-know/9781491905159/ch04.html)
.
Side noteāāāPrecedence determines the order from which operators are executed. The highest the precedence the sooner the operation will be performed. For instance, _*_
has an higher precedence than the operator _+_
. As for Coercion, this is JS ability to convert one of the operands (of an operator) to an āequivalentā value of the other operand. This happens when the operandsā type are different. For instance, for _boolean == integer_
Ā , the _boolean_
operand will be converted into an _integer_
.
Due to [precedence](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)
JS executes first the operationĀ ![]
and then ==
.
The logical NOT operationĀ ![]
negates the truthy of []
and returns the boolean false
. On a step-by-step:
- Evaluate the expression
[]
; - Convert the result to boolean, i.e.
ToBoolean([])
. By definition the result istrue
; - Return
false
, which is the logical negation oftrue
;
We got
**[] == false**
.
Now, it comes [coercion](https://www.safaribooksonline.com/library/view/you-dont-know/9781491905159/ch04.html)
into play.
Because our second operand is a boolean, the operation is translated into [] == ToNumber(false)
. ToNumber
of a boolean returns 1
when true
or 0
when false
(see the specification).
We got
**[] == 0**
.
By specification, [] == 0
translates into ToPrimitive([]) == 0
, which in turn results into the operation OrdinaryToPrimitive([], "number") == 0
.
OrdinaryToPrimitive
for the parameters Object
and "number"
runs both methodsĀ **.valueOf()**
andĀ **.toString()**
of the Object
and returns the result which is not an object. In our case, because [].valueOf()
returns an object (i.e. []
), the result of [].toString()
is returned instead (i.e. ""
).
We got
**"" == 0**
.
Patience. We are almost there š
Now, once the first operand is a string, our operation is translated into ToNumber("") == 0
. By definition, an empty string is converted into 0
.
We got
**0 == 0**
.
Which is true
š
There youĀ go!
Note: I went as deep I could on this first WTF to let you know how handy JS can be. For now on Iāll try to be more briefly.
.apply()
This āfeatureā is brought to you by ECMAScript 5th Edition.
Starting with ES5
we can call Function.prototype.apply()
with any array-like object. What this means is that apply()
ās second argument (see definition) needs to have the property length
and the integer properties in the range 0ā¦lengthāāā1
.
For instance, the array [6,8]
has the property length of 2
and the integer properties from 0ā¦1
(meaning, [6,8][0]
and [6,8][1]
.) So itās an array-like object (this is a simple explanation, you can read the details here.)
Because all the 4 examples are array-like objects with the property length
, apply()
will execute the Array
function with each value from 0ā¦lengthāāā1
as its arguments.
For the example {length: 3}
it has a length
of 3
and apply()
will execute Array
as follows:
.sort()
This is not aĀ WTF.
This is how sort()
works. But we can have fun anyway š
According the specification, sort()
sorts the elements of an array according to their string unicode value.
Because the unicode value for first character of 10
(i.e. 1
) is lower than the unicode value for the character 2
, 10
appears before 2
when āsorting.ā
I feel funnyĀ now!
š„Ā .slice()
You may all recall our friend slice()
which, according to its specification, āit takes two arguments, start
and end
, and returns an array containing the elements of the array from element **start**
up to **end**
(end
not includedā.)
The syntax
array.slice(begin, end)
In both our examples, **begin**
= 0.
However, and although both null
and undefined
represent the absence of a value, the result for **end**
= null has nothing to do with the result for **end**
= undefined.
The reason is ECMAScript Specification.
Which says,
- if ā
**end**
is undefinedā, then ā**end**
is arrayās lengthā. - else ātoInteger(
**end**
) ā, which translated into ātoNumber(**end**
)ā.
By definition,
**toNumber**(null)
isĀ0
.
Our statement [1, 2, 3].slice(0, null)
is in fact [1, 2, 3].slice(0, 0)
.
You guessed it. ThatāsĀ
[]
.
š» Thank you note: A HUGE thanks to @joaoffalcao for this WTF.
< your WTFĀ >
If you find any WTF that should be here, please let me know š
Thatās all forĀ Arrays.
Thanks toĀ :
- MDN Documentation
- Kyle Simpson for his video and book
- Will Ferrel for the gifs
- Paddy Power Betfair guys, especially JoĆ£o and Pedro, for reviewing š¦
- The WTF contributor JoĆ£o FalcĆ£o š
- Hacker Noon for publishing ā¤ļø
Be sure to check out my other articles on JS WTF
JS WTF š¦ with Number_Time to ride on some JavaScript WTF with Number._hackernoon.com