이것은 다른 “<…>에서의 골프 팁”과 유사하지만 특히 ECMAScript 6 이상에서 제공되는 JavaScript의 새로운 기능을 대상으로합니다.
JavaScript는 본질적으로 매우 장황한 언어입니다. function(){}
, .forEach()
문자열을 배열로 변환, 배열 같은 객체를 배열로 변환하는 등은 부풀려서 골프에 적합하지 않습니다.
반면 ES6 +에는 매우 편리한 기능과 설치 공간이 줄었습니다. x=>y
, [...x]
, 등 그냥 예 중 일부입니다.
코드에서 여분의 몇 바이트를 제거하는 데 도움이되는 몇 가지 유용한 트릭을 게시하십시오.
참고 : ES5에 대한 트릭 은 JavaScript의 골프 팁 에서 이미 사용 가능합니다 . 이 스레드에 대한 답변은 ES6 및 기타 향후 ES 버전에서만 사용 가능한 트릭에 중점을 두어야합니다.
그러나이 스레드는 현재 ES5 기능을 사용하여 골프를 타는 사용자를위한 것입니다. 답변에는 ES6 기능을 이해하고 자신의 ES5 코딩 스타일에 매핑하는 데 도움이되는 팁도 포함될 수 있습니다.
답변
스프레드 연산자 ...
스프레드 연산자는 배열 값을 쉼표로 구분 된 목록으로 변환합니다.
사용 사례 1 :
함수가 목록을 기대하는 배열을 직접 사용하십시오.
list=[1,2,3]
x=Math.min(...list)
list=[10,20], a.push(...list) // similar to concat()
사용 사례 2 :
iterable (일반적으로 문자열)에서 배열 리터럴을 만듭니다.
[...'buzzfizz'] // -> same as .split('')
사용 사례 3 :
함수에 대한 가변 개수의 인수를 선언
F=(...x) => x.map(v => v+1)
// example: F(1,2,3) == [2,3,4]
답변
내가 가입 한 이후로 트릭을 배웠다
내 주요 프로그래밍 언어는 JS이며 대부분 ES6입니다. 일주일 전이 사이트에 가입 한 이후, 동료 회원들로부터 많은 유용한 트릭을 배웠습니다. 나는 여기에 그 중 일부를 결합하고 있습니다. 커뮤니티에 대한 모든 크레딧.
화살표 함수 및 루프
우리는 화살표 기능이 많은 바이트를 절약한다는 것을 알고 있습니다.
function A(){do something} // from this
A=a=>do something // to this
하지만 몇 가지를 명심해야합니다
- 사용 클럽 여러 제표에 대한 시도
,
즉,(a=b,a.map(d))
반환되는 값이 마지막 표현이다, 여기에서 –a.map(d)
- 귀하의 경우
do something
부분은 하나 이상의 문입니다, 당신은 주변에 추가해야{}
브래킷. {}
대괄호 가 있으면 명시적인 return 문을 추가해야합니다.
위의 내용은 루프가 관련된 많은 경우에 적용됩니다. 그래서 같은 :
u=n=>{for(s=[,1,1],r=[i=1,l=2];c=l<n;i+=!c?s[r[l++]=i]=1:1)for(j of r)c-=j<i/2&s[i-j];return n>1?r:[1]}
여기에서 반환으로 인해 9 자 이상을 낭비하고 있습니다. 이것은 최적화 될 수 있습니다.
- for 루프를 피하십시오. 사용
.map
하거나.every
또는.some
대신. 매핑하는 것과 동일한 어레이를 변경하려는 경우 실패합니다. - 루프를 폐쇄 화살표 함수로 감싸서 기본 화살표 함수를 단일 명령문으로 변환하십시오.
위의 내용은 다음과 같습니다.
u=n=>(s=>{for(r=[i=1,l=2];c=l<n;i+=!c?s[r[l++]=i]=1:1)for(j of r)c-=j<i/2&s[i-j]})([,1,1])|n>1?r:[1]
제거 된 문자 : {}return
추가 된 문자 : (){}>|
변수를 올바르게 채우는 클로저 메소드를 호출 n
한 다음 클로저 메소드가 아무것도 리턴하지 않기 때문에 (즉, 리턴 undefined
), 비트 단위 또는 n
외부 화살표 함수의 단일 명령문으로 배열을 모두 리턴합니다.u
쉼표와 세미콜론
지금까지의 것을 피하십시오.
루프에서 변수를 선언하거나 이전 섹션에서 언급 한 것과 같이 ,
분리 된 명령문을 사용하여 단일 명령문 화살표 기능을 사용하는 경우,이를 피 ,
하거나 ;
마지막 몇 바이트를 제거 하기 위해 약간의 멋진 트릭을 사용할 수 있습니다 .
이 코드를 고려하십시오.
r=v=>Math.random()*100|0;n=r();m=r();D=v=>A(n-x)+A(m-y);d=0;do{g();l=d;d=D();....
여기서는 많은 변수를 초기화하기 위해 많은 메소드를 호출하고 있습니다. 각 초기화는 ,
또는을 사용하고 ;
있습니다. 이것은 다음과 같이 다시 작성할 수 있습니다.
r=v=>Math.random()*100|0;n=r(m=r(d=0));D=v=>A(n-x)+A(m-y);do{d=D(l=d,g());....
메소드가 전달 된 변수를 방해하지 않는다는 사실을 사용하고 그 사실을 사용하여 3 바이트를 면도하는 방법에 주목하십시오.
기타
.search
대신에 .indexOf
둘 다 동일한 결과를 제공하지만 search
더 짧습니다. 검색에는 정규 표현식이 필요하지만 현명하게 사용하십시오.
특정 조건에 따라 하나 이상의 스트링 부품을 연결해야 할 때 매우 유용합니다.
JS에서 quine을 출력하려면 다음 예제를 사용하십시오.
(f=x=>alert("(f="+f+")()"))()
vs.
(f=x=>alert(`(f=${f})()`))()
두 개의 큰 따옴표 (`) 안에있는 문자열 인 템플릿 문자열에서 a 안에있는 모든 것을 ${ }
코드로 취급하고 결과 답변을 문자열에 삽입합니다.
나중에 몇 가지 요령을 게시하겠습니다. 행복한 골프!
답변
속성 속기 사용
속기 속성을 사용하면 변수를 배열 값으로 설정할 수 있습니다.
a=r[0];b=r[1] // ES5
[a,b]=r // ES6 - 6 bytes saved
이것은 또한 다음과 같이 사용될 수 있습니다 :
a=r[0],b=r[2] // ES5
[a,,b]=r // ES6 - 5 bytes saved
이것을 사용하여 변수를 뒤집을 수도 있습니다.
c=a,a=b,b=c // ES5 - uses extra variable
[b,a]=[a,b] // ES6 - not shorter, but more flexible
이 slice()
기능을 사용하여 기능 을 단축 할 수도 있습니다 .
z = [1, 2, 3, 4, 5];
a=z.slice(1) // a = [2,3,4,5]; ES5
[,...a]=z // a = [2,3,4,5]; ES6
기본 전환
ES6은 Base-2 (이진) 및 Base-8 (8 진수) 형식을 10 진수로 변환하는 훨씬 짧은 방법을 제공합니다.
0b111110111 // == 503
0o767 // == 503
+
이진수, 8 진수 또는 16 진수 문자열을 10 진수로 변환하는 데 사용할 수 있습니다. 당신은 사용할 수 있습니다 0b
, 0o
그리고 0x
각각 진수, 8 진수와 진수를 들면 :
parseInt(v,2) // ES5
+('0b'+v) // ES6 - 4 bytes saved; use '0o' for octal and '0x' for hex
'0b'+v-0 // Shorter, but may not work in all cases
// You can adapt this your case for better results
이> 7 번을 사용하는 경우 사용 parseInt
하고 이름을 바꾸는 것이 더 짧 습니다.
(p=parseInt)(v,2)
이제에 p
사용할 수있어 parseInt
장기적으로 많은 바이트를 절약 할 수 있습니다 .
답변
함수와 함께 문자열 템플릿 사용
하나의 문자열을 인수로 사용하는 함수가있는 경우 ()
식이없는 경우를 생략 할 수 있습니다 .
join`` // Works
join`foobar` // Works
join`${5}` // Doesn't work
답변
배열 이해 (Firefox 30-57)
참고 : 배열 이해는 표준화되지 않았으며 Firefox 58에서는 더 이상 사용되지 않습니다.
원래 ECMAScript 7 사양에는 여러 가지 새로운 배열 기반 기능이 포함되었습니다. 이들의 대부분이 확정 버전으로하지 않았지만, 파이어 폭스 지원 (ED)이 기능의 가능성이 가장 큰 : 대체 할 수있는 멋진 새 구문 .filter
과 .map
와 for(a of b)
구문. 예를 들면 다음과 같습니다.
b.filter(a=>/\s/.test(a)).map(a=>a.length)
[for(a of b)if(/\s/.test(a))a.length]
보시다시피, 두 줄은 부피가 큰 키워드와 화살표 기능을 포함하지 않는 두 번째 줄 외에 다른 것이 아닙니다. 그러나 이것은 주문만을 설명한다 .filter().map()
. .map().filter()
대신에 어떻게됩니까 ? 실제로 상황에 따라 다릅니다.
b.map(a=>a[0]).filter(a=>a<'['&&a>'@')
[for(a of b)if(a<'['&&a>'@')a[0]]
b.map(a=>c.indexOf(a)).filter(a=>a>-1)
[for(a of b)if((d=c.indexOf(a))>-1)d]
b.map(a=>a.toString(2)).filter(a=>/01/.test(a))
[for(a of b)if(/01/.test(c=a.toString(2)))c]
또는 당신이 무엇을 원하는 경우 중 하나 .map
또는 .filter
? 글쎄, 그것은 일반적으로 덜 OK로 나타납니다.
b.map(a=>a.toString(2))
[for(a of b)a.toString(2)]
b.filter(a=>a%3&&a%5)
[for(a of b)if(a%3&&a%5)a]
따라서 제 충고는 일반적으로 .map
and를 사용하는 곳마다 배열 이해를 사용하는 .filter
것이지만 둘 중 하나만 사용하는 것이 아닙니다.
문자열 이해
ES7 이해에 대한 좋은 점은 .map
and와 같은 배열 별 함수와 달리 배열 뿐만 아니라 반복 가능한 객체 에서도.filter
사용할 수 있다는 것 입니다. 문자열을 다룰 때 특히 유용합니다. 예를 들어 문자열을 통해 각 문자를 실행하려면 다음을 수행하십시오 .c
c.charCodeAt()
x=>[...x].map(c=>c.charCodeAt())
x=>[for(c of x)c.charCodeAt()]
그것은 상당히 작은 규모로 절약 된 2 바이트입니다. 문자열에서 특정 문자를 필터링하려면 어떻게해야합니까? 예를 들어, 이것은 대문자 만 유지합니다 :
x=>[...x].filter(c=>c<'['&&c>'@')
x=>[for(c of x)if(c<'['&&c>'@')c]
흠, 그것은 더 짧지 않습니다. 그러나 우리가 두 가지를 결합하면 :
x=>[...x].filter(c=>c<'['&&c>'@').map(c=>c.charCodeAt())
x=>[for(c of x)if(c<'['&&c>'@')c.charCodeAt()]
와우, 전체 10 바이트가 절약되었습니다!
문자열 이해의 또 다른 장점은 하드 코딩 된 문자열이 추가 바이트를 절약한다는 것입니다 of
.
x=>[...'[](){}<>'].map(c=>x.split(c).length-1)
x=>[for(c of'[](){}<>')x.split(c).length-1]
x=>[...'[](){}<>'].filter(c=>x.split(c).length>3)
x=>[for(c of'[](){}<>')if(x.split(c).length>3)c]
인덱싱
배열 이해는 문자열 / 배열에서 현재 색인을 얻는 것이 조금 더 어려워 지지만 수행 할 수 있습니다.
a.map((x,i)=>x+i).filter ((x,i)=>~i%2)
[for(x of(i=0,a))if(++i%2)x+i-1]
주의해야 할 것은 조건이 충족 될 때뿐만 아니라 매번 인덱스가 증가 하도록하는 것입니다.
발전기 이해
생성기 이해는 기본적으로 배열 이해와 동일한 구문을 갖습니다. 괄호를 괄호로 바꾸십시오.
x=>(for(c of x)if(c<'['&&c>'@')c.charCodeAt())
이것은 배열과 거의 같은 방식으로 작동 하는 생성기 를 생성 하지만 다른 대답에 대한 이야기입니다.
요약
기본적으로 이해력은 일반적으로보다 짧지 만 .map().filter()
상황의 세부 사항에 따라 결정됩니다. 두 가지 방법으로 시도하고 어느 것이 더 잘 작동하는지 확인하는 것이 가장 좋습니다.
추신 : 다른 이해 관련 팁이나이 답변을 향상시킬 수있는 방법을 제안하십시오!
답변
ES6의 함수 표현식은 화살표 표기법을 사용하며 ES5 버전과 비교할 때 바이트를 많이 절약하는 데 도움이됩니다.
f=function(x,y){return x+y}
f=(x,y)=>x+y
함수에 하나의 매개 변수 만있는 경우 괄호를 생략하여 2 바이트를 저장할 수 있습니다.
f=x=>x+1
함수에 매개 변수가 없다면 1 바이트를 저장하는 것처럼 선언하십시오.
f=()=>"something"
f=x=>"something"
주의 : 화살표 기능은 정확히 동일하지 않습니다 function () {}
. 규칙 this
이 다릅니다 (더 나은 IMO). 문서 보기
답변
eval
여러 명령문과 함께 화살표 함수에 사용return
내가 우연히 발견 한 더 우스운 트릭 중 하나 …
여러 개의 문과을 필요로하는 간단한 화살표 함수를 상상해보십시오 return
.
a=>{for(o="",i=0;i<a;i++)o+=i;return o}
에있는 a
모든 정수를 반복 하는 단일 매개 변수를 허용하는 간단한 함수 [0, a)
로, 출력 문자열의 끝 부분에 o
이를 반환합니다. 예를 들어,이를 4
매개 변수로 사용하여 호출하면 yield가 0123
됩니다.
이 화살표 함수는 중괄호로 묶어야 하고 끝에 {}
있어야합니다 return o
.
이 첫 번째 시도의 무게는 39 바이트 입니다.
나쁘지는 않지만을 사용 eval
하면이를 개선 할 수 있습니다.
a=>eval('for(o="",i=0;i<a;i++)o+=i;o')
이 함수는 코드를 래핑 eval
하여 eval
평가 에서 마지막 명령문을 작성 하여 중괄호와 return 문을 제거 했습니다 o
. 이로 인해 eval
return o
이 리턴되고 o
, 이제는 단일 명령문이므로 함수가 리턴 됩니다.
이 개선 된 시도의 무게는 38 바이트 이며 원래 바이트는 1 바이트입니다.
그러나 더 많은 것이 있습니다! 평가 문은 마지막 계산서에 평가 된 내용을 반환합니다. 이 경우로 o+=i
평가 o
되므로 ;o
! (감사합니다, edc65!)
a=>eval('for(o="",i=0;i<a;i++)o+=i')
이 마지막 시도의 무게는 36 바이트에 불과 합니다. 원본보다 3 바이트가 절약되었습니다!
이 기술은 화살표 함수가 값을 반환하고 여러 명령문을 가질 필요가있는 일반적인 경우로 확장 될 수 있습니다 (다른 방법으로는 결합 할 수 없음)
b=>{statement1;statement2;return v}
된다
b=>eval('statement1;statement2;v')
바이트를 저장합니다.
로 statement2
평가되면 다음 v
과 같습니다.
b=>eval('statement1;statement2')
총 3 바이트를 절약합니다.