125
\$\begingroup\$

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).

Note: Also see Tips for Golfing in ECMAScript 6 and above

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – pimvdb May 27 '11 at 5:28
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – mellamokb May 27 '11 at 13:44
  • \$\begingroup\$ This link has a bunch of tips relevant here. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 4:53

76 Answers 76

105
\$\begingroup\$

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 bracket notation for repeat property access

This is definitely a balancing act between property name length and number of accesses. Instead of calling a.longFunctionName() with dot notation twice, it's shorter to save the name and call the function via bracket notation:

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

-vs-

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

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

Note:

With bracket notation, the cost is 6 + name.length characters the first time. Each subsequent access has a cost of 3 characters.

For dot notation, all accesses cost name.length + 1 (+1 for the .) characters.

Use this method if 6 + name.length + (3 * (accesses - 1)) < accesses * (name.length + 1).

len = length of property name
i = minimum accesses to take advantage

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

The number of accesses can also span multiple objects. If you access .length 4 or more times on different arrays, you can use the same variable holding the string 'length'.

\$\endgroup\$
  • 5
    \$\begingroup\$ c = ~~a-~~b should be c = ~~a+~~b. Also, you can implicitly cast to integer using |0, for example Math.random()*6|0. \$\endgroup\$ – mellamokb Jun 1 '11 at 19:48
  • 7
    \$\begingroup\$ 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. \$\endgroup\$ – Peter Olson Dec 2 '11 at 21:38
  • 8
    \$\begingroup\$ I swear I'm going to use d- -b in my code someday... \$\endgroup\$ – John Dvorak Dec 19 '13 at 14:21
  • 4
    \$\begingroup\$ +a+b doesn't work (at least on mine...) // a="1",b="1",+a+b // gives "11" \$\endgroup\$ – imma Jan 16 '14 at 11:46
  • 2
    \$\begingroup\$ For "Use Array-Access for repeat function calls" if you're using the function more than twice on the same object, what's a bit shorter is to assign the function to a new member like a.f=a.longfunctionname;a.f(b);a.f(c);a.f(d) \$\endgroup\$ – Martin Ender Sep 11 '14 at 14:40
129
\$\begingroup\$

Splitting with numbers to save the quotemarks:

"alpha,bravo,charlie".split(",") // before
"alpha0bravo0charlie".split(0)   // after
\$\endgroup\$
  • 2
    \$\begingroup\$ It works, and I've used it for multiple digits. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 3:55
  • 12
    \$\begingroup\$ Lol this is actually pretty creative \$\endgroup\$ – NiCk Newman Nov 3 '15 at 19:37
  • 8
    \$\begingroup\$ in ES6 this doesn't matter anymore, you can just do .split`...` \$\endgroup\$ – David Archibald Apr 15 '17 at 22:41
55
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ Is the semicolon necessary at the end of the first sample? \$\endgroup\$ – wjl Aug 20 '12 at 6:12
  • 3
    \$\begingroup\$ @wjlafrance: It would only not be required if it's at the end of the one-liner. \$\endgroup\$ – mellamokb Aug 20 '12 at 14:57
46
\$\begingroup\$

Shorter random number generation

If you need a random boolean (0 or 1):

new Date&1 // equivalent to Math.random()<0.5

If you need a random integer 0 <= n < 1337:

new Date%1337 // equivalent to Math.floor(Math.random()*1337))

This works because a Date is stored internally in JavaScript as the amount of milliseconds since an epoch, so the new Date is being coerced into 123somebignumber456 when you try to do integer math on it.

Of course, these "random" numbers really won't be as random, especially if you call them multiple times in quick succession, so keep that in mind.

\$\endgroup\$
38
\$\begingroup\$

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)
\$\endgroup\$
  • \$\begingroup\$ the getter/setter part was really helpful. thx \$\endgroup\$ – gion_13 Mar 14 '12 at 10:01
  • 1
    \$\begingroup\$ Actually, even better is an object method, if you only use it <= 2 times. On the other hand, arrow functions are far better at cutting down characters, as they serve almost the same purpose, and classes are rarely useful in golfed code. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 3:57
  • \$\begingroup\$ if support is important arrow functions aren't supported in fx. ie11 \$\endgroup\$ – Jim Wolff Sep 18 '17 at 13:38
