Wiki: JavaScript

JavaScript is a high-level, weakly-typed, functional and imperative language. It is used most often in web pages for client-side scripts.

Due to its concise syntax, implicit type conversions and built-in functions, JavaScript is considered an excellent language for golfing. It is relatively easy to learn, especially for those familiar with [[C]]-like syntax.

code.golf uses V8, the engine used in the Chrome browser, to execute JavaScript code. Arguments are accessed through the arguments variable; output is generated using the print (output with newline) and write (output without newline) functions.

Sample code:

// Printing
print("Hello, World!");

// Looping
for (let i = 0; i < 10; i++)
    print(i);

// Accessing arguments
for (let arg of arguments)
    print(arg);

Packers

Both a 2 byte:1 char packer and a 3 byte:1 char packer are available for use on https://rucin93.github.io/javascript-parser/, as well as a regpack option for trying to minimize very large strings with potentially repeating patterns. There are even more packers than that on this page which you can experiment with, but those three see the most common usage.

Conditions

Rather than using an if statement or a ternary statement, you can very often get away with logical operators.

// these are generally identical
if(x)print(y)
x&&print(y)

// so are these
if(!x)print(y)
x||print(y)

Mapping over arguments

The most obvious way to loop over arguments is with a for .. of-loop. However, often it is one byte shorter to use a map function.

// for simple statements, map is shorter
for(a of arguments)print(a-2)
arguments.map(a=>print(a-2))
// for more complex statements, it sometimes isn't
for(a of arguments)for(c of a)<expression>
arguments.map(a=>{for(c of a)<expression>})

It is occasionally not obvious which of the two is shorter, so it is often worth it to spend some time playing around with alternative methods to write the body of the loop that may be equally long, just to check if there is an opportunity for one of the two loop structures to be shorter.

Parsing to integer value

The easiest way to parse many values to an integer is with bitwise operators. This can often be done with expression|0, expression^0 or ~~expression. Here are some examples:

5.5|0        // 5
"5"+"6.5"|0  // 56
"0b101"|0    // 5, note that it correctly parses a string in binary notation
5.6+6.6|0    // 12, note low precedence of bitwise OR
~~5.6+~~6.6  // 11, note high precedence of bitwise NOT
[53.2]|0     // 53
[53.2,3]|0   // 0. Anything that cannot be properly parsed becomes 0, no matter the original type.

Incrementing and decrementing

An alternative method of incrementing and decrementing to +1 and -1 is to use -~ and ~-. This can make a difference when you need something with higher precedence than addition, or when the original value may need to be parsed to a number first

~-5         // 4
-~5         // 6
~-"5"       // 4
~-[][1]     // -1, gets coerced from undefined

Nested loop

Occasionally you will have a nested for-loop, where in the inner loop you require a copy of the outer-loop iterator. In this case, you can sometimes make the condition of the outer loop terminate with modulo rather than a comparison operator to preserve the value of the iterator, so you can assign it to the inner-loop variable.

for(i=0;++i<100;)for(j=i;<condition>;)<code>
for(i=0;j=++i%100;)for(;<condition>;)<code>        // saves a byte

Comma separation

If you separate expressions by a comma, they will still be evaluated as separate expressions, but they can behave as a single line of code. This means you can have multiple expressions in a loop structure without requiring curly braces.

for(x of y){foo(x);print(x)}
for(x of y)foo(x),print(x)

Comma separation has another use in square bracket indexing and in expressions in parentheses. Every expression will be evaluated, but only the last one will be the return value.

[0,1,2][print(2),1]         // prints 2, returns 1
(print(2),1)                // prints 2, returns 1
/* 
  all three expressions get evaluated if x is truth-y.
  the return value is 5 if x is truth-y.
*/
x&&(foo(x),x*=2,print(y),5) 

Multiple print arguments

You can pass multiple arguments to the functions print, write and console.log. Each argument will be printed, separated by spaces.

print("Hello","World!")  // prints "Hello World!"
print(...[1,2,3])        // spread operator turns each element into an argument, so this prints "1 2 3"

This can occasionally be used to save a byte when trying to print some value followed by a space.

print(x+" ")
print(x,"")

Function arguments

If you supply more arguments to a function than that function takes, those arguments will be evaluated as expressions even though they will not be used by that function.

/* 
  replaceAll only takes 2 arguments so the return value of print(z) is ignored, 
  but z will be printed
*/
str.replaceAll(x,y,print(z))

If a function takes no arguments, this means you can add an expression without the cost of any kind of expression separator.

// consider these two functions that each take no arguments
f=()=>3
g=()=>4
// then these two lines do the same
x=f(),y=g()
y=g(x=f())

Tagged templates

With template strings you can write a literal newline in the string rather than having to use \n, saving 1 byte.

