# Tips for golfing in JavaScript

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

• 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. May 27 '11 at 5:28
• @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. May 27 '11 at 13:44
• This link has a bunch of tips relevant here. Feb 12 '15 at 4:53

# 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)){/* ... */}

• Don't get what's going on here but from your description +!!x is shorter and more concise. Nov 5 '15 at 17:27

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

• 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 Nov 22 '16 at 16:56

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

• You could use 0 and 1 instead of booleans. Again, semicolons are optional. May 21 '15 at 19:37
• I know, these were just examples. Instead of true and false, there would most likely be expressions. I used variables to illustrate my point. May 21 '15 at 21:33

If you are ever in a situation where you have an array a and you need to get its last element as an array of itself, use Array#slice():

[a[a.length-1]]    // 15
a.slice(-1)        // 11

• And, if you don't mind changing the original array, [a.pop()], at 9 characters. Sep 8 '17 at 16:53

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:

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


you can do:

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

• 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. Jun 26 '18 at 8:32
• 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. :) Jun 26 '18 at 12:55
• 4**.5;16**.5;100**.5 is even shorter. Jun 26 '18 at 14:53
• 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! Jun 29 '18 at 11:57

# Removing something from a string

When you want to remove a certain substring from a string, split by that and join.

.replace(/h/g,'') // 17 bytes
.splith.join // 16 bytes
.replaceAll('h','') // 19 bytes


Sadly the ES2021 replaceAll is longer.

Convert ints to strings by adding an empty string

For example:

39323+""


Returns:

"39323"


Update:

Adding [] works too

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

• 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) Feb 11 '15 at 0:09
• 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)] Feb 11 '15 at 1:56
• 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. Feb 12 '15 at 3:53
• It's still 6 bytes saved. Feb 12 '15 at 3:53

Improved zzzzBov solution:

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

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


We save 2 characters by using these solutions.

• +"10"+ +"5"===15 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. Dec 18 '12 at 13:18
• You can replace the space with a + (e.g. a-+-b) Nov 5 '15 at 16:37
• In this case use a==c-b
– l4m2
Apr 13 '18 at 16:24

# 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


# 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=>{/* ... */})


# 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)})

• 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). Dec 3 '16 at 20:12
• @ETHproductions Updated Dec 3 '16 at 20:39

This is one of my favorites - ES6

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

'da,dad,sa'.split,

• The first one [...'asdasd']
– l4m2
Apr 25 '18 at 6:34
• 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"] Apr 26 '18 at 13:26
• [...'da,dad,sa'] ... Jun 27 '18 at 15:58

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.

# 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()))


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. ## Square root hack Use (x+2)**(1/2) instead of Math.sqrt(x+2). • a√b = a^(1/b) This can be applied to non-JavaScript languages. – user85052 Feb 1 '20 at 3:20 • Wouldn't it be shorter to use .5 instead of 1/2? Feb 1 '20 at 5:17 • .5 would be shorter, but this way, it applies to 3rd, 4rth, etc. Apr 23 '20 at 20:03 # 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. # 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))) • @manatwork So it is, I missed that when reviewing :/ Aug 22 '19 at 9:50 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]  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... • Or val&&.... Now, it is not equivalent to val == true. Example: 0 != true. Feb 12 '15 at 4:56 • All these strings also evaluate to true: '0', ' ', ' 0', '0 ' Nov 5 '15 at 16:41 • The technical term for "truish" is "truthy". Jun 24 '20 at 3:43 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  • You can also use /0/.test(s) Jun 17 at 9:05 # 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.

The concat is more useful than push in many situations because it returns whole array e.g. we want from d=[{a:1,b:2,c:3},{a:7,b:8,c:9}] generate 'pivot object' p={"a":[1,7],"b":[2,8],"c":[3,9]}

let p={}, d=[{a:1,b:2,c:3},{a:7,b:8,c:9}];

d.map(x=> Object.keys(x).map(k=> p[k]= (p[k]||[]).concat(x[k]) ))

console.log(JSON.stringify(p));

• Instead of mapping the keys, you can do for(k in x) and, instead of the concatenation, you can do p[k]=[...p[k]||[],x[k]]. After wrapping that in {}s, it saves you 14 bytes. TIO Sep 17 '19 at 9:37
• @Shaggy thanks :) - I don't know that tricks. May be you have also some suggestion to this? Sep 17 '19 at 10:10

### output

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

throw !0


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

I have adapted to my needs the Unicode shortcuts method by @bebe.

The problem which many have faced with the original solution is due to the fact that some of the functions/properties belong to a class prototype while others to a class itself. These need to be handled separately.

The minified code now takes 132 bytes:

