19

Looking in the jQuery core I found the following code convention:

nth: function(elem, i, match){
    return match[3] - 0 === i;
},

And I was really curious about the snippet match[3] - 0

Hunting around for '-0' on google isn't too productive, and a search for 'minus zero' brings back a reference to a Bob Dylan song.

So, can anyone tell me. Is this some sort of performance trick, or is there a reason for doing this rather than a parseInt or parseFloat?

alex
  • 479,566
  • 201
  • 878
  • 984
James Wiseman
  • 29,946
  • 17
  • 95
  • 158
  • 1
    I asked a very similar question here. Worth looking into some of the answers: http://stackoverflow.com/questions/2526682/why-is-javascripts-math-floor-the-slowest-way-to-calculate-floor-in-javascript – Mark Bolusmjak Apr 19 '10 at 09:50

7 Answers7

14

Probably just a short-hand way to force the left-hand side into integer. Not as clear as calling a function, of course.

This tutorial on type-conversion states:

Any mathematical operator except the concatenation/addition operator will force type-conversion. So conversion of a string to a number might entail performing a mathematical operation on the string representation of the number that would not affect the resulting number, such as subtracting zero or multiplying by one.

This also reveals that "subtracting" is a better search term than "minus". :)

unwind
  • 391,730
  • 64
  • 469
  • 606
10

Various ways to coerse JS strings to numbers, and their consequences:

Results of converting various strings using the above techniques
(source: phrogz.net)

I personally use *1 as it is short to type, but still stands out (unlike the unary +), and either gives me what the user typed or fails completely. I only use parseInt() when I know that there will be non-numeric content at the end to ignore, or when I need to parse a non-base-10 string.

Community
  • 1
  • 1
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • Thanks. Is there any metrics on the relative performances of these? – James Wiseman Jan 05 '11 at 17:05
  • I'll try to create some. In general the methods (`parse*`) will be _measurably_ slower than the implicit casts, but probably not _noticeably_ slower unless you're doing a LOT of string-to-number conversions. – Phrogz Jan 05 '11 at 17:06
  • @JamesWiseman I created a benchmark, but the results generally vary too wildly to report. You can try the benchmark here: http://phrogz.net/JS/string_to_number.html Reload it several times to see the variation. – Phrogz Jan 05 '11 at 17:50
  • Hmmmm, I see. I wonder if anything can be inferred by taking an average over a large number of executions. – James Wiseman Jan 05 '11 at 18:26
  • @JamesWiseman You're welcome to try. The problem is that with today's JIT interpreters execution time can vary based on how often you perform a certain task. – Phrogz Jan 05 '11 at 18:33
9

Based on a few quick and dirty benchmark runs, "1234" - 0 was about 50% faster than parseInt("1234") and 10% faster than +"1234" in Firefox 3.6.

Update:

My "quick and dirty" benchmark was not very useful because it was just converting the string "1234" in a loop. I tried again using a random list of numbers, and the results are all over the map. The three methods are all within 400-500 ms on this computer except when they jump to 1300 ms! I think garbage collection is interfering. Here is some code to play with in Firebug, in case I did something stupid:

function randomList() {
    var list = [];
    for (var i = 0; i < 1000000; i++) {
        list.push("" + Math.floor(Math.random()*4000000000));
    }
    return list;
}

function testParseInt(list) {
    console.log("Sanity check: parseInt('" + list[0] + "') = " + parseInt(list[0]) );
    var start = new Date();
    for (var string in list)
        var tmp = parseInt(string);
    var time = new Date() - start;
    console.log("parseInt(string): " + time);
}

function testMinusZero(list) {
    console.log("Sanity check: '" + list[0] + "' - 0 = " + (list[0] - 0));
    var start = new Date();
    for (var string in list)
        var tmp = string - 0;
    var time = new Date() - start;
    console.log("string - 0: " + time);
}

function testUnaryPlus(list) {
    console.log("Sanity check: +'" + list[0] + "' = " + (+list[0]));
    var start = new Date();
    for (var string in list)
        var tmp = +string;
    var time = new Date() - start;
    console.log("+string: " + time);
}

function testPlusZero(list) {
    console.log("Sanity check: '" + list[0] + "' + 0 = " + (list[0] + 0) + " Oh no!");
    var start = new Date();
    for (var string in list)
        var tmp = string + 0;
    var time = new Date() - start;
    console.log("string + 0: " + time);
}


var numbers = randomList();

testParseInt(numbers);
testMinusZero(numbers);
testUnaryPlus(numbers);
testPlusZero(numbers);
  • Thanks for taking the trouble to do this. I wonder if there is any comparitive difference between +0 and -0, as highlighted in @S.Mark's post. – James Wiseman Apr 19 '10 at 09:11
  • btw, the unary + I've mentioned in my answer supposed to be `+"1234"` not `"1234" + 0` – YOU Apr 19 '10 at 10:12
  • My favourite jsperf, testing the speed of parsing/casting to a number in various ways: http://jsperf.com/performance-of-parseint/14 (note they have different results in regards to NaN: `~~"x" = 0`, whereas `"x"-0 = NaN`) – Tom McKenzie Mar 10 '13 at 02:18
4

Just a info, According to this site

using unary + operator is faster one than any of the following (which include '- 0'):

var numValue = stringValue - 0;
/* or */
var numValue = stringValue * 1;
/* or */
var numValue = stringValue / 1;

unary + operator also type-converts its operand to a number and because it does not do any additional mathematical operations it is the fastest method for type-converting a string into a number.

This contradicts James' benchmark, although he may be might be correct. I think jQuery wouldn't utilise this syntax if it were slow.

James Wiseman
  • 29,946
  • 17
  • 95
  • 158
YOU
  • 120,166
  • 34
  • 186
  • 219
  • +1. "slow" is a relative term. James's benchmark, whilst a good "quick and dirty" example, is based on Firefox only. Different JavaScript implementations differ in their performance optimizations and the same may not be true of other browsers (only one way to find out really). – Andy E Apr 19 '10 at 10:01
3

Your main reason to use this syntax is if you have generic code that may be any number (int or float) and you want to do a type-sensitive compare (===)

Fenton
  • 241,084
  • 71
  • 387
  • 401
0

If it's not an old relic that got lost, then it just tries to change the type to Number.

elias
  • 1,481
  • 7
  • 13
0

It really looks like a "performant" parseInt to me.

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • Per my answer, it's not `parseInt`, but rather `parseFloat` without the ignore-trailing-garbage _"feature"_. – Phrogz Jan 05 '11 at 17:40