// you can write this
"Hello\nWorld!"
// but this is shorter
`Hello
World!`

You can sometimes use a tagged template to save two bytes when passing a string to a function.

"1,2,3".split(",")  // returns ["1","2","3"]
"1,2,3".split`,`    // also returns ["1","2","3"], but saves two bytes

This often works on string.split and array.join.

Functions are objects

If you need to define an array, and you have already defined a function in your code, you may be able to use that function as an array to save the bytes from having to separately define an array.

f=x=>x+2
f[2]=5
print(f[2]) // prints 5

Note: since this object is of type Function and not of type Array, this object will not have access to any methods of Array.

Functions can be strings

If you compare a string to a function, that function will be converted to a string for the comparison. For example, "x">(b=>b+2) will be evaluated as "x">"b=>b+2". If you have a function with only one argument, you can sometimes pick its argument's name to be useful for specific comparisons.

/*
  since "$" just barely has a higher ASCII value than " " 
  you can often get away with this as a means for checking if something is a space
*/
f=$=>$+2
x<f 
/*
  lowercase letters have higher ASCII values than uppercase letters, 
  so you can use this to check if a letter is uppercase
*/
f=a=>$+2
x<f 

Using x<f here is shorter than x<"a" by two bytes.

Methods can be called with strings

If you end up using the same method several times, you can occasionally use square bracket indexing with a string to call the method instead. This way you can store the string name in a variable, so you do not have to type its full name each time.

// with a long method name this can be shorter with only two uses
s.charCodeAt();t.charCodeAt();
s[c="charCodeAt"]();t[c]();
// short method names often require several uses for this to be shorter
a.slice(x);b.slice(y);c.slice(z);
a[s="slice"](x);b[s](y);c[s](z);

Shortest way to replace a substring

If you want to replace each occurance of substring a in string b, the obvious way to do this is with a replace method on b. However, if both a and b are simple strings, using string.split and string.join usually saves one byte.

"1,2,3".replace(/,/g," ")  // "1 2 3"
"1,2,3".split`,`.join` `

Useful undefined coercion

Since +[] coerces to empty string, and +[undefined] also eventually coerces to empty string. In some cases it's possible to replace parenthesis with square brackets:

'a:'+('qwe'[3]||'r') // returns 'a:r'
'a:'+['qwe'[3]||'r'] // returns 'a:r'

However if there is no need for fallback value - could be like conditional addition of a string or a character, then it's shorter to use +[undefined]

'a:'+('qwe'[3]||'') // returns 'a:'
'a:'+['qwe'[3]]     // returns 'a:'

// All of these variations will print "a:" for i=1
'a:'+('°'[i%2]||'')
'a:'+(i%2?'':'°')
'a:'+['°'[i%2]]

[!] This can be useful for conditional printing as well. [!]

Shorter for range loop

These are (to my knowledge) the shortest ways to loop from 0 to n-1 of the form: for(i in ???)print(i). All are either equal to or shorter than the standard for(i=0;i<???;)print(i++) equivalents.

for(i in'??')print(i)     // 2
for(i in'???')print(i)    // 3
for(i in''+!0)print(i)    // 4
for(i in''+!1)print(i)    // 5
for(i in''+1e5)print(i)   // 6
for(i in''+1e6)print(i)   // 7
for(i in''+1e7)print(i)   // 8
for(i in''+1e8)print(i)   // 9
for(i in''+1e9)print(i)   // 10
for(i in''+1e10)print(i)  // 11
for(i in''+1e11)print(i)  // 12
for(i in''+1e12)print(i)  // 13
for(i in''+1e13)print(i)  // 14
for(i in''+{})print(i)    // 15
for(i in{}+1)print(i)     // 16
for(i in{}+11)print(i)    // 17
for(i in{}+.1)print(i)    // 18
for(i in{}+!0)print(i)    // 19
for(i in{}+!1)print(i)    // 20
for(i in{}+1e5)print(i)   // 21
for(i in{}+1e6)print(i)   // 22
for(i in{}+1e7)print(i)   // 23
for(i in{}+1e8)print(i)   // 24
for(i in{}+1e9)print(i)   // 25
for(i in{}+1e10)print(i)  // 26
for(i in{}+1e11)print(i)  // 27
for(i in{}+1e12)print(i)  // 28
for(i in{}+1e13)print(i)  // 29
for(i in{}+{})print(i)    // 30
for(i in{}+1e15)print(i)  // 31
for(i in''+Map)print(i)   // 32
for(i in 1+Map)print(i)   // 33
for(i in-1+Map)print(i)   // 34
for(i in.1+Map)print(i)   // 35
for(i in!0+Map)print(i)   // 36
for(i in!1+Map)print(i)   // 37
for(i in{}+Map)print(i)   // 47