34
\$\begingroup\$

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];
\$\endgroup\$
  • 7
    \$\begingroup\$ Or, you could do it like either of these: let a=[5,6,7,8,9,10,11,12].map(x=>x*Math.random()|0) or let a=Array(7).map((_,i)=>i*Math.random()|0+5), 36 or 42 bytes saved, respectively. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 4:05
  • \$\begingroup\$ Is it possible to replace r(), or make it shorter? \$\endgroup\$ – NiCk Newman Nov 3 '15 at 19:46
  • 3
    \$\begingroup\$ r={valueOf:Math.random} That's just genius :D \$\endgroup\$ – ETHproductions Nov 22 '16 at 17:03
  • 1
    \$\begingroup\$ @Isiah, well yeah, you can do that now :-D \$\endgroup\$ – Andy E Nov 22 '16 at 22:57
31
\$\begingroup\$

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) === +num2;   // + is 8 characters shorter than parseInt()

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

var num4 = "12.6"
parseInt(num4) === num4|0;  // |0 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.

\$\endgroup\$
  • 6
    \$\begingroup\$ +1 for Creating repetitive strings using Array - hadn't thought about that one. \$\endgroup\$ – mellamokb Jun 9 '11 at 15:04
  • 4
    \$\begingroup\$ To create repetitive strings, in ES6 you can use str.repeat(count) \$\endgroup\$ – Oriol May 12 '15 at 16:38
25
\$\begingroup\$

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.

\$\endgroup\$
  • 12
    \$\begingroup\$ This can also be applied to any function that doesn't accept arguments. \$\endgroup\$ – Casey Chu Jun 19 '11 at 21:59
  • 3
    \$\begingroup\$ 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. \$\endgroup\$ – DocMax Jun 30 '11 at 0:58
  • 3
    \$\begingroup\$ @DocMax: You could use comma operator for that - i=5,[1,2,3].join(). \$\endgroup\$ – Konrad Borowski Jan 4 '13 at 11:59
  • \$\begingroup\$ @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). \$\endgroup\$ – DocMax Jan 4 '13 at 17:01
  • \$\begingroup\$ @DocMax Only if you are taking advantage of ASI. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 4:10
24
\$\begingroup\$

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)

Example with different values for i/j:

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

// after:
for(i=28;i--;)dosomething(0|i/7,i%7)
\$\endgroup\$
  • \$\begingroup\$ (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). \$\endgroup\$ – Camilo Martin Dec 18 '12 at 13:26
  • 1
    \$\begingroup\$ @CamiloMartin No, the loops don't need to be of equal length. The resulting number of iterations is i*j and the division/modulus operators retrieve the individual values of i and j. \$\endgroup\$ – quietmint Dec 19 '13 at 0:38
  • \$\begingroup\$ @user113215 You're right, awesome! :) I've edited the answer to include an example. \$\endgroup\$ – Camilo Martin Dec 19 '13 at 14:14
22
\$\begingroup\$

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.

\$\endgroup\$
  • 6
    \$\begingroup\$ Or, even better, just use for loops. There's really no case where using a for loop results in larger code, as far as I have experienced. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 4:08
22
\$\begingroup\$

Exception abusing

in case string/character literals are prohibited, you can use a try catch block:

try{something0}catch(e){str=e.message.split(0)[0]}

now str equals "something"

if more strings are needed you can chain it with a number (e.g. zeros)

try{something0foo0bar0}catch(e){arr=e.message.split(0)}

now arr equals ["something", "foo", "bar", " is not defined"]

\$\endgroup\$
22
\$\begingroup\$

Unicode shortcuts

If you use a hell of a built-in property at a big golfing challenge you can alias every property to a one character equivalent:

[Math,Number,S=String,Array].map(b=>
    Object.getOwnPropertyNames(b).map((p,i)=>
        b.prototype[S.fromCharCode(i+248)]=b[p]
    )
)

After executing the code above you can use it like this:
"foo".Č(/.*/,'bar') // replaces foo with bar

This costs 118 bytes, so it might not be useful in certain situations

It may be browser dependent and i'm not sure if it's shorter than with(Array){join(foo),...} or defining variables as used properties with(Array){j=join,m=map...} but still it is worth mentioning.

    Math        Number              String              Array

