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
99 Answers 99
Splitting with numbers to save the quotemarks:
"alpha,bravo,charlie".split(",") // before
"alpha0bravo0charlie".split(0) // after
-
2\$\begingroup\$ It works, and I've used it for multiple digits. \$\endgroup\$Claudia– Claudia2015年02月12日 03:55:49 +00:00Commented Feb 12, 2015 at 3:55
-
16\$\begingroup\$ Lol this is actually pretty creative \$\endgroup\$NiCk Newman– NiCk Newman2015年11月03日 19:37:23 +00:00Commented Nov 3, 2015 at 19:37
-
28\$\begingroup\$ in ES6 this doesn't matter anymore, you can just do
.split`...`\$\endgroup\$David Archibald– David Archibald2017年04月15日 22:41:48 +00:00Commented Apr 15, 2017 at 22:41 -
11\$\begingroup\$
"alpha,bravo,charlie".split`,`\$\endgroup\$Kamil Kiełczewski– Kamil Kiełczewski2019年09月16日 09:32:38 +00:00Commented Sep 16, 2019 at 9:32 -
2\$\begingroup\$ I've also used
"AlphaBravoCharlie".split(/(?=[A-Z])/)once. Only useful when you have a lot of words to split. \$\endgroup\$Domino– Domino2022年04月01日 15:26:01 +00:00Commented Apr 1, 2022 at 15:26
Fancy For Loops
you can use the standard for loop in non-standard ways
for ( a; b; c )
is essentially equivalent to:
a;
while ( b )
{
...
c;
}
so a good trick is to write your code with a while loop, and then split it into the a,b,c parts in a for loop.
A couple examples I've written:
for(x=y=n;!z;x--,y++)z=i(x)?x:i(y)?y:0
for(a=b=1;b<n;c=a+b,a=b,b=c);
Chain your setters
If you're initializing or resetting multiple values, chain the value to all the variables that need it:
a=b=1;
Implicit Casting
Don't check your types, just use them as they are. parseInt() costs 10 characters. If you need to cast out of a string, be creative:
a='30';
b='10';
c = a + b; //failure
c = parseInt(a) + parseInt(b) //too long
c = -(-a-b); //try these
c = ~~a+~~b;
c = +a+ +b;
c = a- -b;
Avoid Semicolons
JavaScript has automatic semi-colon insertion. Use it often and well.
One-liners
Save on brackets by shoving as much as possible into single lines, or parameters:
a( realParam1, realParam2, fizz='buzz' )
Increment/Decrement operators
a = a - 1;
foo(a);
and
foo(a);
a = a - 1;
can easily be rewritten as
foo(--a);
and
foo(a--);
respectively.
Use this or self instead of window in global context
self explanatory 2 character savings.
Use bracket notation for repeat property access
This is definitely a balancing act between property name length and number of accesses. Instead of calling a.longFunctionName() with dot notation twice, it's shorter to save the name and call the function via bracket notation:
a.longFunctionName(b)
a.longFunctionName(c)
//42
-vs-
a[f='longFunctionName'](b)
a[f](c)
//34
this is especially effective with functions like document.getElementById which can be reduced to d[e].
Note:
With bracket notation, the cost is 6 + name.length characters the first time. Each subsequent access has a cost of 3 characters.
For dot notation, all accesses cost name.length + 1 (+1 for the .) characters.
Use this method if 6 + name.length + (3 * (accesses - 1)) < accesses * (name.length + 1).
len = length of property name
i = minimum accesses to take advantage
len | i
========
1 | ∞
2 | ∞
3 | 7
4 | 4
5 | 3
6 | 3
7 | 3
8+ | 2
The number of accesses can also span multiple objects. If you access .length 4 or more times on different arrays, you can use the same variable holding the string 'length'.
-
5\$\begingroup\$
c = ~~a-~~bshould bec = ~~a+~~b. Also, you can implicitly cast to integer using|0, for exampleMath.random()*6|0. \$\endgroup\$mellamokb– mellamokb2011年06月01日 19:48:22 +00:00Commented Jun 1, 2011 at 19:48 -
7\$\begingroup\$ It's cheaper to coerce a string to a number with the unary plus operator. If
aandbare strings, you can do+a+bto convert to number and add them. \$\endgroup\$Peter Olson– Peter Olson2011年12月02日 21:38:52 +00:00Commented Dec 2, 2011 at 21:38 -
11\$\begingroup\$ I swear I'm going to use
d- -bin my code someday... \$\endgroup\$John Dvorak– John Dvorak2013年12月19日 14:21:29 +00:00Commented Dec 19, 2013 at 14:21 -
5\$\begingroup\$ +a+b doesn't work (at least on mine...) // a="1",b="1",+a+b // gives "11" \$\endgroup\$imma– imma2014年01月16日 11:46:03 +00:00Commented Jan 16, 2014 at 11:46
-
3\$\begingroup\$ For "Use Array-Access for repeat function calls" if you're using the function more than twice on the same object, what's a bit shorter is to assign the function to a new member like
a.f=a.longfunctionname;a.f(b);a.f(c);a.f(d)\$\endgroup\$Martin Ender– Martin Ender2014年09月11日 14:40:46 +00:00Commented Sep 11, 2014 at 14:40
Use the comma operator to avoid braces (also applies to C):
if(i<10)m+=5,n-=3;
Instead of
if(i<10){m+=5;n-=3}
which is one character longer.
-
2\$\begingroup\$ Is the semicolon necessary at the end of the first sample? \$\endgroup\$wjl– wjl2012年08月20日 06:12:18 +00:00Commented Aug 20, 2012 at 6:12
-
4\$\begingroup\$ @wjlafrance: It would only not be required if it's at the end of the one-liner. \$\endgroup\$mellamokb– mellamokb2012年08月20日 14:57:59 +00:00Commented Aug 20, 2012 at 14:57
-
6\$\begingroup\$ This can also be written as
i<10&&m+=5,n-=3\$\endgroup\$pavi2410– pavi24102019年11月11日 21:41:25 +00:00Commented Nov 11, 2019 at 21:41 -
2\$\begingroup\$ @pavi2410 That doesn't parse correctly due to precedence issues. \$\endgroup\$Maya– Maya2023年04月22日 06:48:12 +00:00Commented Apr 22, 2023 at 6:48
Shorter random number generation
If you need a random boolean (0 or 1):
new Date&1 // equivalent to Math.random()<0.5
If you need a random integer 0 <= n < 1337:
new Date%1337 // equivalent to Math.floor(Math.random()*1337))
This works because a Date is stored internally in JavaScript as the amount of milliseconds since an epoch, so the new Date is being coerced into 123somebignumber456 when you try to do integer math on it.
Of course, these "random" numbers really won't be as random, especially if you call them multiple times in quick succession, so keep that in mind.
-
4\$\begingroup\$ Just remembered this answer while reading More falsehoods programmers believe about time: "21. If you create two date objects right beside each other, they’ll represent the same time. (a fantastic Heisenbug generator)". \$\endgroup\$Sebastian Simon– Sebastian Simon2019年03月01日 13:35:26 +00:00Commented Mar 1, 2019 at 13:35
You can use the object literal form of get/set to avoid using the keyword function.
var obj = {
get f(){
console.log("just accessing this variable runs this code");
return "this is actually a function";
},
set f(v){
console.log("you can do whatever you want in here, passed: " + v);
}
};
1 && obj.f; // runs obj.[[get f]]
obj.f = Infinity; // runs obj.[[set f]](Infinity)
-
\$\begingroup\$ the getter/setter part was really helpful. thx \$\endgroup\$gion_13– gion_132012年03月14日 10:01:07 +00:00Commented Mar 14, 2012 at 10:01
-
1\$\begingroup\$ Actually, even better is an object method, if you only use it <= 2 times. On the other hand, arrow functions are far better at cutting down characters, as they serve almost the same purpose, and classes are rarely useful in golfed code. \$\endgroup\$Claudia– Claudia2015年02月12日 03:57:42 +00:00Commented Feb 12, 2015 at 3:57
-
\$\begingroup\$ if support is important arrow functions aren't supported in fx. ie11 \$\endgroup\$Jim Wolff– Jim Wolff2017年09月18日 13:38:56 +00:00Commented Sep 18, 2017 at 13:38
This one is lesser known and lesser used, but can be impressive if used in the right situation. Consider a function that takes no arguments and always returns a different number when called, and the returned number will be used in a calculation:
var a = [
Math.random()*12|0,
Math.random()*11|0,
Math.random()*10|0,
/* etc... */
];
You might normally shorten this function using a single-letter variable name:
var r=Math.random,a=[r()*12|0,r()*11|0,r()*10|0,r()*9|0,r()*8|0,r()*7|0,r()*6|0,r()*5|0];
A better way to reduce the length is by abusing valueOf, which gives you a saving of 2 characters per invocation. Useful if you call the function more than 5 times:
var r={valueOf:Math.random},a=[r*12|0,r*11|0,r*10|0,r*9|0r*8|0,r*7|0,r*6|0,r*5|0];
-
10\$\begingroup\$ Or, you could do it like either of these:
let a=[5,6,7,8,9,10,11,12].map(x=>x*Math.random()|0)orlet a=Array(7).map((_,i)=>i*Math.random()|0+5), 36 or 42 bytes saved, respectively. \$\endgroup\$Claudia– Claudia2015年02月12日 04:05:58 +00:00Commented Feb 12, 2015 at 4:05 -
\$\begingroup\$ Is it possible to replace
r(), or make it shorter? \$\endgroup\$NiCk Newman– NiCk Newman2015年11月03日 19:46:23 +00:00Commented Nov 3, 2015 at 19:46 -
4\$\begingroup\$
r={valueOf:Math.random}That's just genius :D \$\endgroup\$ETHproductions– ETHproductions2016年11月22日 17:03:37 +00:00Commented Nov 22, 2016 at 17:03 -
2\$\begingroup\$ @Isiah, well yeah, you can do that now :-D \$\endgroup\$Andy E– Andy E2016年11月22日 22:57:26 +00:00Commented Nov 22, 2016 at 22:57
Taking advantage of short-circuit operators
Rather than long if statements or using ternary operators, you can make use of && and || to shorten your code. For instance:
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
can become
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
The || operator is often used in this way for setting defaults:
evt = evt || window.event;
This is the same as writing
if (!evt)
evt = window.event;
Creating repetitive strings using Array
If you want to initialize a long string of a particular character, you can do so by creating an array with a length of n+1, where n is the number of times you wish to repeat the character:
// Create a string with 30 spaces
str = " ";
// or
str = Array(31).join(" ");
The larger the string, the bigger the saving.
Parsing numbers
Use + and ~ operators instead of parseFloat() or parseInt() when coalescing a string type that is just a number to a number type:
var num = "12.6";
parseFloat(num) === +num; // + is 10 characters shorter than parseFloat()
var num2 = "12"
parseInt(num2) === +num2; // + is 8 characters shorter than parseInt()
var num3 = "12.6"
parseInt(num3) === ~~num3; // ~~ is 7 characters shorter than parseInt()
var num4 = "12.6"
parseInt(num4) === num4|0; // |0 is 7 characters shorter than parseInt()
Be wary though, other types can be coalesced with these operators (for instance, true would become 1) an empty string or a string containing just white space would become 0. This could be useful in certain circumstances, however.
-
7\$\begingroup\$ +1 for Creating repetitive strings using Array - hadn't thought about that one. \$\endgroup\$mellamokb– mellamokb2011年06月09日 15:04:30 +00:00Commented Jun 9, 2011 at 15:04
-
12\$\begingroup\$ To create repetitive strings, in ES6 you can use
str.repeat(count)\$\endgroup\$Oriol– Oriol2015年05月12日 16:38:42 +00:00Commented May 12, 2015 at 16:38
Unicode shortcuts
If you use a hell of a built-in property at a big golfing challenge you can alias every property to a one character equivalent:
[Math,Number,S=String,Array].map(b=>
Object.getOwnPropertyNames(b).map((p,i)=>
b.prototype[S.fromCharCode(i+248)]=b[p]
)
)
After executing the code above you can use it like this:
"foo".Č(/.*/,'bar') // replaces foo with bar
This costs 118 bytes, so it might not be useful in certain situations
It may be browser dependent and i'm not sure if it's shorter than with(Array){join(foo),...} or defining variables as used properties with(Array){j=join,m=map...} but still it is worth mentioning.
Math Number String Array
ø toSource prototype prototype prototype
ù abs NaN quote join
ú acos POSITIVE_INFINITY substring reverse
û asin NEGATIVE_INFINITY toLowerCase sort
ü atan MAX_VALUE toUpperCase push
ý atan2 MIN_VALUE charAt pop
þ ceil MAX_SAFE_INTEGER charCodeAt shift
ÿ clz32 MIN_SAFE_INTEGER contains unshift
Ā cos EPSILON indexOf splice
ā exp isFinite lastIndexOf concat
Ă floor isInteger startsWith slice
ă imul isNaN endsWith filter
Ą fround toInteger trim isArray
ą log parseFloat trimLeft lastIndexOf
Ć max parseInt trimRight indexOf
ć min length toLocaleLowerCase forEach
Ĉ pow name toLocaleUpperCase map
ĉ random arguments normalize every
Ċ round caller match some
ċ sin search reduce
Č sqrt replace reduceRight
č tan split
Ď log10 substr
ď log2 concat
Đ log1p slice
đ expm1 fromCharCode
Ē cosh fromCodePoint
ē sinh localeCompare
Ĕ tanh length
ĕ acosh name
Ė asinh arguments
ė atanh caller
Ę hypot
ę trunc
Ě sign
ě cbrt
Ĝ E
ĝ LOG2E
Ğ LOG10E
ğ LN2
Ġ LN10
ġ PI
Ģ SQRT2
ģ SQRT1_2
-
1\$\begingroup\$ I'm using google chrome, and these are all giving undefined. \$\endgroup\$SuperJedi224– SuperJedi2242015年05月14日 19:19:34 +00:00Commented May 14, 2015 at 19:19
-
\$\begingroup\$ It must be very firefox specific then. Sorry for the inconvenience. \$\endgroup\$bebe– bebe2015年05月15日 16:44:59 +00:00Commented May 15, 2015 at 16:44
-
\$\begingroup\$ Why are these all special characters? Why not just use printable ASCII? (easier to type, more reliable, and only 1 byte for golfing) \$\endgroup\$Cyoce– Cyoce2016年02月10日 20:02:21 +00:00Commented Feb 10, 2016 at 20:02
-
1\$\begingroup\$ This doesn't really work for
Mathbecause it doesn't have a.prototypeattribute. RemovingMath, though, I managed to golf this down to a 114-byte snippet that assigns them all to single-byte letters. You can find it here. \$\endgroup\$ETHproductions– ETHproductions2016年12月03日 20:50:36 +00:00Commented Dec 3, 2016 at 20:50 -
3\$\begingroup\$ You can also golf my solution to 106 bytes at the expense of moving all these properties to the range
À-ÿ, which is still 1 byte each in the ISO-8859-1 encoding (which JS supports). In Firefox 50, this unfortunately puts the.localeComparemethod on×, but that shouldn't usually be an issue. source \$\endgroup\$ETHproductions– ETHproductions2016年12月03日 21:59:13 +00:00Commented Dec 3, 2016 at 21:59
Combine nested for loops:
// before:
for(i=5;i--;)for(j=5;j--;)dosomething(i,j)
// after:
for(i=25;i--;)dosomething(0|i/5,i%5)
Example with different values for i/j:
// before:
for(i=4;i--;)for(j=7;j--;)dosomething(i,j)
// after:
for(i=28;i--;)dosomething(0|i/7,i%7)
-
\$\begingroup\$ (I've edited a) minor typo, but very clever! Note that this will only work on nested loops of same length (unless I'm wrong). \$\endgroup\$Camilo Martin– Camilo Martin2012年12月18日 13:26:31 +00:00Commented Dec 18, 2012 at 13:26
-
1\$\begingroup\$ @CamiloMartin No, the loops don't need to be of equal length. The resulting number of iterations is
i*jand the division/modulus operators retrieve the individual values ofiandj. \$\endgroup\$quietmint– quietmint2013年12月19日 00:38:09 +00:00Commented Dec 19, 2013 at 0:38 -
\$\begingroup\$ @user113215 You're right, awesome! :) I've edited the answer to include an example. \$\endgroup\$Camilo Martin– Camilo Martin2013年12月19日 14:14:54 +00:00Commented Dec 19, 2013 at 14:14
Sneak variable initialization into the prompt() call for getting user input
n=prompt(i=5); // sets i=5 at the same time as getting user input
instead of using
n=prompt();i=5;
As a side-effect, it displays the input value in the prompt window while saving 1 character.
-
17\$\begingroup\$ This can also be applied to any function that doesn't accept arguments. \$\endgroup\$Casey Chu– Casey Chu2011年06月19日 21:59:33 +00:00Commented Jun 19, 2011 at 21:59
-
3\$\begingroup\$ Even when the function accepts arguments it can be useful, as in
[1,2,3].join('',i=5)in cases where it saves a pair of braces. \$\endgroup\$DocMax– DocMax2011年06月30日 00:58:23 +00:00Commented Jun 30, 2011 at 0:58 -
3\$\begingroup\$ @DocMax: You could use comma operator for that -
i=5,[1,2,3].join(). \$\endgroup\$null– null2013年01月04日 11:59:33 +00:00Commented Jan 4, 2013 at 11:59 -
\$\begingroup\$ @GlitchMr: I could, but it doesn't save any characters. I agree that most of the time that will be cleaner. I think there may still be cases where my ordering might save a char, although I cannot come up with one at the moment (and I may well be wrong). \$\endgroup\$DocMax– DocMax2013年01月04日 17:01:22 +00:00Commented Jan 4, 2013 at 17:01
-
\$\begingroup\$ @DocMax Only if you are taking advantage of ASI. \$\endgroup\$Claudia– Claudia2015年02月12日 04:10:27 +00:00Commented Feb 12, 2015 at 4:10
Use ^ instead of != or == when comparing to an integer
//x!=3?a:b
x^3?a:b
//x==3?a:b
x^3?b:a
Replace calls to built-in Math functions with shorter expressions
//Math.ceil(n)
n%1?-~n:n
//Math.floor(n)
~~n
0|n
//Math.abs(n)
n<0?-n:n
//Math.round(n)
n+.5|0
//Math.min(x,y)
x<y?x:y
//Math.max(x,y)
y<x?x:y
-
7\$\begingroup\$ Alternatively, you can simply use
-instead of!=for integers; For example,n!=1?a:bwould be equivalent ton-1?a:b\$\endgroup\$user83717– user837172019年05月03日 10:32:29 +00:00Commented May 3, 2019 at 10:32 -
\$\begingroup\$ For arrays, use
Math.max(...a)though. \$\endgroup\$emanresu A– emanresu A2021年03月30日 20:46:15 +00:00Commented Mar 30, 2021 at 20:46 -
1\$\begingroup\$ These wont work for negatives... \$\endgroup\$Siddharth Shyniben– Siddharth Shyniben2021年11月21日 13:24:13 +00:00Commented Nov 21, 2021 at 13:24
Abuse literals
The recent sample: Check whether "c" is uppercase or lowercase, doesn't matter if not letter
"c"<{} // returns false, lower case
"C"<{} // returns true, upper case
Array sum / product / quotient
ES5: 17 bytes
eval(a.join('+'))
ES6: 15 bytes
eval(a.join`+`)
Of course you can swap the + for anything you want, e.g., * for product or / for quotient.
-
2\$\begingroup\$ +1, tired of using
reduceand using up bytes \$\endgroup\$user100690– user1006902021年03月11日 16:56:58 +00:00Commented Mar 11, 2021 at 16:56 -
\$\begingroup\$ And
eval(a.join('+'))/a.lengthfor average. \$\endgroup\$QOO-OOKALAN– QOO-OOKALAN2025年11月10日 16:51:56 +00:00Commented Nov 10 at 16:51
Exception abusing
in case string/character literals are prohibited, you can use a try catch block:
try{something0}catch(e){str=e.message.split(0)[0]}
now str equals "something"
if more strings are needed you can chain it with a number (e.g. zeros)
try{something0foo0bar0}catch(e){arr=e.message.split(0)}
now arr equals ["something", "foo", "bar", " is not defined"]
If you need to check for NaN, don't use isNaN(x), but use x!=x, which is shorter and also works.
if(isNaN(x)){
if(x!=x){
Note that this only works if typeof(x) === "number"; if it's a string for example, isNaN("string") returns true, but "string" != "string" returns false. Thanks to Cyoce for pointing this out!
-
2\$\begingroup\$ That's a genius use of this quirk. +1 \$\endgroup\$ETHproductions– ETHproductions2015年12月22日 21:05:51 +00:00Commented Dec 22, 2015 at 21:05
-
\$\begingroup\$ Warning: these are not always equivalent:
isNaN("string")returnstrue, whereas"string"!="string"returnsfalse(obviously) \$\endgroup\$Cyoce– Cyoce2016年02月10日 22:18:46 +00:00Commented Feb 10, 2016 at 22:18 -
\$\begingroup\$ In many cases, you can even go for
if(!x){, if you are detectingNaNexplicitly. \$\endgroup\$SE - stop firing the good guys– SE - stop firing the good guys2016年08月09日 21:24:31 +00:00Commented Aug 9, 2016 at 21:24 -
\$\begingroup\$ More specifically,
x!=xreturns true only forNaN. \$\endgroup\$ETHproductions– ETHproductions2016年12月01日 19:15:03 +00:00Commented Dec 1, 2016 at 19:15 -
3\$\begingroup\$ Casting
xto number,+x!=+x, makes it equivalent toisNaN(x), yet still 2 characters shorter. Then,+"string"!=+"string"returns true. \$\endgroup\$Tomas Langkaas– Tomas Langkaas2017年09月08日 19:50:42 +00:00Commented Sep 8, 2017 at 19:50
Converting a while loop into a for loop is often equivalent:
while(i--);
for(;i--;);
But the second form can have variable initialization combined:
i=10;while(i--);
for(i=10;i--;);
Notice the second form is one character shorter than the first form.
-
6\$\begingroup\$ Or, even better, just use for loops. There's really no case where using a for loop results in larger code, as far as I have experienced. \$\endgroup\$Claudia– Claudia2015年02月12日 04:08:41 +00:00Commented Feb 12, 2015 at 4:08
If you're initializing a variable to 1 in every iteration of a loop (for example, resetting a variable in an outer loop for an inner loop), like the following (from my answer to this question):
for(j=n-2;p=1,j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^
Since the result of a condition like j++<=n is 1 whenever its true, you can just assign the condition directly to the variable (because when it becomes false, the loop will stop executing and will no longer matter):
for(j=n-2;p=j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^^^^^
You can usually save 2 characters using this method. Regards to @ugoren for the idea in the comments to that answer.
For another example, I also applied this trick to my answer here with the expression w=r=++c<S.length in my outer for loop, saving a total of 4 characters.
If you can accept Spidermonkey (for now) specific scripts, you can use ECMAScript 6 arrow functions. Insteading of writing code like the following.
a.map(function(x){return x*2}) // function? return?
You can shorten it like this.
a.map(x=>x*2)
-
\$\begingroup\$ And now this is standard modern JS so should be in codegolf.stackexchange.com/questions/37624/… \$\endgroup\$qwr– qwr2022年07月13日 02:34:42 +00:00Commented Jul 13, 2022 at 2:34
Rounding
I know that alternatives to Math.floor() have been posted, but what about the others?
Flooring:
Math.floor(x) //before
0|x //after
Rounding:
Math.round(x) //before
0|x+.5 //after
Ceiling:
Math.ceil(x) //before
x%1?-~x:x //after - credits to @Tomas Langkaas
-
1\$\begingroup\$ Note that
0|x+1simply adds 1 if the number you want to find the ceiling of is already an integer. A (mostly) safe alternative is0|x+1-1e9, but this is only three bytes shorter. \$\endgroup\$ETHproductions– ETHproductions2015年11月07日 18:11:16 +00:00Commented Nov 7, 2015 at 18:11 -
1\$\begingroup\$ @ETHproductions don't you mean
0|x+1-1e-9? \$\endgroup\$Mama Fun Roll– Mama Fun Roll2015年11月24日 01:40:03 +00:00Commented Nov 24, 2015 at 1:40 -
\$\begingroup\$ Oops, yeah. Thanks for pointing that out. (For some reason, I can't do @(your username)...) \$\endgroup\$ETHproductions– ETHproductions2015年11月24日 01:42:48 +00:00Commented Nov 24, 2015 at 1:42
-
\$\begingroup\$ Probably because my username chars are upside down :) \$\endgroup\$Mama Fun Roll– Mama Fun Roll2015年11月24日 01:45:53 +00:00Commented Nov 24, 2015 at 1:45
-
1\$\begingroup\$ For ceiling,
x%1?-~x:x(9 characters) is a better alternative. However, like the flooring alternatives0|xand~~x, it only works for positive numbers. \$\endgroup\$Tomas Langkaas– Tomas Langkaas2017年09月08日 18:40:22 +00:00Commented Sep 8, 2017 at 18:40
Use a bitwise operation to round a number toward zero:
// do this
T=Math.random()*6+1|0
// or do this
T=~~(Math.random()*6+1)
(Source: Random dice tipping)
Operator precedence determines which will be shorter in your program.
-
2\$\begingroup\$ This can also be used to coalesce a string input into an integer, i.e.,
n=prompt()|0. \$\endgroup\$mellamokb– mellamokb2011年05月27日 13:31:09 +00:00Commented May 27, 2011 at 13:31 -
1\$\begingroup\$ bitwise is also super fast compared to math.floor : jsperf.com/floor-vs-bitwise \$\endgroup\$vsync– vsync2011年06月07日 22:33:31 +00:00Commented Jun 7, 2011 at 22:33
-
\$\begingroup\$ @vsync: Weird. I get math.floor to be about twice as fast as bitwise on Chrome 11.0.696.77. \$\endgroup\$mellamokb– mellamokb2011年06月08日 11:47:39 +00:00Commented Jun 8, 2011 at 11:47
-
\$\begingroup\$ very weird. for me they are both more or less same speeds & super fast in Chrome, but in FF the bitwise is a lot faster than Chrome, and
Math.flooris terribly slow..almost should not be used I would say. \$\endgroup\$vsync– vsync2011年06月08日 16:15:06 +00:00Commented Jun 8, 2011 at 16:15 -
\$\begingroup\$ To keep the comments up-to-date, in current Fx they're both fast & about equal. Not that it's likely to be a bottleneck in the first place, compared to surrounding code... \$\endgroup\$FireFly– FireFly2014年02月01日 20:13:14 +00:00Commented Feb 1, 2014 at 20:13
Looping Tip I
You can save 1 character when looping by changing the i on the last time used:
//not so god
for(i=0;i<3;i++){
alert(i);
}
//best
for(i=0;i<3;){
alert(i++);
}
Note: works with -- too (but modify the loop accordingly to avoid infinite looping)
Looping Tip II
There are certain scenarios where you can save one character by playing with the incrementing operator and values:
for(i=0;i++<9;)
for(i=0;++i<10;)
Note: you need to pay attention when for example 0 to -1. and 9 to 10, 99 to 100, so play around until you find a way to save the character
Converting an array of strings into numbers
Take the array ["32", "0x30", "0o10", "7.642", "1e3"]. The simple way to convert this to numbers would be .map(n=>+n) or .map(Number).
However, assuming you know everything is a valid number, you can simply use .map(eval), saving at least a byte.
Very simple one, even so, no one had mentioned it.
If you're using Math.min() or Math.max() you can save 6 chars by doing this:
Math.min(a,b) // 13 chars
a<b?a:b // 7 chars
Math.max(a,b)
a>b?a:b
Free commas!
Often you'll want to include a comma in a string, perhaps like so:
f=(x,y,z)=>x+","+y+z
By abusing the string representation of arrays, this can be shortened by two bytes:
f=(x,y,z)=>[x,y]+z
This particular instance only works if you have three variables you want to concatenate as shown. You can use the same trick with two, but you need to be careful. There are three variants you might try:
f=(x,y)=>[x,y]
f=(x,y)=>[x,]+y
f=(x,y)=>x+[,y]
The first one will return an actual array rather than a string, which defeats the purpose. The second one looks like it will work, but in fact most modern browsers will remove the trailing comma when parsing the array. The third one will work though, at the same byte count as the second.
To put this to good use, say you have a function which creates the range [0...n]:
f=x=>x?[...f(x-1),x]:[0]
If returning a string with a separator is allowed, you might do something like this, saving a few bytes:
f=x=>x?f(x-1)+" "+x:0
However, you can save another byte with an array literal:
f=x=>x?f(x-1)+[,x]:0
Note that depending on how you arrange the recursion, you may end up with a leading or trailing separator, so you'll need to make sure your output format is allowed by the challenge.
-
\$\begingroup\$ You may not be able to do
[x,]+y, but you can do[x,,]+y. Though it occurs to me that's the same amount of bytes asx+','+y, so nevermind. \$\endgroup\$Patrick Roberts– Patrick Roberts2017年10月05日 05:43:46 +00:00Commented Oct 5, 2017 at 5:43 -
\$\begingroup\$ you can save 1 byte:
f=x=>x?f(x-1)+" "+x:0==>f=x=>x&&f(x-1)+" "+x\$\endgroup\$Yukulélé– Yukulélé2022年02月12日 23:19:18 +00:00Commented Feb 12, 2022 at 23:19
Prefer .map over .reduce
Consider the following code for summing an array:
a.reduce(function(x,y){return x+y})
Pretty long, right? What if I told you that you could get rid of the return? Well, you can:
a.map(function(x){t+=x},t=0) // 7 bytes saved
(Although an even shorter way is eval(a.join("+")).)
How about reducing by multiplication, where you have to specify the starting number anyway?
a.reduce(function(x,y){return x*y},1) // Looooong
a.map(function(x){t*=x},t=1) // An easy 9 bytes shorter
(Again, eval(a.join("*")) works as well.)
Here, let's try one that doesn't work with eval(a.join()):
a.reduce(function(x,y){return x+f(y)})
a.map(function(x){t+=f(x)},t=0)
Note that this doesn't work quite as well with ES6, although it's still a little shorter:
a.reduce((x,y)=>x+f(y))
a.map(x=>t+=f(x),t=0)
Note: in all of the .map versions, you will need to call t afterwards to get the actual value.
-
\$\begingroup\$ Can you apply the same logic for ES6? \$\endgroup\$Sunny Patel– Sunny Patel2016年08月23日 19:57:09 +00:00Commented Aug 23, 2016 at 19:57
-
\$\begingroup\$ @SunnyPatel Yep, although it doesn't work out quite as well. \$\endgroup\$ETHproductions– ETHproductions2016年11月22日 15:53:42 +00:00Commented Nov 22, 2016 at 15:53
Something worth noting is that you can use a string in place of zero in some instances to save a couple of bytes here and there in loops:
s='';for(i=0;i++<9;)s+=i
for(i=s='';i++<9;)s+=i
// s="123456789", i=10
-
1\$\begingroup\$ I tried ""++ in the console earlier wondering if it would work, of course it has to be in a variable first. Thanks! \$\endgroup\$Vartan– Vartan2015年07月30日 21:00:34 +00:00Commented Jul 30, 2015 at 21:00
How to compare a number with help of how numbers turn into booleans:
If you are going to check if something is equal to a positive number, you can subtract that amount and reverse what was inside the if and else blocks:
//simplified examples:
x==3?"y":"n"; <- 13 Chars
x-3?"n":"y"; <- 12 Chars
//expanded examples:
if(x==3){
yes();
}else{
no();
}
if(x-3){
no();
}else{
yes();
}
And in case you are wanting to compare with a negative number (*different than -1), you just simply need to add this number instead of subtracting.
*well, you can surely use x.indexOf(y) + 1, but in the special case of -1 you have the opportunity to use ~x.indexOf(y) instead.
In cases where you are using the ternary operator to chose between two numbers, and the conditional is either a boolean or number 1 or 0, you can do math operations instead:
(x ? num1 : num2) conclusions:
1)if num1 equals num2, there ARE savings
2)if num1 is (+1) or (-1) than num2, there ARE savings
3)if either num1 or num2 equals to 0, there ARE savings
4)it is MORE LIKELY to find greater savings on num1>num2 instead of num1<num2
5)in method (*A) and (*B), savings are NOT GUARANTEED
a)num1>num2
i)(num1==(num2+1))
ex1: (x?5:4) to (x+4)
ex2: (x?8:7) to (x+7)
ii)num2==0
ex1: (x?3:0) to (x*3)
ex2: (x?7:0) to (x*7)
iii)
(*A) or (*B) //one might be shorter
b)num1<num2
i)((num1+1)==num2)
ex1: (x?4:5) to (5-x)
ex2: (x?7:8) to (8-x)
ii)num1==0
ex1: (x?0:3) to (!x*3)
ex2: (x?0:7) to (!x*7)
iii)
(*A) or (*B) //one might be shorter
c)num1==num2
i)
ex1: (x?5:5) to (5)
ex2: (x?-3:-3) to (-3)
(*A) use ((x*(num1-num2))+num2)
ex1: (x?8:4) to ((x*4)+4)
ex2: (x?4:8) to ((x*-4)+8)
ex3: (x?6:-4) to ((x*10)-4)
ex4: (x?-4:6) to ((x*-10)+6)
ex5: (x?4:-6) to ((x*10)-6)
ex6: (x?-6:4) to ((x*-10)+4)
ex7: (x?-5:-9) to ((x*4)-9)
ex8: (x?-9:-5) to ((x*-4)-5)
(*B) use ((!x*(num2-num1))+num1)
ex1: (x?8:4) to ((!x*-4)+8)
ex2: (x?4:8) to ((!x*4)+4)
ex3: (x?6:-4) to ((!x*-10)+6)
ex4: (x?-4:6) to ((!x*10)-4))
ex5: (x?4:-6) to ((!x*-10)+4)
ex6: (x?-6:4) to ((!x*10)-6)
ex7: (x?-5:-9) to ((!x*-4)-5)
ex8: (x?-9:-5) to ((!x*4)-9)
Note: In addition to this, you will need to remove the unnecessary 0-, +0, +- etc.
Note2: there is an isolated case where (x) !== (x?1:0), as x must be typeof === "number" for it to work. However, in the case of (-x) it works just fine.
Note3: In case you don't find savings, simply use the former (x?y:z)
Previously I thought method B couldn't ever beat A, however exceptions do exist:
(x?97:100) //original
(-3*x+100)
(3*!x+97)
I created a github project that makes the simplification for us (jsFiddle demo)
-
\$\begingroup\$ @ajax333221
void 0(it isn't a function, but a keyword) is not a value, it simply returnsundefined. \$\endgroup\$Camilo Martin– Camilo Martin2012年12月18日 12:07:19 +00:00Commented Dec 18, 2012 at 12:07 -
\$\begingroup\$ @CamiloMartin you are right, also I now see the point in this answer, however
amust be either 1 or 0 for it to work \$\endgroup\$ajax333221– ajax3332212012年12月18日 16:30:23 +00:00Commented Dec 18, 2012 at 16:30 -
\$\begingroup\$ @ajax333221 Yes, actually the funny thing about code golfing to me is that most of the best tricks only work for that particular thing you're doing, and one feels so clever to find one of these corner cases with corner solutions :D By the way, you don't have to delete comments... \$\endgroup\$Camilo Martin– Camilo Martin2012年12月19日 02:07:45 +00:00Commented Dec 19, 2012 at 2:07
Instead of writing true you can use !0.
-
6\$\begingroup\$ Likewise,
!1forfalse. \$\endgroup\$James M. Lay– James M. Lay2015年01月17日 17:46:29 +00:00Commented Jan 17, 2015 at 17:46 -
21\$\begingroup\$ Better yet, use
1fortrueand0forfalse, unless you really need the literal values. \$\endgroup\$ETHproductions– ETHproductions2016年12月13日 18:24:46 +00:00Commented Dec 13, 2016 at 18:24
Transforming to a Boolean:
if(b){b=true}else{b=false}
b=b?true:false;
b=b?!0:!1;
b=!!b;
Note: This changes 0, "",false, null, undefined and NaN to false (everything else to true)
-
\$\begingroup\$ it also changes the DOM method
document.alltofalsebut that isn't really relevant to code golf, lol \$\endgroup\$noodle person– noodle person2023年05月20日 13:50:14 +00:00Commented May 20, 2023 at 13:50
var)? And should JavaScript golf code be a function or output something directly? I honestly think this can make much difference. \$\endgroup\$(class{static #x = 1;get #y(){};set #y(z){}})can be rewritten as(class{static#x = 1;get#y(){};set#y(z){}}). This makes for some nice obfuscation, too, but I can’t think of a practical example in code golf. \$\endgroup\$