Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

What general tips do you have for golfing in JavaScript? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to JavaScript (e.g. "remove comments" is not an answer). Please post one tip per answer.

share|improve this question
I was actually wondering, is it allowed to put variables in global (saves var)? And should JavaScript golf code be a function or output something directly? I honestly think this can make much difference. – pimvdb May 27 '11 at 5:28
1  
@primvdb: It is allowed, but you have to be careful because it can cause side-effects if a function is called multiple times and it is manipulating global variables, or if it is a recursive function. – mellamokb May 27 '11 at 13:44

26 Answers

up vote 17 down vote accepted

Fancy For Loops

you can use the standard for loop in non-standard ways

for ( a; b; c )

is essentially equivalent to:

a;
while ( b )
{
  ...
  c;
}

so a good trick is to write your code with a while loop, and then split it into the a,b,c parts in a for loop.

A couple examples I've written:

for(x=y=n;!z;x--,y++)z=i(x)?x:i(y)?y:0
for(a=b=1;b<n;c=a+b,a=b,b=c);

Chain your setters

If you're initializing or resetting multiple values, chain the value to all the variables that need it:

a=b=1;

Implicit Casting

Don't check your types, just use them as they are. parseInt() costs 10 characters. If you need to cast out of a string, be creative:

a='30';
b='10';
c = a + b; //failure
c = parseInt(a) + parseInt(b) //too long

c = -(-a-b); //try these
c = ~~a+~~b;
c = +a+ +b;
c = a- -b;

Avoid Semicolons

JavaScript has automatic semi-colon insertion. Use it often and well.

One-liners

Save on brackets by shoving as much as possible into single lines, or parameters:

a( realParam1, realParam2, fizz='buzz' )

Increment/Decrement operators

a = a - 1;
foo(a);

and

foo(a);
a = a - 1;

can easily be rewritten as

foo(--a);

and

foo(a--);

respectively.

Use this or self instead of window in global context

self explanatory 2 character savings.

Use Array-Access for repeat function calls

This is definitely a balancing act between variable/function name length and number of invocations. Instead of calling a.longFunctionName() twice, it's shorter to save the name and call the function via array-access:

a.longFunctionName(b)
a.longFunctionName(c)
//42

-vs-

f='longFunctionName'
a[f](b)
a[f](c)
//34

this is especially effective with functions like document.getElementById which can be reduced to d[e]().

Note:

For a single call, the relative cost* is 8 + name.length characters. Each subsequent call has a relative cost of 2 characters.

For standard invocation, all calls cost name.length characters.

Use this method if 8 + name.length + (2 * invocations) < invocations * name.length

i = invocations len = minimum function length to get advantage

i | len
=======
1 |  ∞
2 | 12
3 |  7
4 |  6
5 |  5
6 |  4

* relative cost doesn't include the calling object, perens, or parameters. Essentially: a.XXX() vs a[XXX]()

share|improve this answer
3  
c = ~~a-~~b should be c = ~~a+~~b. Also, you can implicitly cast to integer using |0, for example Math.random()*6|0. – mellamokb Jun 1 '11 at 19:48
6  
It's cheaper to coerce a string to a number with the unary plus operator. If a and b are strings, you can do +a+b to convert to number and add them. – Peter Olson Dec 2 '11 at 21:38
Where can I add github.com/jed/140bytes/wiki/Byte-saving-techniques ? – Inkbug Aug 1 '12 at 10:23

You can use the object literal form of get/set to avoid using the keyword function.

var obj = {
  get f(){
    console.log("just accessing this variable runs this code");
    return "this is actually a function";
  },
  set f(v){
    console.log("you can do whatever you want in here, passed: " + v);
  }
};

1 && obj.f; // runs obj.[[get f]]
obj.f = Infinity; // runs obj.[[set f]](Infinity)
share|improve this answer
the getter/setter part was really helpful. thx – gion_13 Mar 14 '12 at 10:01

Taking advantage of short-circuit operators

Rather than long if statements or using ternary operators, you can make use of && and || to shorten your code. For instance:

var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);

return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;

can become

var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);

return match && decodeURIComponent(match[1].replace(/\+/g, ' '));

The || operator is often used in this way for setting defaults:

evt = evt || window.event;

This is the same as writing

if (!evt)
    evt = window.event;

Creating repetitive strings using Array

If you want to initialize a long string of a particular character, you can do so by creating an array with a length of n+1, where n is the number of times you wish to repeat the character:

// Create a string with 30 spaces
str = "                              ";

// or
str = Array(31).join(" ");

The larger the string, the bigger the saving.

Parsing numbers

Use + and ~ operators instead of parseFloat() or parseInt() when coalescing a string type that is just a number to a number type:

var num = "12.6";
parseFloat(num) === +num;  // + is 10 characters shorter than parseFloat()

var num2 = "12"
parseInt(num2) === +num;   // + is 8 characters shorter than parseInt()

var num3 = "12.6"
parseInt(num2) === ~~num;  // ~~ is 7 characters shorter than parseInt()

Be wary though, other types can be coalesced with these operators (for instance, true would become 1) an empty string or a string containing just white space would become 0. This could be useful in certain circumstances, however.

share|improve this answer
3  
+1 for Creating repetitive strings using Array - hadn't thought about that one. – mellamokb Jun 9 '11 at 15:04

Use the comma operator to avoid braces (also applies to C):

if(i<10)m+=5,n-=3;

Instead of

if(i<10){m+=5;n-=3}

which is one character longer.

share|improve this answer
Is the semicolon necessary at the end of the first sample? – wjl Aug 20 '12 at 6:12
@wjlafrance: It would only not be required if it's at the end of the one-liner. – mellamokb Aug 20 '12 at 14:57

Use a bitwise operation to round a number toward zero:

// do this
T=Math.random()*6+1|0

// or do this
T=~~(Math.random()*6+1)

(Source: Random dice tipping)

Operator precedence determines which will be shorter in your program.

share|improve this answer
2  
This can also be used to coalesce a string input into an integer, i.e., n=prompt()|0. – mellamokb May 27 '11 at 13:31
1  
bitwise is also super fast compared to math.floor : jsperf.com/floor-vs-bitwise – vsync Jun 7 '11 at 22:33
@vsync: Weird. I get math.floor to be about twice as fast as bitwise on Chrome 11.0.696.77. – mellamokb Jun 8 '11 at 11:47
very weird. for me they are both more or less same speeds & super fast in Chrome, but in FF the bitwise is a lot faster than Chrome, and Math.floor is terribly slow..almost should not be used I would say. – vsync Jun 8 '11 at 16:15

Use Mozilla's proprietary "expression closure" feature to save many characters in a script that only needs to work in the SpiderMonkey/Firefox or Rhino engines. For example,

function foo(){return bar}

becomes

function foo()bar

See the Stack Overflow page for more such tricks.

share|improve this answer
That's not Javascript. That's a SPACE STATION!!! – Thomas Eding Aug 20 '11 at 0:40
ECMAScript 6 to the rescue! ->bar – rynah Jun 10 '12 at 18:53

Converting a while loop into a for loop is often equivalent:

while(i--);
for(;i--;);

But the second form can have variable initialization combined:

i=10;while(i--);
for(i=10;i--;);

Notice the second form is one character shorter than the first form.

share|improve this answer

This one is lesser known and lesser used, but can be impressive if used in the right situation. Consider a function that takes no arguments and always returns a different number when called, and the returned number will be used in a calculation:

var a = [ 
    Math.random()*12|0,
    Math.random()*11|0,
    Math.random()*10|0,
    /* etc... */ 
];

You might normally shorten this function using a single-letter variable name:

var r=Math.random,a=[r()*12|0,r()*11|0,r()*10|0,r()*9|0,r()*8|0,r()*7|0,r()*6|0,r()*5|0];

A better way to reduce the length is by abusing valueOf, which gives you a saving of 2 characters per invocation. Useful if you call the function more than 5 times:

var r={valueOf:Math.random},a=[r*12|0,r*11|0,r*10|0,r*9|0r*8|0,r*7|0,r*6|0,r*5|0];
share|improve this answer

Sneak variable initialization into the prompt() call for getting user input

n=prompt(i=5);     // sets i=5 at the same time as getting user input

instead of using

n=prompt();i=5;

As a side-effect, it displays the input value in the prompt window while saving 1 character.

share|improve this answer
1  
This can also be applied to any function that doesn't accept arguments. – Casey Chu Jun 19 '11 at 21:59
1  
Even when the function accepts arguments it can be useful, as in [1,2,3].join('',i=5) in cases where it saves a pair of braces. – DocMax Jun 30 '11 at 0:58
@DocMax: You could use comma operator for that - i=5,[1,2,3].join(). – GlitchMr Jan 4 at 11:59
@GlitchMr: I could, but it doesn't save any characters. I agree that most of the time that will be cleaner. I think there may still be cases where my ordering might save a char, although I cannot come up with one at the moment (and I may well be wrong). – DocMax Jan 4 at 17:01

Initialize arrays with [] instead of Array(), and add to arrays with [.length]:

a=[];       // initialize a new array
a[0]=15;    // insert element to end of array
a[1]=30;    // insert another element to end of array
share|improve this answer
1  
note: I know this is obvious, but if we are going to insert elements too close to index 0, it might be good idea to write it like this a=[15,30]; – ajax333221 Dec 18 '12 at 16:36

