173
\$\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\$
4
  • \$\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
    Commented May 27, 2011 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
    Commented May 27, 2011 at 13:44
  • \$\begingroup\$ This link has a bunch of tips relevant here. \$\endgroup\$
    – Claudia
    Commented Feb 12, 2015 at 4:53
  • 1
    \$\begingroup\$ I have discovered probably the most useless tip: a private class element doesn’t require a space before the private identifier in cases where it is preceded by a keyword: (class{static #x = 1;get #y(){};set #y(z){}}) can be rewritten as (class{static#x = 1;get#y(){};set#y(z){}}). This makes for some nice obfuscation, too, but I can’t think of a practical example in code golf. \$\endgroup\$ Commented Nov 1, 2021 at 15:26

98 Answers 98

4
\$\begingroup\$

If you need to do something different depending on several different values for a string, instead of:

if(v=='hello'){
  j=1
}else if(v=='goodbye'){
  j=2
//...

consider:

j={hello:1,goodbye:2,...}[v]
\$\endgroup\$
3
\$\begingroup\$

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

\$\endgroup\$
3
\$\begingroup\$

For strings and arrays, instead of using a=b.length>a.length?b:a to set a to b if b.length > a.length, you can use a=b[a.length]?b:a.

Note: If b is an array and contains either 0 or false, you'll have to use a=b[a.length]!=null?b:a (still one character shorter).

\$\endgroup\$
1
  • \$\begingroup\$ a.length in b shorter \$\endgroup\$
    – l4m2
    Commented Mar 8 at 10:23
3
\$\begingroup\$

Return 1 for true, 0 for false as much as possible

This should be relatively self-explanatory.

function f(x){return x?(d(x),!1):!0}
function f(x){return x?(d(x),0):1}
function f(x){return !x&&d(x)&0}
if(f(v)){/* ... */}

// ES6 versions
let f=x=>x?(d(x),!1):!0
let f=x=>x?(d(x),0):1
let f=x=>!x&&d(x)&0
if(f(v)){/* ... */}
\$\endgroup\$
1
  • \$\begingroup\$ Don't get what's going on here but from your description +!!x is shorter and more concise. \$\endgroup\$ Commented Nov 5, 2015 at 17:27
3
\$\begingroup\$

If returning void, see if it is shorter to return something useful. This is kinda language-agnostic here.

This isn't an easy apply-anywhere thing, either, though. Word of warning, make sure your parentheses are balanced.

In ES6, in this example, 6 bytes saved

let l=x=>console.log(m+x),x=1,a;l(a=f(x));l(a=g(a));l(h(a))
let l=x=>(console.log(m+x),x),x=1;l(h(l(g(l(f(x))))))

In ES5, it is only 1 byte saved

function l(x){console.log(m+x)}var x=1,a;l(a=f(x));l(a=g(a));l(h(a))
function l(x){console.log(m+x);return x}var x=1;l(h(l(g(l(f(x))))))
\$\endgroup\$
1
  • 1
    \$\begingroup\$ If you need to call a void-returning function repeatedly, it can be especially useful to return the function itself. For example, l=(x,y)=>c.lineTo(x,y);l(1,2);l(3,4);l(5,6);l(7,8) can be rephrased as l=(x,y)=>c.lineTo(x,y)||l;l(1,2)(3,4)(5,6)(7,8), saving 3 bytes. Example usage \$\endgroup\$ Commented Nov 22, 2016 at 16:56
3
\$\begingroup\$

Use Bitwise as Logic Operators When Dealing With Booleans

a = 1 //although this would usually be a boolean expression
b = 0 //same
if(a&&b)c()
if(a&b)c()

Then, use && lazy evaluation to make a chain of ampersands:

a&b&&c()
if(a&&b)c()

Saves 3 characters

\$\endgroup\$
2
  • \$\begingroup\$ You could use 0 and 1 instead of booleans. Again, semicolons are optional. \$\endgroup\$
    – mbomb007
    Commented May 21, 2015 at 19:37
  • \$\begingroup\$ I know, these were just examples. Instead of true and false, there would most likely be expressions. I used variables to illustrate my point. \$\endgroup\$
    – Cyoce
    Commented May 21, 2015 at 21:33
3
\$\begingroup\$

When stringifying dates, .toJSON saves 5 bytes over .toISOString. Apparently this was supported as far back as Firefox 4, but this answer is only the sixth on PPCG to mention it.

\$\endgroup\$
3
\$\begingroup\$

Shortening Promise Chains with async/await

Sometimes you can shorten longer promise chains with async/await. The main benefit is from getting rid of the beginning of the arrow function in each then callback. .then(x=>x (10) gets replaced with await( (-4), but you first pay with async (+6). So to make up for the initial overhead of 6 bytes, you'd need at least two then chains to get any benefit.

+-------------+----------------+
| then chains | async overhead |
+-------------+----------------+
| 0           | +6             |
| 1           | +2             |
| 2           | -2             |
| 3           | -4             |
| …           | …              |
+-------------+----------------+

Example 1

x=>x().then(y=>y.foo()).then(z=>z.bar())
async x=>await(await(x()).foo()).bar()

Example 2

u=>fetch(u).then(r=>r.text()).then(t=>/\0/.test(t))
async u=>/\0/.test(await(await fetch(u)).text()))
\$\endgroup\$
3
\$\begingroup\$
  1. Checking if a string includes a character, e.g. 0:
if(s.indexOf(0)!=-1)
if(~s.indexOf(0))    // -3
if(s.includes(0))    // -3
if(s.match(/0/))     // -4
if(/0/.exec(s))      // -5

exec is shorter than match.

  1. Ceiling a division:
Math.ceil(a/b)
(a+b-1)/b|0    // -3

Even shorter (if you don't mind editing a):

--a/b+1|0     // -5
-~(--a/b)     // -5 too
  1. String to array
// s is a string
Array.from(s)
[...s]        // -7
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can also use /0/.test(s) \$\endgroup\$
    – hypers
    Commented Jun 17, 2021 at 9:05
  • \$\begingroup\$ Note that, if you need an actual boolean, and the pattern comes from an existing string with no regex special characters, x, then !!s.match(x) works (the argument is implicitly converted to a RegExp, and it returns falsy null on failure), achieving the same effect as s.includes(x) while shaving off a character. \$\endgroup\$ Commented Feb 23, 2023 at 18:35
3
\$\begingroup\$

Length of deprecating array +1

1+X.length
X.push(0)   // 1 byte shorter
\$\endgroup\$
0
2
\$\begingroup\$

Convert ints to strings by adding an empty string

For example:

39323+""

Returns:

"39323"

Update:

Adding [] works too

\$\endgroup\$
2
\$\begingroup\$

Array#concat() and the spread operator

This largely depends on the situation.


Combining multiple arrays.

Prefer the concat function unless cloning.

0 bytes saved

a.concat(b)
[...a,...b]

3 bytes wasted

a.concat(b,c)
[...a,...b,...c]

3 bytes saved

a.concat()
[...a]

6 bytes saved

// Concatenate array of arrays
[].concat.apply([],l)
[].concat(...l)

Prefer using an already existing array to Array#concat().

Easy 4 bytes saved

[].concat(a,b)
a.concat(b)
\$\endgroup\$
4
  • \$\begingroup\$ Can't see the point of all this. Concat works with multiple array parameters, does not need apply or spread. Example 1: a.concat(b,c,d,e,f) \$\endgroup\$
    – edc65
    Commented Feb 11, 2015 at 0:09
  • \$\begingroup\$ Flatten: let f=l=>[].concat.apply(l.map(x=>Array.isArray(x)?f(x):x)) vs let f=l=>[...l.map(x=>Array.isArray(x)?f(x):x)] \$\endgroup\$
    – Claudia
    Commented Feb 11, 2015 at 1:56
  • \$\begingroup\$ Well...except my flatten shouldn't work. Here's a corrected version: let f=x=>[].concat(...l.map(x=>Array.isArray(x)?f(x):x)). The previous version would've done nothing. \$\endgroup\$
    – Claudia
    Commented Feb 12, 2015 at 3:53
  • \$\begingroup\$ It's still 6 bytes saved. \$\endgroup\$
    – Claudia
    Commented Feb 12, 2015 at 3:53
2
\$\begingroup\$

Adding Values with Implicit Casting

Improved zzzzBov solution:

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

//best
a- -b==c;
a-+-b==c;

We save 2 characters by using these solutions.

\$\endgroup\$
4
  • \$\begingroup\$ +"10"+ +"5"===15 \$\endgroup\$
    – gion_13
    Commented Mar 14, 2012 at 9:59
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ Commented Dec 18, 2012 at 13:18
  • 1
    \$\begingroup\$ You can replace the space with a + (e.g. a-+-b) \$\endgroup\$
    – Toothbrush
    Commented Nov 5, 2015 at 16:37
  • 2
    \$\begingroup\$ In this case use a==c-b \$\endgroup\$
    – l4m2
    Commented Apr 13, 2018 at 16:24
2
\$\begingroup\$

Function

If you need a function in as few bytes as possible, and any function will do (perhaps you just want to access some of the goodies from Function.prototype), then here are some options (starting with large ones):

Function.prototype
[].map
Date
CSS     (available in modern browsers)
Map     (ES6: available in Node and modern browsers)
Set     (ES6: available in Node and modern browsers)
URL     (available in very old browsers, but not in Node)

So if you want a reference to the call function, you can get it like this:

c=URL.call
\$\endgroup\$
2
\$\begingroup\$

If iterating through own properties, prefer Object.keys.

15 bytes saved

for(let p in o)if(o.hasOwnProperty(e)){/* ... */}
for(let p of Object.keys(o)){/* ... */}
Object.keys(o).map(p=>{/* ... */})

This is also the case for ES5, where it is 7 bytes saved.

for(var p in o)if(o.hasOwnProperty(e)){/* ... */}
Object.keys(o).map(function(p){/* ... */})

If you do that more than once, alias it as a function.

In this ES6 example, 6 bytes saved. It still saves bytes in ES5, but only if used 3 times or more.

Object.keys(o).map(p=>{/* ... */})Object.keys(o).map(p=>{/* ... */})
i=f=>Object.keys(o).map(f);i(p=>{/* ... */});i(p=>{/* ... */})
\$\endgroup\$
0
2
\$\begingroup\$

If you are using the same function more than once, it's often useful to reference the function to a new function name. I.e:

Instead of:

Math.sqrt(4)
Math.sqrt(16)
Math.sqrt(100)

you can do:

r=Math.sqrt
r(4)
r(16)
r(100)
\$\endgroup\$
4
  • 6
    \$\begingroup\$ Correct, but that is not JavaScript specific, is a generic tip added to Tips for golfing in <all languages> by Blazer more that 6 years ago. \$\endgroup\$
    – manatwork
    Commented Jun 26, 2018 at 8:32
  • \$\begingroup\$ Welcome to PPCG! As manatwork pointed out this tip has already be posted, so I recommend deleting it. But I hope you nevertheless stick around and answer some challenges. :) \$\endgroup\$
    – Laikoni
    Commented Jun 26, 2018 at 12:55
  • 2
    \$\begingroup\$ 4**.5;16**.5;100**.5 is even shorter. \$\endgroup\$
    – Dennis
    Commented Jun 26, 2018 at 14:53
  • \$\begingroup\$ Thanks for your replies. I will take a look at the general tips. Maybe I find something which has not yet been added ;) love code golfing though! \$\endgroup\$
    – Xzibitee
    Commented Jun 29, 2018 at 11:57
2
\$\begingroup\$

Square root hack

Use (x+2)**(1/2) instead of Math.sqrt(x+2).

\$\endgroup\$
3
  • 1
    \$\begingroup\$ a√b = a^(1/b) This can be applied to non-JavaScript languages. \$\endgroup\$
    – user85052
    Commented Feb 1, 2020 at 3:20
  • 9
    \$\begingroup\$ Wouldn't it be shorter to use .5 instead of 1/2? \$\endgroup\$
    – Stephen
    Commented Feb 1, 2020 at 5:17
  • 1
    \$\begingroup\$ .5 would be shorter, but this way, it applies to 3rd, 4rth, etc. \$\endgroup\$ Commented Apr 23, 2020 at 20:03
2
\$\begingroup\$

Abusing template literals

You can often save two bytes on parentheses by replacing

a.join('+')

with

a.join`+`

This works for most properties that take in a single string.

This has been used in other answers, but there isn't an answer dedicated to this specifically.

\$\endgroup\$
2
\$\begingroup\$

You can produce undefined with 0[0] to save 5 bytes. This is 2 bytes shorter than the more traditional void 0 method of creating undefined.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ Note that you can also use [].x, or, if you have a variable defined anywhere in the program/function (which is very likely), something like x.x, a.x, _.x, and so on, which is a byte shorter. \$\endgroup\$
    – rydwolf
    Commented Nov 15, 2021 at 21:29
2
\$\begingroup\$

When using regexps, if you need . to exclude \n, so you can't use the /s flag, you can uniquely (other regex engines do not allow this) write [^] instead of [\s\S] saving 3 bytes.

\$\endgroup\$
2
\$\begingroup\$

Instead of a>b&&(A[x]=y), write A[a>b&&x]=y, so long as A[false] isn't used

\$\endgroup\$
2
\$\begingroup\$

Test Equality to Zero

Instead of

num==0

You can use

!num
\$\endgroup\$
1
  • 2
    \$\begingroup\$ This is very helpful in ternary expressions, you can replace num==0?result_a:result_b to num?result_b:result_a \$\endgroup\$ Commented Jun 2, 2023 at 22:09
2
\$\begingroup\$

Avoid typeof

typeof x === 'number' is pretty verbose if you need to distinguish your input values by type. (Granted, this is rare in most coding challenges). typeof x=='number' is barely better, you still have an operator and a constant that are pretty heavy on byte count.

Instead, coerce the input to the desired type and use === to check whether the result is the same type (and value) as the input:

Number(x)===x

or better yet

+x===x
typeof expression equivalent === check golfed
typeof x === 'boolean' Boolean(x) === x !!x===x
typeof x === 'string' String(x) === x ""+x===x
typeof x === 'number' Number(x) === x +x===x
typeof x === 'bigint' BigInt(x) === x BigInt(x)===x
typeof x === 'object' && x !== null Object(x) === x1 Object(x)===x1
typeof x === 'undefined' void x === x x===[][0]2,3
x === undefined || x === null x == null2 x==null

There exist no coercion functions for functions or symbols. You'll have to keep using typeof for them.

1: Object(x) === x also detects function objects
2: that's a different trick, but I wanted to include it for completeness
3: thanks to comment by @noodle man

\$\endgroup\$
2
  • \$\begingroup\$ for undefined do [][] instead of void x \$\endgroup\$ Commented Sep 17, 2023 at 0:55
  • \$\begingroup\$ undefined could also be something like 1..a \$\endgroup\$ Commented Mar 8 at 10:23
1
\$\begingroup\$

ES6-specific: avoid Function#bind()

Self-explanatory, 7 bytes saved

f.bind(null,x,...xs)
_=>f(x,...xs)

Use sloppy mode to avoid variable declarations

Here, 8 bytes saved

a.forEach(e=>{let b=e+1,c=d(b)+2;f(e);g(b);h(c);i(b,c)})
a.forEach(e=>{f(e);g(b=e+1);h(c=d(b)+2);i(b,c)})

// Even better, reuse variables and use `Array#map()`
// Drops an additional 6 bytes
a.map(e=>{f(e++);g(e);h(b=d(e)+2);i(e,b)})

This also holds in ES5. Here, 8 bytes saved

a.forEach(function(e){let b=e+1,c=d(b)+2;f(e);g(b);h(c);i(b,c)})
a.forEach(function(e){f(e);g(b=e+1);h(c=d(b)+2);i(b,c)})

// Even better, reuse variables and use `Array#map()`
a.map(function(e){f(e++);g(e);h(b=d(e)+2);i(e,b)})
\$\endgroup\$
2
  • 1
    \$\begingroup\$ 1. You don't ever need to initialize variables in code-golf unless you want them to be undefined, so getting rid of let saves 4 bytes off of the first line of both examples. 2. If you want to use .bind with customizable parameters, .bind is better: q=f.bind(0,x) vs. q=(..._)=>f(x,..._) (though if you only want one parameter, q=y=>f(x,y) is better). \$\endgroup\$ Commented Dec 3, 2016 at 20:12
  • \$\begingroup\$ @ETHproductions Updated \$\endgroup\$
    – Claudia
    Commented Dec 3, 2016 at 20:39
1
\$\begingroup\$

This is one of my favorites - ES6

'da,dad,sa'.split``
 ["d", "a", ",", "d", "a", "d", ",", "s", "a"]

'da,dad,sa'.split`,`
["da", "dad", "sa"]
\$\endgroup\$
3
  • 6
    \$\begingroup\$ The first one [...'asdasd'] \$\endgroup\$
    – l4m2
    Commented Apr 25, 2018 at 6:34
  • \$\begingroup\$ Did you copy and paste ? it, if done in the console and in code pen I get ["d", "a", ",", "d", "a", "d", ",", "s", "a"] 'da,dad,sa'.split`` (9) ["d", "a", ",", "d", "a", "d", ",", "s", "a"] \$\endgroup\$ Commented Apr 26, 2018 at 13:26
  • \$\begingroup\$ [...'da,dad,sa'] ... \$\endgroup\$
    – Cétia
    Commented Jun 27, 2018 at 15:58
1
\$\begingroup\$

Use the simplest shortening method available - your variable declaration!

var myName = "Jack";

Obviously is very long compared to:

m="Jack"

It's a whole 12 characters shorter. You have all 64 of these single-character variable names available:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_

And also - never use spaces or semicolons in your variable naming - changing m = "Mum"; to m="Mum" saves another three characters.

\$\endgroup\$
0
1
\$\begingroup\$

Remove duplicates from array

a.filter(e=>!(t[e]=e in t)) 

let unique= (a,t={})=> a.filter(e=>!(t[e]=e in t));

// "stand-alone" version working with global t:
// a1.filter((t={},e=>!(t[e]=e in t)));

// Test data
let a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];
let a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12]];
let a3 = ['Mike', 'Adam','Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];

// Results
console.log(JSON.stringify( unique(a1) ))
console.log(JSON.stringify( unique(a2) ))
console.log(JSON.stringify( unique(a3) ))

O(n) performance; we assume your array is in a and t={}. Explanation here

And shorter but slower version (which not work with 2D arrays)

[...new Set(a)]

let unique = a => [...new Set(a)];

// Test data
let a1 = [5, 6, 0, 4, 9, 2, 3, 5, 0, 3, 4, 1, 5, 4, 9];
let a3 = ['Mike', 'Adam', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];

// Results
console.log(JSON.stringify(unique(a1)))
console.log(JSON.stringify(unique(a3)))

\$\endgroup\$
2
  • \$\begingroup\$ @manatwork So it is, I missed that when reviewing :/ \$\endgroup\$ Commented Aug 22, 2019 at 9:50
  • \$\begingroup\$ You don't need a t, you can set properties of the array. only works with non-integers thoguh \$\endgroup\$
    – emanresu A
    Commented May 9, 2022 at 10:45
1
\$\begingroup\$

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

if(val){...}

*everything different than 0, 0n, "", 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...
\$\endgroup\$
4
  • \$\begingroup\$ Or val&&.... Now, it is not equivalent to val == true. Example: 0 != true. \$\endgroup\$
    – Claudia
    Commented Feb 12, 2015 at 4:56
  • \$\begingroup\$ All these strings also evaluate to true: '0', ' ', ' 0', '0 ' \$\endgroup\$
    – Toothbrush
    Commented Nov 5, 2015 at 16:41
  • 1
    \$\begingroup\$ The technical term for "truish" is "truthy". \$\endgroup\$ Commented Jun 24, 2020 at 3:43
  • \$\begingroup\$ Other falsy things: window.all and new Date("1970-01-01T00:00:00.000Z") \$\endgroup\$ Commented Jul 20, 2022 at 14:29
1
\$\begingroup\$

output

sometimes you can use throw instead of alert to save 1 byte

throw !0
alert(!0)  

Do note that the program terminates, so you can't use it for loops.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ You don't need the space in this instance: throw!0 \$\endgroup\$
    – pxeger
    Commented Dec 19, 2021 at 21:19
1
\$\begingroup\$

Compressing Long Strings

If you have a very long, repetitive string, you can compress it using something similar to:

``.replace(/./gs,p=>p.charCodeAt().toString(2).padStart(7,0)).match(/.{n}/g).map(p=>+("0b"+p))

The `` should contain any code points between 0 and 127, with some needing to be escaped. These are: 0x00 (\0 or \x00, depending on whether a digit is following), 0x0d (\r), 0x5c (\\), and 0x60 (\`). In some very rare cases you may need to escape a $ if it is followed by a {.

You should replace n with the number of bits the output should be grouped into, and you can put any code you want in the final map and use +("0x"+p) to get the decimal value wherever necessary.

This adds roughly 100 bytes of overhead, compared to atob/btoa's 8. This method fits just under 7 bits per character in the string (due to escaping), and takes advantage of the fact that JS lets you put pretty much any code points into a string.

In order for this to be shorter, the data compressed needs to be one of:

  • Binary or numeric data, which is difficult to work with using atob and btoa
  • A string that has few distinct characters and is longer than 100 or so characters

In order to create a compressed string, convert each chunk of the string to binary using whatever encoding you want, then break it into chunks 7 bits wide. You may need to add some padding, which will be ignored if it is under 7 bits. Then, convert these into code points and paste them into the string.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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