ø   toSource    prototype           prototype           prototype
ù   abs         NaN                 quote               join
ú   acos        POSITIVE_INFINITY   substring           reverse
û   asin        NEGATIVE_INFINITY   toLowerCase         sort
ü   atan        MAX_VALUE           toUpperCase         push
ý   atan2       MIN_VALUE           charAt              pop
þ   ceil        MAX_SAFE_INTEGER    charCodeAt          shift
ÿ   clz32       MIN_SAFE_INTEGER    contains            unshift
Ā   cos         EPSILON             indexOf             splice
ā   exp         isFinite            lastIndexOf         concat
Ă   floor       isInteger           startsWith          slice
ă   imul        isNaN               endsWith            filter
Ą   fround      toInteger           trim                isArray
ą   log         parseFloat          trimLeft            lastIndexOf
Ć   max         parseInt            trimRight           indexOf
ć   min         length              toLocaleLowerCase   forEach
Ĉ   pow         name                toLocaleUpperCase   map
ĉ   random      arguments           normalize           every
Ċ   round       caller              match               some
ċ   sin                             search              reduce
Č   sqrt                            replace             reduceRight
č   tan                             split   
Ď   log10                           substr  
ď   log2                            concat  
Đ   log1p                           slice   
đ   expm1                           fromCharCode    
Ē   cosh                            fromCodePoint   
ē   sinh                            localeCompare   
Ĕ   tanh                            length  
ĕ   acosh                           name    
Ė   asinh                           arguments   
ė   atanh                           caller  
Ę   hypot           
ę   trunc           
Ě   sign            
ě   cbrt            
Ĝ   E           
ĝ   LOG2E           
Ğ   LOG10E          
ğ   LN2         
Ġ   LN10            
ġ   PI          
Ģ   SQRT2           
ģ   SQRT1_2         
\$\endgroup\$
  • \$\begingroup\$ I'm using google chrome, and these are all giving undefined. \$\endgroup\$ – SuperJedi224 May 14 '15 at 19:19
  • \$\begingroup\$ It must be very firefox specific then. Sorry for the inconvenience. \$\endgroup\$ – bebe May 15 '15 at 16:44
  • \$\begingroup\$ Why are these all special characters? Why not just use printable ASCII? (easier to type, more reliable, and only 1 byte for golfing) \$\endgroup\$ – Cyoce Feb 10 '16 at 20:02
  • \$\begingroup\$ This doesn't really work for Math because it doesn't have a .prototype attribute. Removing Math, though, I managed to golf this down to a 114-byte snippet that assigns them all to single-byte letters. You can find it here. \$\endgroup\$ – ETHproductions Dec 3 '16 at 20:50
  • \$\begingroup\$ You can also golf my solution to 106 bytes at the expense of moving all these properties to the range À-ÿ, which is still 1 byte each in the ISO-8859-1 encoding (which JS supports). In Firefox 50, this unfortunately puts the .localeCompare method on ×, but that shouldn't usually be an issue. source \$\endgroup\$ – ETHproductions Dec 3 '16 at 21:59
18
\$\begingroup\$

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.

\$\endgroup\$
18
\$\begingroup\$

If you can accept Spidermonkey (for now) specific scripts, you can use ECMAScript 6 arrow functions. Insteading of writing code like the following.

a.map(function(x){return x*2}) // function? return?

You can shorten it like this.

a.map(x=>x*2)
\$\endgroup\$
17
\$\begingroup\$

If you need to check for NaN, don't use isNaN(x), but use x!=x, which is shorter and also works.

