Weird alternative syntax array.length

this surprised me:

var parts = email.split('@');
if (parts < 2) {

      

link: https://github.com/Kicksend/mailcheck/blob/master/src/jquery.mailcheck.js#L21-22

essentially it looks like this:

var a = [null, null, null]
a < 2 // false

var b = [null]
b < 2 // true

      

it looks like it works, but I want to know why, what kind of coercion is actually going on for this? since the intent here was to vouch if less than 2 parts are coming from the email string, I would expect it to always get through due to the array being defined as true - it should create an array with at least one member even on an empty string.

I always prefer to use array.length

. is it safe?

+3


source to share


5 answers


It is a string and then a number conversion which happens as arrays cannot be straight compared to operator <

. It will first do a string comparison, but with a number, which will then do a numerical comparison.

Note that:

  • [null, null, null] == ",,"

  • [null] == ""

and



  • +",,"

    NaN

  • +"" === 0

Now this makes sense because 0 < 2 === true

, but NaN < 2 === false

.

Therefore, this is not a meaningful expression. [null, null] < 3

is equal false

because it "," < 3

essentially does NaN < 3

.

+4


source


Using operators <

or >

to compare an array with a number is not safe, reliable, or correct. You shouldn't be doing this.

Here are the conversion rules, taken from this O'Reilly book :

The operands of these comparison operators can be of any type. However, comparison can only be performed on numbers and strings, so operands that are not numbers or strings are converted. Comparison and conversion takes place as follows:

If both operands are numbers or both are converted to numbers, they are compared numerically.

If both operands are strings or are converted to strings, they are compared as strings.

If one operand is either converted to a string and one is either converted to number, the operator attempts to convert the string to a number and perform a numeric comparison. If the string is not a number, it converts to NaN and the comparison is false. (In JavaScript 1.1, converting a string to a number throws an error instead of giving NaN.)

If the object can be converted to a number or a string, JavaScript performs the numeric conversion. This means, for example, that Date objects are compared numerically, and it makes sense to compare two dates to see if the previous one is.

If the operands of comparison operators cannot both be successfully converted to numbers or strings, these operators always return false.

If either operand is or is converted to NaN, the comparison operator always evaluates to false.



In this particular case, since there is no array-to-number conversion, it ends up comparing the two strings, which are completely unreliable.

This is another reason why you only need to compare two items of the same type. In this particular case, it also has much more readable code to use the property .length

directly and use:

a.length > 2

      

+2


source


It seems to me that this is not safe because:

[0, 0] > 1 // false

      

and

[0, 0] < Infinity // false

      


Ok, this is not an item count comparison at all. It compares the string representation of the array, so NaN < Infinity

it gives false

. So the answer is no, it is not a safe alternative at all, because they do not remotely do the same. It only works for you because:

[null] < 2 -> null < 2 -> 0 < 2 -> true

      

but

[null, null, null] < 2 -> ',,' < 2 -> NaN < 2 -> false

      

+2


source


Arrays cannot be converted to numbers. What's going on here, arrays are converted to strings.

When arrays are converted to strings, internal JavaScript does array.join(',')

.

So it ['a','b']

becomes "a,b"

.

[null]

- ""

, a [null,null]

- ","

. This is because it null

converts to an empty string.

So [null,null] < 2

there is "," < 2

, which is false.

To get the length of an array use .length

.

+1


source


Oh, it's safe, it just doesn't compare what you think of comparing it.

The expression parts < 2

compares the array to a number. To complete this comparison, JavaScript must convert the two values ​​to a common type, and the only one available is a string. The toString () method of the array object concatenates each of the string values ​​of the array elements with a comma, and the null string value is an empty string. So your test expressions do ",," < "2"

and "" < "2"

, which I'm sure are not meant to do.

As long as you don't use delete

in an array (use instead slice

), using length should be completely safe.

+1


source







All Articles