JavaScript에서 골프를 치기위한 일반적인 팁은 무엇입니까? JavaScript와 관련이있는 코드 골프 문제에 일반적으로 적용 할 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).
참고 : ECMAScript 6 이상의 골프 팁 도 참조하십시오 .
JavaScript에서 골프를 치기위한 일반적인 팁은 무엇입니까? JavaScript와 관련이있는 코드 골프 문제에 일반적으로 적용 할 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).
참고 : ECMAScript 6 이상의 골프 팁 도 참조하십시오 .
답변:
비표준 방식으로 표준 for 루프를 사용할 수 있습니다
for ( a; b; c )
본질적으로 다음과 같습니다.
a;
while ( b )
{
...
c;
}
따라서 좋은 방법은 while
루프로 코드를 작성한 다음 루프의 a,b,c
일부로 코드 를 분할하는 것 for
입니다.
내가 쓴 몇 가지 예 :
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);
여러 값을 초기화하거나 재설정하는 경우 값을 필요한 모든 변수에 연결하십시오.
a=b=1;
유형을 확인하지 말고 그대로 사용하십시오. parseInt()
비용 10
문자. 끈에서 캐스트해야하는 경우 창의력을 발휘하십시오.
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;
JavaScript에는 자동 세미콜론 삽입이 있습니다. 자주 사용하십시오.
가능한 한 줄이나 매개 변수로 밀어 넣어 괄호를 절약하십시오.
a( realParam1, realParam2, fizz='buzz' )
a = a - 1;
foo(a);
과
foo(a);
a = a - 1;
쉽게 다시 쓸 수 있습니다
foo(--a);
과
foo(a--);
각기.
this
또는 self
대신 사용window
자기 설명 2 문자 절약.
이것은 속성 이름 길이와 액세스 횟수 간의 균형을 맞추는 행위입니다. a.longFunctionName()
점 표기법으로 두 번 호출 하는 대신 이름을 저장하고 대괄호 표기법으로 함수를 호출하는 것이 더 짧습니다.
a.longFunctionName(b)
a.longFunctionName(c)
//42
-vs-
a[f='longFunctionName'](b)
a[f](c)
//34
이것은 document.getElementById
로 줄일 수있는 기능에 특히 효과적입니다 d[e]
.
노트 :
대괄호 표기법으로 비용은 6 + name.length
처음 문자입니다. 각 후속 액세스에는 3
문자 비용이 있습니다.
점 표기법의 경우 모든 액세스 비용 name.length + 1
은 .
문자 (+1 )입니다.
이 경우이 방법을 사용하십시오 6 + name.length + (3 * (accesses - 1)) < accesses * (name.length + 1)
.
len = 속성 이름 길이
i = 활용하기위한 최소 액세스
len | i
========
1 | ∞
2 | ∞
3 | 7
4 | 4
5 | 3
6 | 3
7 | 3
8+ | 2
액세스 수는 여러 개체에 걸쳐있을 수도 있습니다. .length
다른 배열에서 4 번 이상 액세스 하면 string을 보유한 동일한 변수를 사용할 수 있습니다 'length'
.
c = ~~a-~~b
이어야합니다 c = ~~a+~~b
. 또한, 암시 적으로 사용하여 정수로 캐스트 할 수 있습니다 |0
예를 들어, Math.random()*6|0
.
a
및 b
문자열 인 경우 +a+b
숫자로 변환하여 추가 할 수 있습니다.
d- -b
언젠가는 내 코드에 ...
a.f=a.longfunctionname;a.f(b);a.f(c);a.f(d)
"alpha,bravo,charlie".split(",") // before
"alpha0bravo0charlie".split(0) // after
.split`...`
"alpha,bravo,charlie".split`,`
임의의 부울 ( 0
또는 1
) 이 필요한 경우 :
new Date&1 // equivalent to Math.random()<0.5
임의의 정수가 필요한 경우 0 <= n < 1337
:
new Date%1337 // equivalent to Math.floor(Math.random()*1337))
이것은 Date
에포크 이후 밀리 초의 양으로 JavaScript에 내부적으로 저장되어 있기 때문에 작동하므로 정수 수학을 시도 할 때 new Date
강제로 진행 123somebignumber456
됩니다.
물론,이 "무작위"숫자는 실제로 임의적이지 않습니다. 특히 연속해서 여러 번 연속해서 호출하는 경우 명심하십시오.
키워드 사용을 피하기 위해 객체 리터럴 형태의 get / set을 사용할 수 있습니다 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)
이것은 덜 알려지고 덜 사용되지만 올바른 상황에서 사용하면 인상적 일 수 있습니다. 인수를 취하지 않고 호출 될 때 항상 다른 숫자를 반환하는 함수를 고려하면 반환 된 숫자가 계산에 사용됩니다.
var a = [
Math.random()*12|0,
Math.random()*11|0,
Math.random()*10|0,
/* etc... */
];
일반적으로 단일 문자 변수 이름을 사용하여이 기능을 단축 할 수 있습니다.
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];
길이를 줄이는 더 좋은 방법은 abusing valueOf
을 사용하여 호출 당 2자를 절약 할 수 있습니다. 함수를 5 번 이상 호출하면 유용합니다.
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];
let a=[5,6,7,8,9,10,11,12].map(x=>x*Math.random()|0)
또는 let a=Array(7).map((_,i)=>i*Math.random()|0+5)
36 또는 42 바이트가 각각 저장됩니다.
r()
하거나 더 짧게 만들 수 있습니까?
r={valueOf:Math.random}
그것은 천재입니다. : D
긴 if
문장이나 삼항 연산자를 사용하는 대신 코드를 사용 &&
하고 ||
단축 할 수 있습니다. 예를 들어 :
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
될 수있다
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
||
연산자는 종종 기본값을 설정하기위한 이러한 방법으로 사용된다 :
evt = evt || window.event;
이것은 글쓰기와 같습니다
if (!evt)
evt = window.event;
특정 문자의 긴 문자열을 초기화하려면 길이가 n + 1 인 배열을 작성하면됩니다 . 여기서 n 은 문자를 반복하려는 횟수입니다.
// Create a string with 30 spaces
str = " ";
// or
str = Array(31).join(" ");
줄이 클수록 절약 효과도 커집니다.
사용 +
하고 ~
대신 운영자 parseFloat()
또는 parseInt()
인 문자열 유형 병합 할 때 단지 숫자 숫자 유형을 :
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()
하지만주의하십시오, 다른 유형 (예를 들어, 이러한 연산자와 합체 할 수있다 true
될 것 1
빈 문자열 또는 문자열이 그냥 흰색 공간이 될 것 포함) 0
. 그러나 특정 상황에서는 유용 할 수 있습니다.
str.repeat(count)
사용자 입력을 얻기 위해 prompt () 호출로 변수 초기화 몰래
n=prompt(i=5); // sets i=5 at the same time as getting user input
사용하는 대신
n=prompt();i=5;
부작용으로 1 문자를 저장하는 동안 프롬프트 창에 입력 값을 표시합니다.
[1,2,3].join('',i=5)
중괄호 쌍을 저장하는 경우 와 같이 유용 할 수 있습니다 .
i=5,[1,2,3].join()
.
중첩 된 for 루프를 결합하십시오.
// before:
for(i=5;i--;)for(j=5;j--;)dosomething(i,j)
// after:
for(i=25;i--;)dosomething(0|i/5,i%5)
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)
i*j
상기 분할 / 모듈러스 연산자의 개별 값을 검색 i
하고 j
.
유니 코드 단축키
큰 골프 도전에서 빌트인 속성의 지옥을 사용하는 경우 모든 속성의 별칭을 한 문자로 지정할 수 있습니다.
[Math,Number,S=String,Array].map(b=>
Object.getOwnPropertyNames(b).map((p,i)=>
b.prototype[S.fromCharCode(i+248)]=b[p]
)
)
위의 코드를 실행하면 다음과 같이 사용할 수 있습니다.
"foo".Č(/.*/,'bar') // replaces foo with bar
이 비용은 118 바이트이므로 특정 상황에서는 유용하지 않을 수 있습니다.
브라우저에 따라 다를 수 있으며 with(Array){join(foo),...}
변수가 사용 속성으로 짧 거나 정의되어 있는지 확실하지 with(Array){j=join,m=map...}
않지만 여전히 언급 할 가치가 있습니다.
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
Math
이 없기 때문에 실제로 작동 하지 않습니다 .prototype
. 그러나을 제거 Math
하면이를 1 바이트 문자에 할당하는 114 바이트 스 니펫으로 골프를 쳤습니다. 여기에서 찾을 수 있습니다 .
À
- ÿ
여전히 (JS 지원)을 ISO-8859-1 인코딩 각각 1 바이트이다. Firefox 50에서는 불행히도이 .localeCompare
방법을 사용 ×
하지만 일반적으로 문제가되지는 않습니다. 출처
while
루프를 루프로 변환하는 for
것은 종종 동일합니다.
while(i--);
for(;i--;);
그러나 두 번째 형식은 변수 초기화를 결합 할 수 있습니다.
i=10;while(i--);
for(i=10;i--;);
두 번째 형식은 첫 번째 형식보다 한 문자가 짧습니다.
당신이 변수를 초기화하는 경우 1
처럼, (내부 루프에 대한 외부 루프에서 변수를 재설정, 예를 들어) 루프의 모든 반복에 (에서 다음과 같은 내 대답이 질문에 ) :
for(j=n-2;p=1,j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^
조건의 결과 j++<=n
는 1
항상 참이므로 조건을 변수에 직접 할당 할 수 있습니다 (거짓이되면 루프 실행이 중지되고 더 이상 문제가되지 않음).
for(j=n-2;p=j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^^^^^
이 방법을 사용하면 일반적으로 2자를 저장할 수 있습니다 . @ugoren
해당 답변에 대한 의견의 아이디어를 존중합니다 .
또 다른 예를 들어, 외부 for 루프 의 표현식 으로 여기 에이 트릭을 적용 w=r=++c<S.length
하여 총 4자를 절약했습니다.
Spidermonkey (현재) 특정 스크립트를 승인 할 수있는 경우 ECMAScript 6 화살표 기능을 사용할 수 있습니다 . 다음과 같은 코드를 작성하는 대신.
a.map(function(x){return x*2}) // function? return?
이렇게 짧게 만들 수 있습니다.
a.map(x=>x*2)
당신은 사용하지 않는, NaN를 확인해야하는 경우 isNaN(x)
만 사용 x!=x
짧고도 작동합니다.
if(isNaN(x)){
if(x!=x){
이 경우에만 작동합니다 typeof(x) === "number"
. 예를 들어 문자열이면을 isNaN("string")
반환 true
하지만을 "string" != "string"
반환합니다 false
. 이것을 지적 해준 Cyoce에게 감사드립니다!
isNaN("string")
returns true
, 반면에 "string"!="string"
returns false
(명백하게)
if(!x){
감지하는 경우 에도 갈 수 있습니다 NaN
.
x
number (으)로 캐스팅하면와 +x!=+x
같지만 isNaN(x)
여전히 2 자 더 짧습니다. 그런 다음 +"string"!=+"string"
true를 반환합니다.
비트 연산을 사용하여 숫자를 0으로 반올림하십시오.
// do this
T=Math.random()*6+1|0
// or do this
T=~~(Math.random()*6+1)
(출처 : 랜덤 주사위 팁 )
연산자 우선 순위 에 따라 프로그램에서 더 짧은 것이 결정됩니다.
n=prompt()|0
.
Math.floor
느립니다. 거의 사용해서는 안됩니다.
루핑 팁 I
마지막으로 사용한 시간 1
을 변경하여 루핑 할 때 문자 를 저장할 수 있습니다 i
.
//not so god
for(i=0;i<3;i++){
alert(i);
}
//best
for(i=0;i<3;){
alert(i++);
}
참고 :--
너무 작동 하지만 무한 반복을 피하려면 루프를 적절히 수정하십시오.
루핑 팁 II
증분 연산자와 값으로 재생하여 하나의 문자를 저장할 수있는 특정 시나리오가 있습니다.
for(i=0;i++<9;)
for(i=0;++i<10;)
참고 : 예를 들어주의를 기울여야 0 to -1
합니다. 그리고 9 to 10, 99 to 100
, 그래서 주위까지 재생 문자를 저장하는 방법을 찾아
^
대신 !=
또는 ==
정수와 비교할 때 사용//x!=3?a:b
x^3?a:b
//x==3?a:b
x^3?b:a
//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
-
대신 간단하게 사용할 수 있습니다 !=
. 예를 들어 n!=1?a:b
다음과 같습니다.n-1?a:b
대안 Math.floor()
이 게시 된 것을 알고 있지만 다른 것은 어떻습니까?
Math.floor(x) //before
0|x //after
Math.round(x) //before
0|x+.5 //after
Math.ceil(x) //before
x%1?-~x:x //after - credits to @Tomas Langkaas
0|x+1
당신의 천장을 발견 할 수는 이미 정수의 경우 단순히 1을 추가합니다. (대부분의) 안전한 대안은 0|x+1-1e9
이지만 이것은 3 바이트 더 짧습니다.
0|x+1-1e-9
인가요?
x%1?-~x:x
(9 자)가 더 나은 대안입니다. 그러나 바닥재 대안 0|x
및과 마찬가지로 ~~x
양수에만 적용됩니다.
삼항 연산자를 사용하여 두 숫자 중에서 선택 하고 조건이 부울 또는 숫자 인 1 or 0
경우 대신 수학 연산을 수행 할 수 있습니다.
(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)
참고 : 이 외에도, 당신은 불필요한 제거해야합니다 0-
, +0
, +-
등
주 2 : 고립 된 경우가 있습니다 (x) !== (x?1:0)
로는, x
해야 typeof === "number"
작동하는. 그러나이 경우에는 (-x)
잘 작동합니다.
참고 3 : 저축을 찾을 수없는 경우 단순히 전자를 사용하십시오(x?y:z)
이전에는 메소드 B가 A를 이길 수 없다고 생각했지만 예외는 있습니다.
(x?97:100) //original
(-3*x+100)
(3*!x+97)
우리를 위해 단순화 시키는 github 프로젝트 를 만들었습니다 ( jsFiddle demo )
void 0
(함수는 아니지만 키워드)은 값이 아니며 단순히를 반환합니다 undefined
.
a
작동하는 1 또는 0 중 하나를해야합니다
tl; dr : ES6 기능을 사용하십시오!
문서 : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/arrow_functions
예 :
s = x => x*x
// s = function (x) {
// return x * x;
// }
숫자가 부울로 바뀌는 방법을 사용하여 숫자를 비교하는 방법 :
무언가가 양수 인지 확인하려면 해당 양을 빼고 if
and else
블록 내부의 내용을 되돌릴 수 있습니다 .
//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();
}
그리고 음수 (*와 다른 -1
) 를 비교 하려면 빼기 대신이 숫자 를 추가 하면됩니다.
* 글쎄, 당신은 반드시 사용할 수 x.indexOf(y) + 1
있지만 특별한 경우에는 대신 -1
사용할 수 있습니다 ~x.indexOf(y)
.
Mozilla의 비표준 "표현식 폐쇄"기능을 사용하여 SpiderMonkey / Firefox 또는 Rhino 엔진에서만 작동하는 스크립트에 많은 문자를 저장하십시오. 예를 들어
function foo(){return bar}
된다
function foo()bar
더 많은 트릭에 대해서는 스택 오버플로 페이지 를 참조하십시오 .
->bar
let foo = () => bar;
위의 골프 코드보다 짧습니다.
foo=_=>bar
더 짧습니다.
쓰지 않고 true
사용할 수 있습니다 !0
.
!1
대한 false
.
1
for true
및 0
for를 사용 하는 것이 더 false
좋습니다.
부울로 변환 :
if(b){b=true}else{b=false}
b=b?true:false;
b=b?!0:!1;
b=!!b;
참고 : 이 변경 0
, ""
, false
, null
, undefined
과 NaN
에 false
(로 다른 모든 것들 true
)
var
) 에 변수를 넣을 수 있습니까? 그리고 JavaScript 골프 코드는 함수이거나 직접 출력해야합니까? 솔직히 이것이 큰 차이를 만들 수 있다고 생각합니다.