if(isNaN(x)){
if(x!=x){

Note that this only works if typeof(x) === "number"; if it's a string for example, isNaN("string") returns true, but "string" != "string" returns false. Thanks to Cyoce for pointing this out!

\$\endgroup\$
  • 2
    \$\begingroup\$ That's a genius use of this quirk. +1 \$\endgroup\$ – ETHproductions Dec 22 '15 at 21:05
  • \$\begingroup\$ Warning: these are not always equivalent: isNaN("string") returns true, whereas "string"!="string" returns false (obviously) \$\endgroup\$ – Cyoce Feb 10 '16 at 22:18
  • \$\begingroup\$ @Cyoce Good point, thanks! I edited my answer. \$\endgroup\$ – ProgramFOX Feb 11 '16 at 7:36
  • \$\begingroup\$ In many cases, you can even go for if(!x){, if you are detecting NaN explicitly. \$\endgroup\$ – Hohmannfan Aug 9 '16 at 21:24
  • 1
    \$\begingroup\$ Casting x to number, +x!=+x, makes it equivalent to isNaN(x), yet still 2 characters shorter. Then, +"string"!=+"string" returns true. \$\endgroup\$ – Tomas Langkaas Sep 8 '17 at 19:50
14
\$\begingroup\$

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.

\$\endgroup\$
  • 2
    \$\begingroup\$ This can also be used to coalesce a string input into an integer, i.e., n=prompt()|0. \$\endgroup\$ – mellamokb May 27 '11 at 13:31
  • 1
    \$\begingroup\$ bitwise is also super fast compared to math.floor : jsperf.com/floor-vs-bitwise \$\endgroup\$ – vsync Jun 7 '11 at 22:33
  • \$\begingroup\$ @vsync: Weird. I get math.floor to be about twice as fast as bitwise on Chrome 11.0.696.77. \$\endgroup\$ – mellamokb Jun 8 '11 at 11:47
  • \$\begingroup\$ 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. \$\endgroup\$ – vsync Jun 8 '11 at 16:15
  • \$\begingroup\$ To keep the comments up-to-date, in current Fx they're both fast & about equal. Not that it's likely to be a bottleneck in the first place, compared to surrounding code... \$\endgroup\$ – FireFly Feb 1 '14 at 20:13
14
\$\begingroup\$

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;)

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

\$\endgroup\$
13
\$\begingroup\$

Array sum / product / quotient

ES5: 17 bytes

eval(a.join('+'))

ES6: 15 bytes

eval(a.join`+`)

Of course you can swap the + for anything you want, e.g., * for product or / for quotient.

\$\endgroup\$
11
\$\begingroup\$

Use ^ instead of != or == when comparing to an integer

//x!=3?a:b
  x^3?a:b

//x==3?a:b
  x^3?b:a

Replace calls to built-in Math functions with shorter expressions

//Math.ceil(n)
  n%1?-~n:n

//Math.floor(n)
  ~~n
  0|n

//Math.abs(n)
  n<0?-n:n

//Math.round(n)
  n+.5|0

//Math.min(x,y)
  x<y?x:y

//Math.max(x,y)
  y<x?x:y
\$\endgroup\$
  • 1
    \$\begingroup\$ Alternatively, you can simply use - instead of != for integers; For example, n!=1?a:b would be equivalent to n-1?a:b \$\endgroup\$ – vrugtehagel May 3 at 10:32
10
\$\begingroup\$

Something worth noting is that you can use a string in place of zero in some instances to save a couple of bytes here and there in loops:

s='';for(i=0;i++<9;)s+=i
for(i=s='';i++<9;)s+=i
// s="123456789", i=10
\$\endgroup\$
  • 1
    \$\begingroup\$ I tried ""++ in the console earlier wondering if it would work, of course it has to be in a variable first. Thanks! \$\endgroup\$ – Vartan Jul 30 '15 at 21:00
10
\$\begingroup\$

Very simple one, even so, no one had mentioned it.

If you're using Math.min() or Math.max() you can save 6 chars by doing this:

Math.min(a,b)  // 13 chars
a<b?a:b        //  7 chars

Math.max(a,b)
a>b?a:b
\$\endgroup\$
9
\$\begingroup\$

In cases where you are using the ternary operator to chose between two numbers, and the conditional is either a boolean or number 1 or 0, you can do math operations instead:

(x ? num1 : num2) conclusions:

    1)if num1 equals num2, there ARE savings
    2)if num1 is (+1) or (-1) than num2, there ARE savings
    3)if either num1 or num2 equals to 0, there ARE savings
    4)it is MORE LIKELY to find greater savings on num1>num2 instead of num1<num2
    5)in method (*A) and (*B), savings are NOT GUARANTEED

    a)num1>num2
        i)(num1==(num2+1))
            ex1: (x?5:4) to (x+4)
            ex2: (x?8:7) to (x+7)
        ii)num2==0
            ex1: (x?3:0) to (x*3)
            ex2: (x?7:0) to (x*7)
        iii)
            (*A) or (*B) //one might be shorter

    b)num1<num2
        i)((num1+1)==num2)
            ex1: (x?4:5) to (5-x)
            ex2: (x?7:8) to (8-x)
        ii)num1==0
            ex1: (x?0:3) to (!x*3)
            ex2: (x?0:7) to (!x*7)
        iii)
            (*A) or (*B) //one might be shorter

    c)num1==num2
        i)
            ex1: (x?5:5) to (5)
            ex2: (x?-3:-3) to (-3)

    (*A) use ((x*(num1-num2))+num2)
        ex1: (x?8:4)   to ((x*4)+4)
        ex2: (x?4:8)   to ((x*-4)+8)

        ex3: (x?6:-4)  to ((x*10)-4)
        ex4: (x?-4:6)  to ((x*-10)+6)

        ex5: (x?4:-6)  to ((x*10)-6)
        ex6: (x?-6:4)  to ((x*-10)+4)

        ex7: (x?-5:-9) to ((x*4)-9)
        ex8: (x?-9:-5) to ((x*-4)-5)

    (*B) use ((!x*(num2-num1))+num1)
        ex1: (x?8:4)   to ((!x*-4)+8)
        ex2: (x?4:8)   to ((!x*4)+4)

        ex3: (x?6:-4)  to ((!x*-10)+6)
        ex4: (x?-4:6)  to ((!x*10)-4))

        ex5: (x?4:-6)  to ((!x*-10)+4)
        ex6: (x?-6:4)  to ((!x*10)-6)

        ex7: (x?-5:-9) to ((!x*-4)-5)
        ex8: (x?-9:-5) to ((!x*4)-9)