for a given array, we know a for..in loop might lead to errors because stuff might be added to the Array.Prototype, so we revert to a normal for loop:

So instead of this iteration:

for (var i=0; i<arr.length; i++ )

lets do this:

for (var i=arr.length; i--; )

if we just want to iterate the Array not caring it goes backwards

share|improve this answer
Nicely found, but var can be dropped here as well I guess. Secondly, I honestly don't think you'd add functions to Array.prototype when golfing. – pimvdb Jun 7 '11 at 20:12
var makes the counter a local and not global variable, and globals are considered bad – vsync Jun 7 '11 at 21:17
Oh well I don't know, but that was the reason of the downvote of my post here :) – pimvdb Jun 8 '11 at 6:01
3  
Indeed globals are considered bad in general JavaScript programming. But in code-golfing, it saves 4 characters which is never bad :-) In code golfing, you're generally breaking a lot of readability and usability rules anyway to squeeze out the last character. – mellamokb Jun 8 '11 at 11:53
haha, then just compress your code then! your program might very well break if you use globals, so always ask yourself if you omit some var, would that effect something else far down the code – vsync Jun 8 '11 at 16:16
show 1 more comment

Another thing I came across is forcing a multidimensional array into a single-dimensional array like this:

[[1,2],[3,4]].join().split(",") // ["1", "2", "3", "4"]

It does convert everything into strings, so basically only numbers/strings are possible, but it can come in handy. Calculating with strings automatically converts it into numbers anyway.

EDIT: As Austin Hyde pointed out, you can flatten one level like this:

[].concat.apply([],[[1,2],[3,4]])

Although it only takes it down one level, the data types remain.

share|improve this answer
I use [[1,2],[3,4]].reduce(function(a,b){ return a.concat(b) }) – vsync Jun 7 '11 at 19:03
@vsync: Isn't that longer? – mellamokb Jun 7 '11 at 19:40
1  
yeah but if you need to use indexOf on the array later to find numbers in it...it won't find them if the array so made of strings, so this is more pure flattening – vsync Jun 7 '11 at 20:05
2  
[].concat.apply([],[[1,2],[3,4]]) also works, but only flattens it one level. It's two characters longer, but works on any data type. – Austin Hyde Jun 13 '11 at 18:11
@Austin Hyde: Nice one, thanks. – pimvdb Jun 14 '11 at 7:15
show 1 more comment

In some cases, a conditional check for empty can be replaced with multiplication. For instance:

a?42:0

Returns 42 if a is 1 and 0 if a is 0. This does the same thing:

a*42

and saves two characters.

