Skip to content

General Javascript Golfing Tricks

Joey Clark edited this page Nov 2, 2018 · 15 revisions

Looping

A reverse for loop is shorter than a forwards for loop:

for(i=0;i<10;i++)...   // before
for(i=10;i--;)...

A for loop can use a , instead of {} to do multiple things inside the body:

for(i=10;i--;){thing1();thing2()}   // before
for(i=10;i--;)thing1(),thing2()

You can save a further char by moving the last thing (or more) inside the for:

for(i=10;i--;)thing1(),thing2()   // before
for(i=10;i--;thing2())thing1()

Do you need to loop from 0 to 2 or less? You can use for ... in

for(i=0;i<3;i++)...
// becomes
for(i in 'omg')...
// but looping backwards is still shorter (if you can)
for(i=3;i--;)...

If you want to loop the values of a string:

for(p of '🦡🍄🐍')console.log(p)

Instead of two nested loops, you can often use one loop, and get the original numbers using floored division and modulus:

// Before
for(i=128;i--;)for(j=32;j--)draw(i,j)
// After
for(k=4096;i--;)draw(k/32|0,k%32)

And if the inner loop happens to be a power of two (such as 32 === 2**5), then you can get the flooring for free by using a bitshift for division:

// After
for(k=4096;i--;)draw(k>>5,k&31)

Statement separators

Usually in Javascript we use ; to separate statements. But when golfing, we can save space by using , or | to combine multiple expressions into one expression.

if(x){thing1();thing2()}
if(x)thing1(),thing2()

// Unfortunately commas won't help inside arrow functions
f=(a,b)=>thing1(a,b),thing2(b,a)     // will run thing2 _outside_ the function!

// But no problem.  In an arrow function, we can use | or & instead of ,

f=(a,b)=>{thing1(a,b);thing2(b,a)}
f=(a,b)=>thing1(a,b)|thing2(b,a)     // These both evaluate thing2()
f=(a,b)=>thing1(a,b)&thing2(b,a)     // regardless of the result of thing1()

Dictionaries (hashtables)

You can use just about any existing Javascript object as a dictionary if you need to, to avoid initialising your own.

onclick=e=>{a=[],a[9]=5}
onclick=e=>{e[9]=5,a=e}

A dictionary can be used as a cheap array, but it won't give you .length or any Array methods.

With

Four times x. can be shortened using with(x)...

Need to call a function multiple times, but it's a member of another object?

You can't do F=x.fillRect;F();F() because F won't see its context object x.

But you can do:

x.F=x.fillRect;x.F(X,Y+7,3,3);x.F(187,Y+C(X/39)*29,5,20);x.F(0,Y-S(X/29)*22,5,20)

Alternatively, or additionally, try using the with operator.

with(x)F(),F(),F(),F()

Experiment

Some of the Javascript API functions have really long names. If you are using more than ~5 of these, then these functions might help. They let us search for properties using a regexp.

/** p(object, regexp) = find key in object */
p=(o,r)=>{for(k in o)if(k.match(r))return ok}
/** P(object, regexp) = get property from object */
P=(o,r)=>o[p(r)]

f=(o,r)=>p(o,r).bind(o)

If I am using the same o repeatedly, then I might remove the o argument from those functions, and instead set it as a global before calling p or P.

So now, instead of XMLHttpRequest ......................... ?

Logic

You can not do foo&&bar=1 but you can do foo?bar=1:0

Remember that | is greedy but % is not. Other bitwise operations are also greedy (&, <<, >>, ^).

If you need to floor and then modulus, instead of (x|0)%y you can use ~~x%y

Emojis

You can access most Unicode chars directly from a string: "abc"[k]

But that doesn't work so well with emojis, because emojis are two characters each, so you only get half the code!

However, an iterators loops a string different. So you can use an iterator to copy emojis into an array, without losing them:

[...'🐸🌷☁️️'].map(e=>console.log(e))

or

for(e of '🐸🌷☁️️')console.log(e)

This only saves space if you are using 3 or more emojis.

Extreme Javascript Tricks

If you need to call a function many times, you can override the valueOf of an object, and trigger the interpreter to call it without having to use any ()s in your own code. (demo, slide)

// Before
r=Math.random;x.arc(r(),r(),r(),r(),r(),r())
// After
T.valueOf=Math.random;x.arc(T,T,T,T,T,T)

Explanation: When an object is used in an algebraic expression, before coercion its valueOf function is called by the interpreter.