-
Notifications
You must be signed in to change notification settings - Fork 67
General Javascript Golfing Tricks
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)
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()
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.
Four times
x.
can be shortened usingwith(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()
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
......................... ?
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
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.
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.