share|improve this answer
@ajax333221 void 0 (it isn't a function, but a keyword) is not a value, it simply returns undefined. – Camilo Martin Dec 18 '12 at 12:07
@CamiloMartin you are right, also I now see the point in this answer, however a must be either 1 or 0 for it to work – ajax333221 Dec 18 '12 at 16:30
@ajax333221 Yes, actually the funny thing about code golfing to me is that most of the best tricks only work for that particular thing you're doing, and one feels so clever to find one of these corner cases with corner solutions :D By the way, you don't have to delete comments... – Camilo Martin Dec 19 '12 at 2:07

If you're initializing a variable to 1 in every iteration of a loop (for example, resetting a variable in an outer loop for an inner loop), like the following (from my answer to this question):

for(j=n-2;p=1,j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
          ^^^^

Since the result of a condition like j++<=n is 1 whenever its true, you can just assign the condition directly to the variable (because when it becomes false, the loop will stop executing and will no longer matter):

for(j=n-2;p=j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
          ^^^^^^^^

You can usually save 2 characters using this method. Regards to @ugoren for the idea in the comments to that answer.


For another example, I also applied this trick to my answer here with the expression w=r=++c<S.length in my outer for loop, saving a total of 4 characters.

share|improve this answer

Transforming to a Boolan:

if(b){b=true}else{b=false}
b=b?true:false;
b=b?!0:!1;
b=!!b;

Note: They change 0, "",false, null, undefined and NaN to false (everything else to true)

share|improve this answer

combine nested for loops

// before:
for(i=5;i--;)for(j=5;j--;)dosomething(i,j)

// after:
for(i=25;i--;)dosomething(0|i/5,i%5)
share|improve this answer
(I've edited a) minor typo, but very clever! Note that this will only work on nested loops of same length (unless I'm wrong). – Camilo Martin Dec 18 '12 at 13:26

Sometimes declaring a variable (or more) as function parameters can save some strokes by avoiding the var keyword. This use case is fairly rare though:

function f(){var i} => function f(i){}

Also you can use short circuit operators to avoid if statements:

if(a)b => a&&b

if(!a)b => a||b

To coerce to a number: str-0

share|improve this answer

You can check if a value is *truish by simply passing it:

if(val){...}

*everything different than 0, "", false, null, undefined and NaN is evaluated to true !

This method can be applied with many other functions and operators:

  • ternary operator val?"true":"false";
  • for loop for(;val;){...}
  • while loop while(val){...}
  • etc...

Note: it is exactly to (val == true) and (val != false)

share|improve this answer

Repeated characters

Be creative when trying to repeat the same character:

"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
s="a";while(s.length<32)s+=s;
for(s="a";s.length<32;s+=s);
for(s="aa",i=4;i--;s+=s);
new Array(33).join("a");
s="aaaaaaaa",s+=s,s+=s;
s="aaaaaaaa",s+=s+s+s;

Note: It is unlikely that you use it to form a string, but the idea can be applied to form large numbers too

share|improve this answer
also, note that new Array(n).join(c); method is the best when the repeated text is bigger (replace all the a with <br> and you will see) – ajax333221 Mar 26 '12 at 22:37
2  
new could be dropped; the Array constructor called as a function does the same as if it's called as a constructor. If the character to repeat is unimportant, it could be left out and it'll default to ",". – FireFly Aug 30 '12 at 21:59

Treat strings like you do C Strings.

Given s="hello"

s[0]

is equivalent to

s.charAt(0)

and

s.split("")[0]
share|improve this answer
This is EcmaScript 5, but for code golf it's fine. – GlitchMr Jan 4 at 12:03

Less/Greater than "10/100/1000..." vs "9/99/999...":

//for(i=0;i<20;i++){
    if(i<10){}else{}
    if(i>9){}else{}
//}

Note: Just remember to swap what is inside the if with the else

share|improve this answer

Adding Values with Implicit Casting

Improved zzzzBov solution:

//not so good
-(-a-b)==c;

//best
a- -b==c;

We save 2 characters by using the second solution.

Note: you MUST leave the space between the - operators

share|improve this answer
+"10"+ +"5"===15 – gion_13 Mar 14 '12 at 9:59
Note that the space is needed because the -- (decrement) operator takes precedence over subtraction. Also, @gion_13, what's the point? your solution has one extra character. – Camilo Martin Dec 18 '12 at 13:18

Looping Tip I

You can save 1 character when looping by changing the i on the last time used:

//not so god
for(i=0;i<3;i++){
  alert(i);
}

//best
for(i=0;i<3;){
  alert(++i);
}

Note: works with -- too (but modify the loop accordingly to avoid infinite looping)


Looping Tip II

There are certain scenarios where you can save one character by playing with the incrementing operator and values:

for(i=0;i++<9;)
for(i=0;++i<10;)

//and

for(i=11;i-->0;)
for(i=11;--i>-1;)

Note: you need to pay attention when for example 0 to -1. and 9 to 10, 99 to 100, so play around until you find a way to save the character

share|improve this answer

Splitting with numbers to save the quotemarks:

"alpha,bravo,charlie".split(",") // before
"alpha0bravo0charlie".split(0)   // after
share|improve this answer

How to compare a number with help of how numbers turn into booleans:

If you are going to check if something is equal to a positive number, you can subtract that amount and reverse what was inside the if and else blocks:

//simplified examples:
(x==3)?"y":"n"; <- 15 Chars
(x-3)?"n":"y"; <- 14 Chars

//expanded examples:
if(x==3){
    yes();
}else{
    no();
}

if(x-3){
    no();
}else{
    yes();
}

And in case you are wanting to compare with a negative number (*different than -1), you just simply need to add this number instead of subtracting.

*well, you can surely use x.indexOf(y) + 1, but in the special case of -1 you have the opportunity to use ~x.indexOf(y) instead.

share|improve this answer

Some extra tricks that I don't see very often, that are more JS-specific:

  • Use array literals and indexing as a sort of switch as an expression. You can leave out "unnecessary" elements and they'll default to undefined (which is a falsy value, by the way). E.g. [,1,,-1][i%4] would evaluate to either 1 or -1 depending on whether i is 1,5,9,13,... or 3,7,11,15,... (and we don't care about the other cases).

  • Similarly, use object literals when you want arbitrary strings for the keys.

  • This one is common to all C-style languages: (ab)use the fact that that & and | works just as well as && and || with boolean values, albeit with different precedence. Keep in mind that the single-character variants aren't short-circuiting though!

  • -~x is the same as x+1, and ~-x is the same as x-1. Sometimes the {bitwise,arithmetic} negation variants are useful to avoid extra parens; for instance, 4*~-n rather than 4*(n-1).

  • ~9 could be used as a two-character literal for the value -10 (I've never had a use for this, but it's a fun curiosity).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.