Note: In addition to this, you will need to remove the unnecessary 0-, +0, +- etc.

Note2: there is an isolated case where (x) !== (x?1:0), as x must be typeof === "number" for it to work. However, in the case of (-x) it works just fine.

Note3: In case you don't find savings, simply use the former (x?y:z)

Previously I thought method B couldn't ever beat A, however exceptions do exist:

(x?97:100) //original

(-3*x+100)
(3*!x+97)

I created a github project that makes the simplification for us (jsFiddle demo)

\$\endgroup\$
  • \$\begingroup\$ @ajax333221 void 0 (it isn't a function, but a keyword) is not a value, it simply returns undefined. \$\endgroup\$ – Camilo Martin Dec 18 '12 at 12:07
  • \$\begingroup\$ @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 \$\endgroup\$ – ajax333221 Dec 18 '12 at 16:30
  • \$\begingroup\$ @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... \$\endgroup\$ – Camilo Martin Dec 19 '12 at 2:07
9
\$\begingroup\$

tl;dr: Use ES6 features!

Arrow functions

Doc: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/arrow_functions
Example:

s = x => x*x
// s = function (x) {
//   return x * x;
// }
\$\endgroup\$
  • \$\begingroup\$ Arrow functions were already mentioned on Oct 13 '13 at 15:42. But that for..of is cool. Even shorter than for each..in. \$\endgroup\$ – manatwork Jan 7 '14 at 15:11
  • 2
    \$\begingroup\$ The array comprehension syntax seems to be wrong. According to the documentation should be like in Python: b = [s(x) for (x of a)]. \$\endgroup\$ – manatwork Jan 7 '14 at 15:15
  • \$\begingroup\$ @manatwork The above samples run fine in Traceur's REPL \$\endgroup\$ – Florent Jan 7 '14 at 15:31
  • \$\begingroup\$ No idea about Traceur, but you mentioned ECMAScript and pointed to Mozilla documentation. And array comprehensions in none of them looks like you wrote it. \$\endgroup\$ – manatwork Jan 7 '14 at 15:39
  • 1
    \$\begingroup\$ Array comprehensions were actually pulled midway through. \$\endgroup\$ – Isiah Meadows Dec 3 '14 at 22:20
9
\$\begingroup\$

Rounding

I know that alternatives to Math.floor() have been posted, but what about the others?

Flooring:

Math.floor(x) //before
0|x           //after

Rounding:

Math.round(x) //before
0|x+.5        //after

Ceiling:

Math.ceil(x) //before
x%1?-~x:x    //after - credits to @Tomas Langkaas
\$\endgroup\$
  • 1
    \$\begingroup\$ Note that 0|x+1 simply adds 1 if the number you want to find the ceiling of is already an integer. A (mostly) safe alternative is 0|x+1-1e9, but this is only three bytes shorter. \$\endgroup\$ – ETHproductions Nov 7 '15 at 18:11
  • \$\begingroup\$ @ETHproductions don't you mean 0|x+1-1e-9? \$\endgroup\$ – Mama Fun Roll Nov 24 '15 at 1:40
  • \$\begingroup\$ Oops, yeah. Thanks for pointing that out. (For some reason, I can't do @(your username)...) \$\endgroup\$ – ETHproductions Nov 24 '15 at 1:42
  • \$\begingroup\$ Probably because my username chars are upside down :) \$\endgroup\$ – Mama Fun Roll Nov 24 '15 at 1:45
  • 1
    \$\begingroup\$ For ceiling, x%1?-~x:x (9 characters) is a better alternative. However, like the flooring alternatives 0|x and ~~x, it only works for positive numbers. \$\endgroup\$ – Tomas Langkaas Sep 8 '17 at 18:40
9
\$\begingroup\$

Abuse literals

The recent sample: Check whether "c" is uppercase or lowercase, doesn't matter if not letter

"c"<{} // returns false, lower case
"C"<{} // returns true, upper case
\$\endgroup\$
  • 3
    \$\begingroup\$ How does this work? \$\endgroup\$ – Cows quack Jun 26 '18 at 10:15
  • 2
    \$\begingroup\$ @Cowsquack String({}) gives "[object Object]". \$\endgroup\$ – Dennis Jun 26 '18 at 14:49
8
\$\begingroup\$

Use if(~a.indexOf(b)) instead of if(a.indexOf(b)!=-1)

\$\endgroup\$
8
\$\begingroup\$

Transforming to a Boolean:

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

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

\$\endgroup\$
8
\$\begingroup\$

Prefer .map over .reduce

Consider the following code for summing an array:

a.reduce(function(x,y){return x+y})

Pretty long, right? What if I told you that you could get rid of the return? Well, you can:

a.map(function(x){t+=x},t=0)    // 7 bytes saved

(Although an even shorter way is eval(a.join("+")).)

How about reducing by multiplication, where you have to specify the starting number anyway?

a.reduce(function(x,y){return x*y},1)  // Looooong
a.map(function(x){t*=x},t=1)    // An easy 9 bytes shorter

(Again, eval(a.join("*")) works as well.)

Here, let's try one that doesn't work with eval(a.join()):

a.reduce(function(x,y){return x+f(y)})
a.map(function(x){t+=f(x)},t=0)

Note that this doesn't work quite as well with ES6, although it's still a little shorter:

a.reduce((x,y)=>x+f(y))
a.map(x=>t+=f(x),t=0)

Note: in all of the .map versions, you will need to call t afterwards to get the actual value.

\$\endgroup\$
  • \$\begingroup\$ Can you apply the same logic for ES6? \$\endgroup\$ – Sunny Patel Aug 23 '16 at 19:57
  • \$\begingroup\$ @SunnyPatel Yep, although it doesn't work out quite as well. \$\endgroup\$ – ETHproductions Nov 22 '16 at 15:53
7
\$\begingroup\$

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"; <- 13 Chars
x-3?"n":"y"; <- 12 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.

\$\endgroup\$
7
\$\begingroup\$

Use Mozilla's nonstandard "expression closures" 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.

\$\endgroup\$
  • 2
    \$\begingroup\$ That's not Javascript. That's a SPACE STATION!!! \$\endgroup\$ – Thomas Eding Aug 20 '11 at 0:40
  • 1
    \$\begingroup\$ ECMAScript 6 to the rescue! ->bar \$\endgroup\$ – Ry- Jun 10 '12 at 18:53
  • 4
    \$\begingroup\$ ECMAScript 6: let foo = () => bar;, ironically shorter than the golfed code above. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 4:41
  • 1
    \$\begingroup\$ ECMAScript 6: foo=_=>bar, even shorter. \$\endgroup\$ – ETHproductions Dec 22 '15 at 1:02
  • \$\begingroup\$ that link is broken. \$\endgroup\$ – Cyoce Feb 11 '16 at 7:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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