[Number,S=String,Array].map(r=>{f=(r=>Object.getOwnPropertyNames(r).map((e,t)=>r[S.fromCharCode(t+248)]=r[e])),f(r),f(r.prototype)})


Of course, you can drop Number and Array if unused from the initial array to save a couple of bytes. String is used in the code itself so removing it doesn't help a lot.

Part of the problems came from Math having no protype thus requiring its special handling. Besides the name in the initial array it also takes another 5 bytes to skip prototype handing. So use the variant below only if you need Math:

[Number,S=String,Array,Math].map(r=>{f=(r=>Object.getOwnPropertyNames(r).map((e,t)=>r[S.fromCharCode(t+248)]=r[e])),f(r),r.E||f(r.prototype)})


I use the same code for Node.js (v12.19.0) and Chrome (90.0.4430.212 x64).

Code Char Number          Number.prototype String        String.prototype  Array    Array.prototype Math
248  ø    length            constructor    length        length            length    length         abs
249  ù    name              toExponential  name          constructor       name      constructor    acos
250  ú    prototype         toFixed        prototype     anchor            prototype concat         acosh
251  û    isFinite          toPrecision    fromCharCode  big               isArray   copyWithin     asin
252  ü    isInteger         toString       fromCodePoint blink             from      fill           asinh
253  ý    isNaN             valueOf        raw           bold              of        find           atan
254  þ    isSafeInteger     toLocaleString               charAt                      findIndex      atanh
255  ÿ    parseFloat                                     charCodeAt                  lastIndexOf    atan2
256  Ā    parseInt                                       codePointAt                 pop            ceil
257  ā    MAX_VALUE                                      concat                      push           cbrt
258  Ă    MIN_VALUE                                      endsWith                    reverse        expm1
259  ă    NaN                                            fontcolor                   shift          clz32
260  Ą    NEGATIVE_INFINITY                              fontsize                    unshift        cos
261  ą    POSITIVE_INFINITY                              fixed                       slice          cosh
262  Ć    MAX_SAFE_INTEGER                               includes                    sort           exp
263  ć    MIN_SAFE_INTEGER                               indexOf                     splice         floor
264  Ĉ    EPSILON                                        italics                     includes       fround
265  ĉ                                                   lastIndexOf                 indexOf        hypot
267  ċ                                                   localeCompare               keys           log
268  Č                                                   match                       entries        log1p
269  č                                                   matchAll                    values         log2
270  Ď                                                   normalize                   forEach        log10
273  đ                                                   repeat                      flatMap        pow
274  Ē                                                   replace                     map            random
275  ē                                                   search                      every          round
276  Ĕ                                                   slice                       some           sign
277  ĕ                                                   small                       reduce         sin
278  Ė                                                   split                       reduceRight    sinh
279  ė                                                   strike                      toLocaleString sqrt
280  Ę                                                   sub                         toString       tan
281  ę                                                   substr                                     tanh
282  Ě                                                   substring                                  trunc
283  ě                                                   sup                                        E
284  Ĝ                                                   startsWith                                 LN10
285  ĝ                                                   toString                                   LN2
286  Ğ                                                   trim                                       LOG10E
287  ğ                                                   trimStart                                  LOG2E
288  Ġ                                                   trimLeft                                   PI
289  ġ                                                   trimEnd                                    SQRT1_2
290  Ģ                                                   trimRight                                  SQRT2
291  ģ                                                   toLocaleLowerCase
292  Ĥ                                                   toLocaleUpperCase
293  ĥ                                                   toLowerCase
294  Ħ                                                   toUpperCase
295  ħ                                                   valueOf
296  Ĩ                                                   replaceAll (*)


Notes:

replaceAll (marked with an asterisk) exists only for Chrome.

Some comments where criticizing the usage of non-standard alphabet. If you manage to find another consistent range of Unicode characters that can be used as property names in JS then feel free to improve this answer. I couldn't find better than the original.

# For ES6 arrow functions with 2 parameters, nest functions

f=(x,k)=>x+k
f=x=>k=>x+k


Only works in some cases. E.g. for recursive functions, this doesn't help because calling is one byte longer:

f(1,2)
f(1)(2)


The 9**999 is Infinity shortcut (2 characters shorter)

console.log( 9**999===Infinity )

• 1/0 is a bit shorter Feb 27 '20 at 14:53
• @James wow - it is not NaN (I don't know this) Feb 27 '20 at 14:58

Converting a string to an int/float by subtracting a empty array

Before(22 bytes)

parseFloat("12.52463")


After(13 bytes, saved 9 bytes)

"12.52463"-[]

• This is covered by other answers already. The shortest version is +"12.52463". Feb 10 '15 at 19:18
• @MartinEnder What about [restricted-source] questions? Maybe sometimes you can't use +`. May 19 '20 at 19:25