146
\$\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

82 Answers 82

1 2
3
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))))))
| improve this answer | |
\$\endgroup\$
  • \$\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\$ – ETHproductions Nov 22 '16 at 16:56
2
\$\begingroup\$

Convert ints to strings by adding an empty string

For example:

39323+""

Returns:

"39323"

Update:

Adding [] works too

| improve this answer | |
\$\endgroup\$
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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ +"10"+ +"5"===15 \$\endgroup\$ – gion_13 Mar 14 '12 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\$ – Camilo Martin Dec 18 '12 at 13:18
  • 1
    \$\begingroup\$ You can replace the space with a + (e.g. a-+-b) \$\endgroup\$ – Toothbrush Nov 5 '15 at 16:37
  • 2
    \$\begingroup\$ In this case use a==c-b \$\endgroup\$ – l4m2 Apr 13 '18 at 16:24
  • \$\begingroup\$ maybe that can work, in some cases, but i don't think they are interchangeable on all scenarios, but very cool! \$\endgroup\$ – ajax333221 Apr 27 '18 at 23:16
2
\$\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

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You could use 0 and 1 instead of booleans. Again, semicolons are optional. \$\endgroup\$ – mbomb007 May 21 '15 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 May 21 '15 at 21:33
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
| improve this answer | |
\$\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=>{/* ... */})
| improve this answer | |
\$\endgroup\$
2
\$\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)})
| improve this answer | |
\$\endgroup\$
  • 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\$ – ETHproductions Dec 3 '16 at 20:12
  • \$\begingroup\$ @ETHproductions Updated \$\endgroup\$ – Isiah Meadows Dec 3 '16 at 20:39
2
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
  • 3
    \$\begingroup\$ And, if you don't mind changing the original array, [a.pop()], at 9 characters. \$\endgroup\$ – Tomas Langkaas Sep 8 '17 at 16:53
2
\$\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"]
| improve this answer | |
\$\endgroup\$
  • 3
    \$\begingroup\$ The first one [...'asdasd'] \$\endgroup\$ – l4m2 Apr 25 '18 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\$ – Newbie programmer Apr 26 '18 at 13:26
  • \$\begingroup\$ [...'da,dad,sa'] ... \$\endgroup\$ – Cétia Jun 27 '18 at 15:58
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)
| improve this answer | |
\$\endgroup\$
  • 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 Jun 26 '18 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 Jun 26 '18 at 12:55
  • 2
    \$\begingroup\$ 4**.5;16**.5;100**.5 is even shorter. \$\endgroup\$ – Dennis Jun 26 '18 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 Jun 29 '18 at 11:57
2
\$\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.

| improve this answer | |
\$\endgroup\$
1
\$\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)
| improve this answer | |
\$\endgroup\$
  • \$\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 Feb 11 '15 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\$ – Isiah Meadows Feb 11 '15 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\$ – Isiah Meadows Feb 12 '15 at 3:53
  • \$\begingroup\$ It's still 6 bytes saved. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 3:53
1
\$\begingroup\$

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...
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Or val&&.... Now, it is not equivalent to val == true. Example: 0 != true. \$\endgroup\$ – Isiah Meadows Feb 12 '15 at 4:56
  • \$\begingroup\$ All these strings also evaluate to true: '0', ' ', ' 0', '0 ' \$\endgroup\$ – Toothbrush Nov 5 '15 at 16:41
  • \$\begingroup\$ The technical term for "truish" is "truthy". \$\endgroup\$ – Steve Bennett Jun 24 at 3:43
1
\$\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.

| improve this answer | |
\$\endgroup\$
1
\$\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()))
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Square root hack

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

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

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @manatwork So it is, I missed that when reviewing :/ \$\endgroup\$ – caird coinheringaahing Aug 22 '19 at 9:50
0
\$\begingroup\$

Add elements to Array

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

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ 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 \$\endgroup\$ – Shaggy Sep 17 '19 at 9:37
  • \$\begingroup\$ @Shaggy thanks :) - I don't know that tricks. May be you have also some suggestion to this? \$\endgroup\$ – Kamil Kiełczewski Sep 17 '19 at 10:10
0
\$\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.

| improve this answer | |
\$\endgroup\$
0
\$\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]
| improve this answer | |
\$\endgroup\$
-1
\$\begingroup\$

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

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

| improve this answer | |
\$\endgroup\$
  • 4
    \$\begingroup\$ 1/0 is a bit shorter \$\endgroup\$ – James Feb 27 at 14:53
  • \$\begingroup\$ @James wow - it is not NaN (I don't know this) \$\endgroup\$ – Kamil Kiełczewski Feb 27 at 14:58
-2
\$\begingroup\$

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"-[]
| improve this answer | |
\$\endgroup\$
  • 13
    \$\begingroup\$ This is covered by other answers already. The shortest version is +"12.52463". \$\endgroup\$ – Martin Ender Feb 10 '15 at 19:18
  • \$\begingroup\$ @MartinEnder What about [restricted-source] questions? Maybe sometimes you can't use +. \$\endgroup\$ – VFDan May 19 at 19:25
1 2
3

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.