เคล็ดลับสำหรับการเล่นกอล์ฟใน ECMAScript 6 ขึ้นไป


88

สิ่งนี้คล้ายกับ "เคล็ดลับสำหรับการเล่นกอล์ฟใน <... >" อื่น ๆ แต่มีการกำหนดเป้าหมายเฉพาะคุณลักษณะใหม่ใน JavaScript ที่แสดงใน ECMAScript 6 ขึ้นไป

JavaScript โดยเนื้อแท้เป็นภาษาที่ละเอียดมากfunction(){}, .forEach()แปลงสตริงอาร์เรย์วัตถุอาร์เรย์เหมือนอาร์เรย์ ฯลฯ ฯลฯ มี bloats สุดและไม่ดีต่อสุขภาพกอล์ฟ

ในทางกลับกัน ES6 + มีคุณสมบัติที่มีประโยชน์บางอย่างและลดการปล่อยทิ้ง x=>y, [...x]ฯลฯ เป็นเพียงตัวอย่างบางส่วน

โปรดโพสต์เทคนิคดีๆที่สามารถช่วยลดจำนวนไบต์พิเศษเหล่านี้จากโค้ดของคุณ

หมายเหตุ: เคล็ดลับสำหรับ ES5 มีอยู่แล้วในTips for golfing in JavaScript ; คำตอบของหัวข้อนี้ควรมุ่งเน้นไปที่เทคนิคเฉพาะใน ES6 และรุ่น ES อื่น ๆ ในอนาคต

อย่างไรก็ตามเธรดนี้มีไว้สำหรับผู้ใช้ที่กำลังเล่นกอล์ฟโดยใช้คุณสมบัติ ES5 รู้รอบอาจมีเคล็ดลับที่จะช่วยให้พวกเขาเข้าใจและจับคู่ฟีเจอร์ ES6 กับสไตล์ของการเข้ารหัส ES5

คำตอบ:


42

ผู้ประกอบการแพร่กระจาย ...

ผู้ประกอบการแพร่กระจายแปลงค่าอาร์เรย์เป็นรายการคั่นด้วยเครื่องหมายจุลภาค

ใช้กรณีที่ 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]

ดูเอกสาร mozilla


3
ตอนนี้ฉันมีคะแนนโหวตที่นี่ เห็นได้ชัดว่ามีคนสังเกตเห็นบางสิ่งบางอย่างผิดปกติอย่างมากในเคล็ดลับนี้เป็นคนขี้อายเกินกว่าที่จะแสดงความคิดเห็นและอธิบายสิ่งที่ ...
edc65

มันดูไม่เป็นไร บางทีมันอาจจะขาดอัฒภาค? ;) (btw คุณยังสามารถใช้เป็นพารามิเตอร์ที่เหลือได้เช่น
splats

คุณสามารถเพิ่มว่ามันยังมีกรณีการใช้งานฟังก์ชั่นในลายเซ็น :)
เฟลิกซ์ Dombek

Misclick ไม่ได้หมายถึง downvote
Stan Strum

@StrumStrum มันเกิดขึ้น ฉันจะอัปเดตเล็ก ๆ ของโพสต์นี้เพื่อให้คุณสามารถเปลี่ยนการโหวตของคุณ (หรือคุณทำไปแล้ว)
edc65

21

เคล็ดลับเรียนรู้ที่นี่ตั้งแต่ฉันเข้าร่วม

ภาษาโปรแกรมหลักของฉันคือ JS และ ES6 ส่วนใหญ่ เมื่อฉันกลับมาที่ไซต์นี้เมื่อสัปดาห์ที่แล้วฉันได้เรียนรู้เทคนิคที่มีประโยชน์มากมายจากเพื่อนสมาชิก ฉันรวมบางส่วนของที่นี่ เครดิตทั้งหมดให้กับชุมชน

ฟังก์ชั่นลูกศรและลูป

เราทุกคนรู้ว่าฟังก์ชั่นลูกศรช่วยประหยัดเวลาได้มากมาย

function A(){do something} // from this
A=a=>do something // to this

แต่คุณต้องจำไว้เล็กน้อย

  • ลองคลับหลายงบโดยใช้,ie (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 ตัวอักษรเนื่องจากการกลับมา สิ่งนี้สามารถปรับให้เหมาะสม

  • พยายามหลีกเลี่ยงการวนซ้ำ ใช้.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สั้นกว่า แม้ว่าการค้นหาจะคาดหวังนิพจน์ปกติดังนั้นให้ใช้อย่างชาญฉลาด

`เทมเพลตสตริง '

สิ่งเหล่านี้มีประโยชน์มากเมื่อคุณต้องต่อชิ้นส่วนสตริงหนึ่งอันหรือมากกว่านั้นตามเงื่อนไขที่กำหนด

ใช้ตัวอย่างต่อไปนี้เพื่อแสดงผล quine ใน JS

(f=x=>alert("(f="+f+")()"))()

เมื่อเทียบกับ

(f=x=>alert(`(f=${f})()`))()

ในสตริงเท็มเพลตซึ่งเป็นสตริงภายในสอง backquotes (`) สิ่งใดภายใน a ${ }จะถูกใช้เป็นโค้ดและประเมินเพื่อแทรกคำตอบที่เกิดขึ้นในสตริง

ฉันจะโพสต์เทคนิคเพิ่มเติมในภายหลัง มีความสุขในการเล่นกอล์ฟ!


1
.search สั้นใช้เมื่อเป็นไปได้! แต่มันไม่เหมือนกันของ. indexOf .search ต้องการ a regexpไม่ใช่สตริง ลอง'abc'.search('.')
edc65


คุณสามารถปรับเปลี่ยนอาร์เรย์เดิมด้วยวิธีการอินสแตนซ์ ที่สองคือดัชนีปัจจุบันและที่สามคืออาร์เรย์ที่ถูกทำซ้ำ
Isiah Meadows

8
"เข้าร่วมเว็บไซต์หนึ่งสัปดาห์หลัง" - 21.4k ตัวแทน ...
GamrCorps

2
รวมถึงการ.mapเรียกซ้ำเป็นอีกเทคนิคหนึ่งที่บางครั้งสามารถช่วยคุณเปลี่ยนforลูปเป็นนิพจน์ได้
Neil

20

การใช้ชวเลขคุณสมบัติ

ชวเลขคุณสมบัติช่วยให้คุณสามารถตั้งค่าตัวแปรให้เป็นค่าอาร์เรย์:

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 (ฐานแปด) เป็นทศนิยม:

0b111110111 // == 503
0o767       // == 503

+สามารถใช้ในการแปลงสตริงไบนารีฐานแปดหรือฐานสิบหกให้เป็นตัวเลขทศนิยม คุณสามารถใช้0b, 0oและ0x, สำหรับไบนารี, ฐานแปดและฐานสิบหกตามลำดับ:

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ช่วยให้คุณประหยัดหลายไบต์ในระยะยาว


เคล็ดลับการแปลงฐานเป็นสิ่งที่ดี แต่มีโอกาสมากกว่าที่หมายเลขการแปลงจะอยู่ในรูปแบบของตัวแปรแทนที่จะเป็นตัวอักษรซึ่งในกรณีนี้จะกลายเป็นนานกว่านั้นมาก
เครื่องมือเพิ่มประสิทธิภาพ

1
'0x'+v-0สั้นกว่านี้ แต่อาจใช้งานไม่ได้ในบางสถานการณ์
ETHproductions

1
โดยวิธีการ0767(ES5) สั้นกว่า0o767สัญกรณ์ (ES6)
Camilo Martin

@CamiloMartin 0767เป็นส่วนขยายที่ไม่ได้มาตรฐานและเป็นสิ่งต้องห้ามในโหมดเข้มงวด
Oriol

1
@Oriol โหมดเข้มงวดเป็นมส์ที่ไม่ดี มันไม่ได้ช่วยเรื่องประสิทธิภาพไม่ได้บังคับให้คุณเขียนโค้ดที่ดีจริงๆและจะไม่เป็นค่าเริ่มต้นอยู่ดี 0ตัวอักษรฐานแปด -prefixed จะไม่ได้ไปทุกที่และมี ECMAScript 0oที่ถูกต้องเป็น
Camilo Martin

19

การใช้แม่แบบสตริงพร้อมฟังก์ชั่น

เมื่อคุณมีฟังก์ชั่นที่มีหนึ่งสตริงเป็นอาร์กิวเมนต์ คุณสามารถละเว้น()ถ้าคุณไม่มีนิพจน์ใด ๆ :

join`` // Works
join`foobar` // Works
join`${5}` // Doesn't work 

9
ถูกเตือนนี่จะส่งผ่านอาร์เรย์จริงๆ fun`string` เป็นเช่นเดียวกับที่ไม่ได้fun(["string"]) fun("string")สิ่งนี้ดีสำหรับฟังก์ชั่นที่ส่งไปยังสตริงเช่นalertแต่สำหรับคนอื่น ๆ สิ่งนี้อาจทำให้เกิดปัญหา สำหรับข้อมูลเพิ่มเติมโปรดดูบทความ MDN
Cyoce

5
สิ่งอ้างอิงด่วน: fun`foo${1}bar${2}bazเทียบเท่ากับการโทรfun(["foo","bar","baz"],1,2)
Cyoce

14

Array Comprehensions (Firefox 30-57)

หมายเหตุ: ความเข้าใจของอาเรย์ไม่เคยเป็นมาตรฐานและล้าสมัยกับ Firefox 58. ใช้ด้วยความเสี่ยงของคุณเอง


แต่เดิมข้อมูลจำเพาะ ECMAScript 7 มีคุณสมบัติใหม่มากมาย แม้ว่าสิ่งเหล่านี้ส่วนใหญ่ไม่ได้ทำให้เป็นรุ่นที่สรุปแล้วการสนับสนุน Firefox (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 ? ปกติแล้วมันจะโอเคน้อยกว่า:

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]

ดังนั้นคำแนะนำของฉันคือการใช้ array comprehensions ไม่ว่าคุณจะใช้ที่ใด.map และ .filterโดยทั่วไป

String Comprehensions

สิ่งที่ดีเกี่ยวกับความเข้าใจใน ES7 นั้นแตกต่างจากฟังก์ชั่นเฉพาะของอาเรย์เช่น.mapและ.filterพวกเขาสามารถใช้กับวัตถุที่ทำซ้ำได้ใด ๆไม่ใช่แค่อาร์เรย์ สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อจัดการกับสตริง ตัวอย่างเช่นหากคุณต้องการเรียกใช้อักขระแต่ละตัวcในสตริงผ่านc.charCodeAt():

x=>[...x].map(c=>c.charCodeAt())
x=>[for(c of x)c.charCodeAt()]

นั่นคือการบันทึกสองไบต์ในขนาดที่ค่อนข้างเล็ก และถ้าคุณต้องการกรองอักขระบางตัวในสตริง? ตัวอย่างเช่นอันนี้เก็บเฉพาะอักษรตัวใหญ่:

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 ไบต์!

ข้อดีอีกประการของความเข้าใจสตริงคือสตริง hardcoded บันทึกไบต์พิเศษเนื่องจากคุณสามารถเว้นช่องว่างหลังจาก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()แต่ทุกอย่างก็มาลงในข้อมูลเฉพาะของสถานการณ์ เป็นการดีที่สุดที่จะลองใช้ทั้งสองวิธีและดูว่าวิธีใดที่ใช้งานได้ดีกว่า

PS อย่าลังเลที่จะแนะนำเคล็ดลับที่เกี่ยวข้องกับความเข้าใจอื่นหรือวิธีการปรับปรุงคำตอบนี้!


นี่คือเคล็ดลับสำหรับช่วงที่จะช่วยเพิ่มตัวละครอีกสองสามตัว:(x,y)=>[...Array(y-x)].map(a=>x++)
Mwr247

2
คุณสามารถตัดอีก 11 ไบต์เพื่อให้ช่วงจาก 0 ถึง x:x=>[...Array(x).keys()]
Mwr247

อันสุดท้ายสำหรับความเข้าใจที่นั่น: n=>[for(x of Array(n).keys())if(/1/.test(x))x](ประหยัด 7 ไบต์)
Mwr247

@ Mwr247 ที่จริงฉันเห็นแล้วว่าช่วงนี้มักจะไม่สั้นกับความเข้าใจเหมือนกับคุณสมบัติ ES6 อื่น ๆ ฉันจะเพิ่มในส่วนของสตริงแทนและให้คุณจัดการกับช่วง
ETHproductions

เป็นที่น่าสังเกตว่า Array Comprehensions นั้นเลิกใช้แล้วและถูกลบออกจากจาวาสคริปต์ทุกเวอร์ชันล่าสุด ดูเอกสาร MDNในเรื่อง
Keefer Rourke

13

การแสดงออกของฟังก์ชั่นใน ES6 ใช้เครื่องหมายลูกศรและช่วยประหยัดไบต์ได้มากหากเปรียบเทียบกับรุ่น ES5:

f=function(x,y){return x+y}
f=(x,y)=>x+y

หากฟังก์ชันของคุณมีเพียงพารามิเตอร์เดียวคุณสามารถละเว้นวงเล็บเพื่อบันทึกสองไบต์:

f=x=>x+1

หากฟังก์ชั่นของคุณไม่มีพารามิเตอร์เลยให้ประกาศมันราวกับว่ามันมีหนึ่งที่จะบันทึกหนึ่งไบต์:

f=()=>"something"
f=x=>"something"

ระวัง: ฟังก์ชั่นลูกศรไม่เหมือนกันfunction () {}ทุกประการ กฎสำหรับthisแตกต่างกัน (และ IMO ที่ดีกว่า) ดูเอกสาร


2
แต่เมื่อคุณเล่นกอล์ฟคุณมักไม่สนใจthisฯลฯ
เครื่องมือเพิ่มประสิทธิภาพ

1
โดยทั่วไปไม่ได้ แต่มันเป็นข้อแม้ที่คุณอาจไม่เคยรู้เมื่อมันเกิดขึ้น มันเป็นเรื่องธรรมดามากขึ้นสำหรับ lambdas ที่ไม่จำเป็นต้องมีฟังก์ชั่นเฉพาะที่นี้มีผลผูกพันในการผลิต
Isiah Meadows

นอกจากนี้ถ้าคุณต้องการที่จะใช้เวลาทั้งหมดของการขัดแย้งของคุณคุณสามารถใช้ "ส่วนที่เหลือ" คุณสมบัติอาร์กิวเมนต์เช่นจะมีที่f=(...x)=>x f(1,2,3) => [1,2,3]
Conor O'Brien

1
นี่คือเคล็ดลับเฉพาะสำหรับไซต์นี้: หากคุณกำลังตอบกลับด้วยฟังก์ชั่นที่ใช้รูปแบบที่(x,y)=>...คุณสามารถบันทึกไบต์ด้วยการแกงโดยแทนที่ด้วยx=>y=>...
Cyoce

12

ใช้evalสำหรับฟังก์ชั่นลูกศรที่มีหลายคำสั่งและreturn

หนึ่งในเทคนิคที่ไร้สาระยิ่งกว่าที่ฉันเคยเจอ ...

returnลองนึกภาพการทำงานของลูกศรที่เรียบง่ายที่ต้องการงบหลายและ

a=>{for(o="",i=0;i<a;i++)o+=i;return o}

ฟังก์ชั่นที่เรียบง่ายยอมรับพารามิเตอร์เดียวaซึ่งวนซ้ำจำนวนเต็มทั้งหมดใน[0, a)และ tacks พวกเขาไปยังจุดสิ้นสุดของสตริงออกoซึ่งจะถูกส่งกลับ ตัวอย่างเรียกนี้กับเป็นพารามิเตอร์จะให้ผลผลิต40123

โปรดทราบว่าฟังก์ชั่นลูกศรนี้จะต้องอยู่ในวงเล็บปีกกา{}และมีreturn oที่สิ้นสุด

นี้ความพยายามครั้งแรกน้ำหนักในที่39 ไบต์

ไม่เลว แต่โดยใช้evalเราสามารถปรับปรุงสิ่งนี้

a=>eval('for(o="",i=0;i<a;i++)o+=i;o')

ฟังก์ชั่นนี้ออกวงเล็บและงบผลตอบแทนโดยการตัดรหัสในevalและก็ทำให้คำสั่งสุดท้ายในการประเมินผลการeval oสิ่งนี้ทำให้เกิดการevalกลับoซึ่งจะทำให้ฟังก์ชั่นที่จะกลับมาoเพราะตอนนี้มันเป็นคำสั่งเดียว

ความพยายามที่ได้รับการปรับปรุงนี้มีน้ำหนัก38 ไบต์บันทึกหนึ่งไบต์จากต้นฉบับ

แต่เดี๋ยวก่อนมีอีกมาก! ข้อความ Eval จะคืนสิ่งที่ประเมินล่าสุดของพวกเขา ในกรณีนี้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 ไบต์


1
ฉันคิดว่าการเขียนฟังก์ชั่นนิรนามอาจสั้นกว่านี้ด้วย
Downgoat

@vihan ใช่ฟังก์ชั่นทั้งสองนี้สามารถทำให้ไม่ระบุชื่อเพื่อบันทึก 2 ไบต์แต่ละรายการ ออมทรัพย์หนึ่งไบต์ยังคงยืนแม้ว่า
ริ

1
แต่ยังดีกว่า: eval ส่งคืนนิพจน์สุดท้ายที่ประเมินดังนั้นคุณไม่จำเป็นต้อง;oลองดู:a=>eval('for(o="",i=0;i<a;i++)o+=i')
edc65

4
แต่สตริงเทมเพลต!
Conor O'Brien

1
@ CᴏɴᴏʀO'Bʀɪᴇɴสนใจที่จะอธิบายว่าสายแม่แบบจะทำงานที่นี่โดยใช้ฟังก์ชั่นตัวอย่างเป็นบริบท?
WallyWest

10

ต้องการเทมเพลตสตริงบรรทัดใหม่เหนือ "\ n"

สิ่งนี้จะเริ่มชำระด้วยอักขระบรรทัดใหม่หนึ่งบรรทัดในรหัสของคุณ กรณีใช้งานหนึ่งกรณีอาจเป็น:

(16 ไบต์)

array.join("\n")

(15 ไบต์)

array.join(`
`)

อัปเดต:คุณสามารถทิ้งวงเล็บไว้ได้เนื่องจากสตริงแม่แบบที่ติดแท็ก (ขอบคุณ edc65!):

(13 ไบต์)

array.join`
`

5
แต่ยิ่งดีกว่าคุณสามารถหลีกเลี่ยงวงเล็บ อ่านเอกสาร ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ … ) เพื่อดูว่าทำไม
edc65

อ่าใช่มั้ย ขอบคุณฉันได้เพิ่ม
Chiru

9

ไส้อาร์เรย์ - ค่าคงที่และช่วงไดนามิก

ฉันทิ้งสิ่งเหล่านี้ไว้เป็นความคิดเห็นภายใต้ความเข้าใจ แต่เนื่องจากโพสต์นั้นมุ่งเน้นที่ความเข้าใจเป็นหลักฉันจึงคิดว่ามันจะเป็นการดีถ้าให้ที่นี่เป็นที่ของตัวเอง

ES6 ทำให้เราสามารถเติมอาร์เรย์ด้วยค่าคงที่โดยไม่ต้องใช้การวนซ้ำ:

// ES5
function(x){for(i=0,a=[];i<x;i++)a[i]=0;return a}

// ES6
x=>Array(x).fill(0)

ทั้งสองส่งคืนอาร์เรย์ของความยาว x ซึ่งเติมด้วยค่า 0

หากคุณต้องการเติมอาร์เรย์ด้วยค่าไดนามิก (เช่นช่วงจาก 0 ... x) ผลลัพธ์จะยาวขึ้นเล็กน้อย (แม้ว่าจะยังสั้นกว่าแบบเดิม):

// ES5
function(x){for(i=0,a=[];i<x;i++)a[i]=i;return a}

// ES6
x=>Array(x).fill().map((a,i)=>i)

ทั้งสองส่งคืนอาร์เรย์ของความยาว x เริ่มต้นด้วยค่า 0 และสิ้นสุดใน x-1

เหตุผลที่คุณต้องการ.fill()คือมีเพียงการเริ่มต้นอาร์เรย์จะไม่อนุญาตให้คุณแมป กล่าวคือการทำเช่นx=>Array(x).map((a,i)=>i)นั้นจะส่งคืนอาร์เรย์ว่าง คุณสามารถหลีกเลี่ยงความต้องการในการเติม (และทำให้สั้นลง) โดยใช้ตัวดำเนินการสเปรดดังนี้:

x=>[...Array(x)]

เมื่อใช้ตัวดำเนินการและ.keys()ฟังก์ชันสเปรดคุณสามารถสร้างช่วงสั้น 0 ... x:

x=>[...Array(x).keys()]

หากคุณต้องการช่วงที่กำหนดเองจาก x ... y หรือช่วงพิเศษทั้งหมด (เช่นหมายเลขคู่) คุณสามารถกำจัด.keys()และใช้.map()หรือใช้.filter()กับตัวดำเนินการกระจายได้:

// Custom range from x...y
(x,y)=>[...Array(y-x)].map(a=>x++)

// Even numbers (using map)
x=>[...Array(x/2)].map((a,i)=>i*2)

// Even numbers (using filter)
x=>[...Array(x).keys()].filter(a=>~a%2)

นี่คือข้อเสนอแนะสำหรับตัวอย่างที่สอง: x=>Array(x).fill(i=0).map(a=>i++)นอกจากนี้ฉันไม่แน่ใจว่า.fill(0)จำเป็นต้องใช้ 0 ใน คุณเคยลองไหม
ETHproductions

@ETHproductions คุณพูดถูกฉันลืม 0 ไม่จำเป็นในการเติมก่อนแผนที่ นี่ทำให้ตัวละครสั้นกว่าที่คุณแนะนำ 1 ตัวดังนั้นฉันจะให้มันเป็นอย่างนั้น ขอบคุณ!
Mwr247

ยังยกตัวอย่างเช่นที่ผ่านมาทำงานได้ดีเช่นเดียวกับa=>a%2-1 a=>a%2<1
ETHproductions

1
เคล็ดลับใหม่ที่ฉันได้เรียนรู้: ใช้[...Array(x)]งานได้ดีArray(x).fill()และสั้นลง 2 ไบต์ x=>[...Array(x)].map((a,i)=>i)
ETHproductions

1
@yonatanmn ดีมาก! ความคิดเห็นจะมีเพียง 1) 1/4ตัวอย่างจะสั้นลง[0,0,0,0]และ 2) ฟังก์ชันที่ได้รับการจัดทำขึ้นเพื่อการใช้งานที่เฉพาะเจาะจงดังนั้นจะไม่ส่งคืนความยาวที่เชื่อถือได้ ( Mapคือ 32 ไบต์ใน Chrome แต่ 36 ไบต์ใน Firefox)
Mwr247

9

การคืนค่าในฟังก์ชั่นลูกศร

มันเป็นความรู้ทั่วไปว่าถ้าคำสั่งเดียวตามประกาศฟังก์ชันลูกศรมันจะส่งกลับผลลัพธ์ของคำสั่งนั้น:

a=>{return a+3}
a=>a+3

-7 ไบต์

ดังนั้นเมื่อเป็นไปได้ให้รวมหลาย ๆ คำสั่งเป็นหนึ่ง สิ่งนี้ทำได้ง่ายที่สุดโดยการล้อมรอบข้อความสั่งด้วยวงเล็บและคั่นด้วยเครื่องหมายจุลภาค:

a=>{r=0;a.map(n=>r+=n);return r}
a=>(r=0,a.map(n=>r+=n),r)

-8 ไบต์

แต่ถ้ามีเพียงสองข้อความก็มักจะเป็นไปได้ (และสั้นกว่า) เพื่อรวมเข้ากับ&&หรือ||:

a=>{r=0;a.map(n=>r+=n);return r}

// - Use && because map always returns an array (true)
// - declaration of r moved into unused map argument to make it only 2 statements
a=>a.map(n=>r+=n,r=0)&&r

-9 ไบต์

ในที่สุดหากคุณกำลังใช้แผนที่ (หรือคล้ายกัน) และจำเป็นต้องส่งคืนตัวเลขและคุณสามารถรับประกันได้ว่าแผนที่จะไม่ส่งคืนอาร์เรย์ที่มีความยาว 1 หมายเลขด้วยตัวเลขคุณสามารถคืนค่าตัวเลขด้วย|:

a=>{a=b=0;a.map(n=>(a+=n,b-=n));return a/b}

// - {} in map ensures it returns an array of undefined, so the | will make the returned
//   array cast from [ undefined, undefined, undefined ] to ",," to NaN to 0 and 0|n = n,
//   if the map returned [ 4 ] it would cast from [ 4 ] to "4" to 4 and make it 4|n
a=>a.map(n=>{a+=n,b-=n},a=b=0)|a/b

ในตัวอย่างสุดท้ายนั้นคุณต้องแน่ใจด้วยว่าจำนวนจะเป็นจำนวนเต็มเสมอ
ETHproductions

8

การแฮ็กแม่แบบสตริงแบบสุ่ม

ฟังก์ชั่นนี้จะทำให้เกิดสองสาย (เช่นเปลี่ยน"abc","de"เป็น"adbec"):

f=(x,y)=>String.raw({raw:x},...y)

โปรดทราบว่านี้จะทำงานเฉพาะเมื่อมีความยาวมากกว่าx yมันทำงานอย่างไรคุณถาม? String.rawถูกออกแบบมาให้เป็นเทมเพลตแท็กเช่น:

String.raw`x: ${x}\ny: ${y}\nx + y: ${x + y}`

สิ่งนี้เรียกโดยทั่วไปString.raw(["x: ", "\ny: ", "\nx + y: ", ""], x, y, x + y)แม้ว่าจะไม่ใช่เรื่องง่าย เทมเพลตอาร์เรย์ยังมีrawคุณสมบัติพิเศษซึ่งโดยทั่วไปจะเป็นสำเนาของอาเรย์ แต่ด้วยสตริงดิบ String.raw(x, ...args)โดยทั่วไปแล้วผลตอบแทนx.raw[0] + args[0] + x.raw[1] + args[1] + x.raw[2] + ...และอื่น ๆ จนกว่าxจะหมดรายการ

ดังนั้นตอนนี้เรารู้วิธีการString.rawทำงานเราสามารถใช้มันเพื่อประโยชน์ของเรา:

f=(x,y)=>String.raw({raw:x},...y)                   // f("abc", "de") => "adbec"
f=x=>String.raw({raw:x},...[...x].keys())           // f("abc") => "a0b1c"
f=(x,y)=>String.raw({raw:x},...[...x].fill(y))      // f("abc", " ") => "a b c"

แน่นอนว่าสำหรับอันสุดท้ายf=(x,y)=>x.split``.join(y)นั้นสั้นกว่า แต่คุณก็เข้าใจ

ต่อไปนี้เป็นฟังก์ชั่น riffling สองอย่างที่สามารถใช้ได้หากxและyมีความยาวเท่ากัน:

f=(x,y)=>String.raw({raw:x.match(/.?/g)},...y)
f=(x,y)=>String.raw({raw:x},...y)+y.slice(-1)  // Only works if x.length == y.length

คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับString.raw เกี่ยวกับ MDN


7

วิธีเล่นกอล์ฟด้วยการเรียกซ้ำ

การเรียกซ้ำแม้ว่าจะไม่ใช่ตัวเลือกที่เร็วที่สุด แต่มักจะสั้นที่สุด โดยทั่วไปการเรียกซ้ำนั้นสั้นที่สุดหากโซลูชันสามารถทำให้การแก้ปัญหาง่ายขึ้นสำหรับส่วนเล็ก ๆ ของความท้าทายโดยเฉพาะอย่างยิ่งถ้าอินพุตเป็นตัวเลขหรือสตริง ตัวอย่างเช่นหากf("abcd")สามารถคำนวณได้จาก"a"และf("bcd")มักจะใช้การเรียกซ้ำ

ยกตัวอย่างเช่นแฟคทอเรียล:

n=>[...Array(n).keys()].reduce((x,y)=>x*++y,1)
n=>[...Array(n)].reduce((x,_,i)=>x*++i,1)
n=>[...Array(n)].reduce(x=>x*n--,1)
n=>{for(t=1;n;)t*=n--;return t}
n=>eval("for(t=1;n;)t*=n--")
f=n=>n?n*f(n-1):1

ในตัวอย่างนี้การเรียกซ้ำเป็นทางสั้นกว่าตัวเลือกอื่น ๆ อย่างชัดเจน

วิธีการเกี่ยวกับผลรวมของ charcodes:

s=>[...s].map(x=>t+=x.charCodeAt(),t=0)|t
s=>[...s].reduce((t,x)=>t+x.charCodeAt())
s=>[for(x of(t=0,s))t+=x.charCodeAt()]|t  // Firefox 30+ only
f=s=>s?s.charCodeAt()+f(s.slice(1)):0

หนึ่งนี้เป็น trickier .mapแต่เราจะเห็นว่าเมื่อดำเนินการอย่างถูกต้องจะช่วยประหยัดการเรียกซ้ำมากกว่า

ทีนี้ลองดูการเรียกซ้ำแบบต่างๆ:

Pre-เรียกซ้ำ

นี่เป็นประเภทการเรียกซ้ำที่สั้นที่สุด การป้อนข้อมูลที่ถูกแบ่งออกเป็นสองส่วนaและbและฟังก์ชั่นคำนวณสิ่งที่มีและa f(b)กลับไปที่ตัวอย่างปัจจัยของเรา:

f=n=>n?n*f(n-1):1

ในกรณีนี้aคือn , bเป็นn-1a*f(b)และค่าที่ส่งกลับคือ

หมายเหตุสำคัญ:ฟังก์ชันเรียกซ้ำทั้งหมดจะต้องมีวิธีหยุดการเรียกซ้ำเมื่ออินพุตมีขนาดเล็กพอ ในฟังก์ชั่นแฟกทอเรียลนี่คือการควบคุมด้วยn? :1เช่นถ้าอินพุตเป็น0ส่งคืน1โดยไม่ต้องโทรfอีกครั้ง

โพสต์เรียกซ้ำ

โพสต์ - เรียกซ้ำคล้าย pre- ซ้ำ แต่แตกต่างกันเล็กน้อย การป้อนข้อมูลที่ถูกแบ่งออกเป็นสองส่วนaและbและฟังก์ชั่นคำนวณสิ่งที่มีแล้วโทรออกa f(b,a)อาร์กิวเมนต์ที่สองมักจะมีค่าเริ่มต้น (เช่นf(a,b=1))

การเรียกซ้ำล่วงหน้าเป็นสิ่งที่ดีเมื่อคุณต้องทำอะไรเป็นพิเศษด้วยผลลัพธ์สุดท้าย ตัวอย่างเช่นหากคุณต้องการแฟคทอเรียลของตัวเลขบวก 1:

f=(n,p=1)=>n?f(n-1,n*p):p+1

อย่างไรก็ตามถึงกระนั้นการโพสต์ก็ยังไม่สั้นกว่าการใช้การเรียกซ้ำล่วงหน้าภายในฟังก์ชั่นอื่น:

n=>(f=n=>n?n*f(n-1):1)(n)+1

ดังนั้นเมื่อมันสั้นลง? คุณอาจสังเกตเห็นว่าการโพสต์ซ้ำในตัวอย่างนี้ต้องใช้วงเล็บรอบ ๆ อาร์กิวเมนต์ของฟังก์ชั่นในขณะที่การสอบถามซ้ำไม่ได้ โดยทั่วไปหากทั้งสองโซลูชันต้องการวงเล็บล้อมรอบข้อโต้แย้งการโพสต์ซ้ำจะสั้นกว่าประมาณ 2 ไบต์:

n=>!(g=([x,...a])=>a[0]?x-a.pop()+g(a):0)(n)
f=([x,...a],n=0)=>a[0]?f(a,x-a.pop()+n):!n

(โปรแกรมที่นำมาจากคำตอบนี้ )

วิธีการหาทางออกที่สั้นที่สุด

โดยปกติแล้ววิธีเดียวที่จะหาวิธีที่สั้นที่สุดคือลองทั้งหมด รวมถึง:

  • ลูป
  • .map(สำหรับสตริงอย่างใดอย่างหนึ่ง[...s].mapหรือs.replace; สำหรับตัวเลขคุณสามารถสร้างช่วง )
  • ความเข้าใจของอาเรย์
  • การเรียกซ้ำล่วงหน้า (บางครั้งอยู่ในตัวเลือกอื่นเหล่านี้)
  • โพสต์เรียกซ้ำ

และนี่เป็นเพียงวิธีแก้ปัญหาที่พบบ่อยที่สุด ทางออกที่ดีที่สุดอาจจะมีการรวมกันของเหล่านี้หรือแม้กระทั่งบางสิ่งบางอย่างที่แตกต่างกันอย่างสิ้นเชิง วิธีที่ดีที่สุดที่จะหาวิธีการแก้ปัญหาที่สั้นที่สุดคือการพยายามทำทุกอย่าง


1
+1 สำหรับค่าของมันและฉันต้องการเพิ่ม +1 อีกหนึ่งสำหรับ zootopia
edc65

7

วิธีที่สั้นกว่าที่จะทำ .replace


หากคุณต้องการแทนที่อินสแตนซ์ทั้งหมดของสตริงย่อยที่แน่นอนหนึ่งด้วยสตริงอื่นในสตริงวิธีที่ชัดเจนจะเป็น:

f=s=>s.replace(/l/g,"y") // 24 bytes
f("Hello, World!")       // -> "Heyyo, Woryd!"

อย่างไรก็ตามคุณสามารถทำได้น้อยกว่า 1 ไบต์:

f=s=>s.split`l`.join`y`  // 23 bytes
f("Hello, World!")       // -> "Heyyo, Woryd!"

โปรดทราบว่านี่จะไม่สั้นอีกต่อไปหากคุณต้องการใช้คุณสมบัติ regex นอกเหนือจากการgตั้งค่าสถานะ อย่างไรก็ตามหากคุณกำลังแทนที่อินสแตนซ์ทั้งหมดของตัวแปรมันมักจะสั้นกว่ามาก:

f=(s,c)=>s.replace(RegExp(c,"g"),"") // 36 bytes
f=(s,c)=>s.split(c).join``           // 26 bytes
f("Hello, World!","l") // -> "Heo, Word!"

บางครั้งคุณต้องการแมปชาร์ตแต่ละอันในสตริงแทนที่แต่ละอันด้วยอย่างอื่น ฉันมักจะพบว่าตัวเองทำสิ่งนี้:

f=s=>s.split``.map(x=>x+x).join`` // 33 bytes
f=s=>[...s].map(x=>x+x).join``    // 30 bytes
f("abc") // -> "aabbcc"

อย่างไรก็ตาม.replaceเกือบจะสั้นกว่าเสมอ:

f=s=>s.replace(/./g,x=>x+x)  // 27 bytes
f=s=>s.replace(/./g,"$&$&")  // Also works in this particular case

ตอนนี้ถ้าคุณต้องการแมปไปที่อักขระแต่ละตัวในสตริง แต่ไม่สนใจเกี่ยวกับสตริงผลลัพธ์.mapมักจะดีกว่าเพราะคุณสามารถกำจัด.join``:

f=s=>s.replace(/./g,x=>t+=+x,t=0)&&t // 36 bytes
f=s=>[...s].map(x=>t+=+x,t=0)&&t     // 32 bytes
f("12345")  // -> 15

สำหรับกรณีสุดท้ายหากมีเพียงบางตัวอักษรที่ตรงกับ regex (เช่น/\w/g) มีความสนใจการใช้แทนที่จะดีกว่ามากในการสาธิตนี้
Shieru Asakoto

6

เขียนตัวอักษร RegEx ด้วย eval

คอนสตรัค regex อาจมีขนาดใหญ่มากเนื่องจากเป็นชื่อยาว ให้เขียนตัวอักษรด้วย eval และ backticks แทน:

eval(`/<${i} [^>]+/g`)

หากตัวแปรiเท่ากับfooสิ่งนี้จะสร้าง:

/<foo [^>]+/g

นี่เท่ากับ:

new RegExp("<"+i+" [^>]+","g")

นอกจากนี้คุณยังสามารถใช้String.rawเพื่อหลีกเลี่ยงการหลบแบ็กสแลชซ้ำ ๆ\

eval(String.raw`/\(?:\d{4})?\d{3}\d{3}\d{3}\d{3}\d{3}\d{3}\d{4}/g`)

สิ่งนี้จะออก:

/(?:\d{4})?\d{3}\d{3}\d{3}/g

ซึ่งเท่ากับ:

RegExp("\\(?:\\d{4})?\\d{3}\\d{3}\\d{3}\\d{3}\\d{3}\\d{3}\\d{4}","g")

จำไว้!

String.rawใช้ไบต์จำนวนมากและหากคุณไม่มีแบ็กสแลชอย่างน้อยเก้าตัวString.rawก็จะยาวขึ้น


คุณไม่จำเป็นต้องใช้newมันดังนั้นการใช้ Constructor นั้นจะสั้นกว่าสำหรับตัวอย่างที่สอง
เครื่องมือเพิ่มประสิทธิภาพ

5

.forEachvs forลูป

มัก.mapจะชอบวงใด ๆ ง่ายประหยัดทันที


a.map(f)
for(x of a)f(x);
for(i=0;i<a.length;)f(a[i++]);
  • ทั้งหมด 8 ไบต์สำหรับต้นฉบับ
  • บันทึกได้ 8 ไบต์เทียบกับการลด( 50% )
  • บันทึก 22 ไบต์เทียบกับ C-style สำหรับลูป ( ลด73% )

a.map(x=>f(x,0))
for(x of a)f(x,0);
for(i=0;i<a.length;)f(a[i++],0);
  • ทั้งหมด 16 ไบต์สำหรับต้นฉบับ
  • บันทึก 2 ไบต์เทียบกับ for-of ( ลด11% )
  • บันทึก 16 ไบต์เทียบกับ C-style สำหรับลูป ( ลด 50% )

a.map((x,i)=>f(x,i,0))
for(i in a)f(a[i],i,0);
for(i=0;i<a.length;)f(a[i],i++,0);
  • รวม 22 ไบต์สำหรับต้นฉบับ
  • บันทึก 1 ไบต์เทียบกับ for-in ( ลด4% )
  • บันทึก 11 ไบต์เทียบกับ C-style สำหรับลูป ( ลด33% )

a.map(x=>f(x)&g(x))
for(x of a)f(x),g(x);
for(i=0;i<a.length;)f(x=a[i++]),g(x);
  • ผลรวม 19 ไบต์สำหรับต้นฉบับ
  • บันทึก 2 ไบต์เทียบกับ for-of ( ลด10% )
  • บันทึก 18 ไบต์เทียบกับ C-style สำหรับลูป ( ลด49% )

5

การใช้ตัวนับเริ่มต้นในการเรียกซ้ำ

หมายเหตุ : พูดอย่างเคร่งครัดนี่ไม่เฉพาะ ES6 อย่างไรก็ตามการใช้และการเรียกใช้ซ้ำใน ES6 นั้นเหมาะสมกว่าเนื่องจากลักษณะที่กระชับของฟังก์ชันลูกศร


เป็นเรื่องปกติที่จะพบกับฟังก์ชั่นวนซ้ำที่ใช้ตัวนับkเริ่มแรกตั้งค่าเป็นศูนย์และเพิ่มขึ้นในแต่ละการวนซ้ำ:

f = (…, k=0) => [do a recursive call with f(…, k+1)]

ภายใต้สถานการณ์บางอย่างเป็นไปได้ที่จะละเว้นการเริ่มต้นของตัวนับและแทนที่k+1ด้วย-~k:

f = (…, k) => [do a recursive call with f(…, -~k)]

เคล็ดลับนี้มักจะช่วยประหยัด 2 ไบต์

มันทำงานทำไมและเมื่อไหร่?

~undefined === -1สูตรที่ทำให้มันเป็นไปได้คือ ดังนั้นในการย้ำแรกจะได้รับการประเมินเพื่อ-~k 1ในการทำซ้ำครั้งต่อไปนั้น-~kจะเทียบเท่ากับ-(-k-1)ซึ่งเท่ากับk+1อย่างน้อยสำหรับจำนวนเต็มในช่วง [0 … 2 31 -1]

อย่างไรก็ตามคุณต้องตรวจสอบให้แน่ใจว่าk = undefinedการทำซ้ำครั้งแรกจะไม่ส่งผลกระทบต่อการทำงานของฟังก์ชัน โดยเฉพาะอย่างยิ่งคุณควรเก็บไว้ในใจว่าดำเนินการทางคณิตศาสตร์ที่เกี่ยวข้องมากที่สุดจะส่งผลให้undefinedNaN

ตัวอย่างที่ 1

ป.ร. ให้ไว้เป็นจำนวนเต็มบวกnฟังก์ชั่นนี้จะมองหาจำนวนเต็มเล็กkที่ไม่ได้แบ่งn:

f=(n,k=0)=>n%k?k:f(n,k+1)   // 25 bytes

มันสามารถย่อให้เหลือ:

f=(n,k)=>n%k?k:f(n,-~k)     // 23 bytes

งานนี้เพราะn % undefinedเป็นNaNซึ่งเป็นเท็จ นั่นคือผลลัพธ์ที่คาดหวังในการทำซ้ำครั้งแรก

[ลิงก์ไปยังคำตอบดั้งเดิม]

ตัวอย่างที่ 2

ป.ร. ให้ไว้เป็นจำนวนเต็มบวกnฟังก์ชั่นนี้จะมองหาจำนวนเต็มpดังกล่าวว่า(3**p) - 1 == n:

f=(n,p=0,k=1)=>n<k?n>k-2&&p:f(n,p+1,k*3)  // 40 bytes

มันสามารถย่อให้เหลือ:

f=(n,p,k=1)=>n<k?n>k-2&&p:f(n,-~p,k*3)    // 38 bytes

ใช้งานได้เพราะpไม่ได้ใช้เลยในการวนซ้ำครั้งแรก ( n<kเป็นเท็จ)

[ลิงก์ไปยังคำตอบดั้งเดิม]


5

ฟังก์ชั่น ES6

คณิตศาสตร์

Math.cbrt(x)Math.pow(x,1/3)บันทึกตัวอักษรมากกว่า

Math.cbrt(x)
Math.pow(x,1/3)

บันทึก 3 ตัวอักษร

Math.hypot(...args)มีประโยชน์เมื่อคุณต้องการสแควร์รูทของผลรวมของกำลังสองของส่วนโค้ง การสร้างรหัส ES5 นั้นทำได้ยากกว่าการใช้บิวด์อิน

ฟังก์ชั่นMath.trunc(x)จะไม่เป็นประโยชน์เนื่องจากx|0สั้นลง (ขอบคุณ Mwr247!)

มีคุณสมบัติมากมายที่ใช้โค้ดจำนวนมากใน ES5 แต่ง่ายกว่าใน ES6:

  • Math.acosh, asinh, atanh, cosh, ,sinh tanhคำนวณค่าไฮเพอร์โบลิกเทียบเท่าของฟังก์ชันตรีโกณมิติ
  • Math.clz32. อาจเป็นไปได้ที่จะทำใน ES5 แต่ตอนนี้ง่ายขึ้น นับจำนวนศูนย์นำหน้าด้วยตัวเลข 32 บิต

มีมากขึ้นดังนั้นฉันแค่จะรายการบางส่วน:
Math.sign, Math.fround, Math.imul, Math.log10, ,Math.log2Math.log1p


Math.trunc(x)x|0เป็นสี่ครั้งนานกว่า
Mwr247

@ mwr247: ตกลงจะอัปเดต
ev3commander

นี่คือเทียบเท่า ES5 ที่สั้นที่สุดที่ฉันรู้สำหรับฟังก์ชั่นเหล่านี้สองสามอัน: Math.hypot(a,b) => Math.sqrt(a*a+b*b)(อีกต่อไป 3 ไบต์; ยิ่งมีอาร์กิวเมนต์มากขึ้นอีก), Math.sign(a) => (a>0)-(a<0)(สั้นกว่า 1 ไบต์ แต่ต้องการวงเล็บที่ล้อมรอบในบางกรณี; อาจใช้ไม่ได้NaN)
ETHproductions

@ETHproductions คุณต้องมีอาเรย์สำหรับอาร์กิวเมนต์ (วิธีแก้ปัญหา es5 ของ) hypot และคุณแน่ใจหรือไม่ว่าวิธีแก้ปัญหาสำหรับ Math.sign ใช้สำหรับ -0 ได้หรือไม่ (ควรคืนค่า -0)
ev3commander

1
@ ev3commander สิ่งเหล่านี้มีความหมายเหมือนกับการแทนที่แบบอินไลน์สำหรับเทียบเท่า ES6 ตามลำดับดังนั้นจึงถูกลดขนาดลงสำหรับการใช้งาน 99% การสร้างฟังก์ชั่นเหล่านี้ใหม่อย่างแท้จริงจะต้องใช้รหัสมากขึ้น นอกจากนี้ฉันไม่เห็นเหตุผลที่จะต้องมีกรณีพิเศษสำหรับ -0 เนื่องจาก (AFAIK) ไม่มีวิธีรับ -0 ยกเว้นโดยการระบุด้วยตนเองและไม่มีประโยชน์ในการใช้งานใน code-golf แต่ขอบคุณสำหรับการชี้สิ่งเหล่านั้นออกมา
ETHproductions

5

ปรับช่วงค่าคงที่ขนาดเล็กให้เหมาะสม map()

บริบท

map()for[0..N1]

for(i = 0; i < 10; i++) {
  do_something_with(i);
}

สามารถถูกแทนที่ด้วย:

[...Array(10).keys()].map(i => do_something_with(i))

หรือมากกว่าปกติ:

[...Array(10)].map((_, i) => do_something_with(i))

Array(N)N

[0..N1]

ด้านล่างนี้เป็นบทสรุปของวิธีทางเลือกที่สั้นกว่าเมื่อตัวนับ i

N           | Method                               | Example                         | Length
------------+--------------------------------------+---------------------------------+-------
N ≤ 6       | use a raw array of integers          | [0,1,2,3].map(i=>F(i))          | 2N+10
N = 7       | use either a raw array of integers   | [0,1,2,3,4,5,6].map(i=>F(i))    | 24
            | or a string if your code can operate | [...'0123456'].map(i=>F(i))     | 23
            | with characters rather than integers |                                 |
8 ≤ N ≤ 9   | use scientific notation 1e[N-1]      | [...1e7+''].map((_,i)=>F(i))    | 24
N = 10      | use scientific notation 1e9          | [...1e9+''].map((_,i)=>F(i))    | 24
            | or the ES7 expression 2**29+'4' if   | [...2**29+'4'].map(i=>F(i))     | 23
            | the order doesn't matter and your    |                                 |
            | code can operate with characters     |  (order: 5,3,6,8,7,0,9,1,2,4)   |
            | rather than integers                 |                                 |
11 ≤ N ≤ 17 | use scientific notation 1e[N-1]      | [...1e12+''].map((_,i)=>F(i))   | 25
N = 18      | use the fraction 1/3                 | [...1/3+''].map((_,i)=>F(i))    | 24
N = 19      | use the fraction 1/6                 | [...1/6+''].map((_,i)=>F(i))    | 24
20 ≤ N ≤ 21 | use scientific notation 1e[N-1]      | [...1e20+''].map((_,i)=>F(i))   | 25
N = 22      | use scientific notation -1e20        | [...-1e20+''].map((_,i)=>F(i))  | 26
23 ≤ N ≤ 99 | use Array(N)                         | [...Array(23)].map((_,i)=>F(i)) | 27

หมายเหตุ : ความยาวของรหัสโทรกลับF(i)จะไม่ถูกนับ

การเพิ่มประสิทธิภาพสำหรับช่วง [1..9]

[1..9]

[...17**6+'8'].map(i=>F(i))  // order: 2,4,1,3,7,5,6,9,8; length: 23

การปรับให้เหมาะสมโดยไม่มีตัวนับ

Nครั้งโดยไม่ต้องใช้ตัวนับ:

N           | Method                               | Example                         | Length
------------+--------------------------------------+---------------------------------+-------
N ≤ 5       | use a raw array of integers          | [0,0,0,0].map(_=>F())           | 2N+10
6 ≤ N ≤ 10  | use scientific notation 1e[N-1]      | [...1e7+''].map(_=>F())         | 20
11 ≤ N ≤ 17 | use scientific notation 1e[N-1]      | [...1e12+''].map(_=>F())        | 21
N = 18      | use the fraction 1/3                 | [...1/3+''].map(_=>F())         | 20
N = 19      | use the fraction 1/6                 | [...1/6+''].map(_=>F())         | 20
20 ≤ N ≤ 21 | use scientific notation 1e[N-1]      | [...1e20+''].map(_=>F())        | 21
N = 22      | use scientific notation -1e20        | [...-1e20+''].map(_=>F())       | 22
23 ≤ N ≤ 99 | use Array(N)                         | [...Array(23)].map(_=>F())      | 23

NB : ความยาวของรหัสโทรกลับF()จะไม่ถูกนับ


ไม่ควร2**26จะเป็น2**29?
Shaggy

@Shaggy Heck จับดี!
Arnauld

ไม่ต้องการที่จะแก้ไขในตัวเองเพราะฉันมีรหัสตาบอด! : D
Shaggy

ใช้.keys()งานคุณไม่จำเป็นต้องใช้แลมบ์ดา:[...Array(10).keys()].map(do_something_with)
lazuli ยาว

@ long-lazuli หากคุณไม่ต้องการแลมบ์ดาและต้องการช่วงระยะหนึ่งคุณอาจไม่จำเป็นต้องใช้แผนที่เช่นกัน ...
Arnauld

4

การมอบหมายการทำลายล้าง

ES6 แนะนำไวยากรณ์ใหม่สำหรับการทำลายล้างการมอบหมายเช่นการตัดค่าเป็นชิ้น ๆ และกำหนดแต่ละชิ้นให้กับตัวแปรที่แตกต่างกัน นี่คือตัวอย่างบางส่วน:

สตริงและอาร์เรย์

a=s[0];b=s[1];       // 14 bytes
[a,b]=s;             //  8 bytes

a=s[0];s=s.slice(1); // 20 bytes
a=s.shift();         // 12 bytes, only works if s is an array
[a,...s]=s;          // 11 bytes, converts s to an array

วัตถุ

a=o.asdf;b=o.bye;c=o.length; // 28 bytes
{asdf:a,bye:b,length:c}=o;   // 26 bytes

a=o.a;b=o.b;c=o.c; // 18 bytes
{a,b,c}=o;         // 10 bytes

การมอบหมายเหล่านี้สามารถใช้ในพารามิเตอร์ฟังก์ชันได้:

f=a=>a[0]+a[1]+a[2]
f=([a,b,c])=>a+b+c

f=b=>b[1]?b[0]+f(b.slice(1)):b[0]*2
f=b=>b[1]?b.shift()+f(b):b[0]*2
f=([a,...b])=>b[0]?a+f(b):a*2

4

อีกวิธีหนึ่งที่ควรหลีกเลี่ยง return

คุณรู้ว่าคุณควรใช้ eval สำหรับฟังก์ชั่นลูกศรที่มีหลายคำสั่งและส่งคืนลูกศรกับงบหลายและผลตอบแทน ในกรณีที่ผิดปกติบางอย่างคุณสามารถประหยัดได้มากขึ้นโดยใช้ฟังก์ชั่นย่อยด้านใน

ฉันพูดผิดปกติเพราะ

  1. ผลลัพธ์ที่ส่งคืนจะต้องไม่ใช่นิพจน์สุดท้ายที่ประเมินในลูป

  2. ต้องมีการเริ่มต้นที่แตกต่างกัน (อย่างน้อย) 2 ครั้งก่อนลูป

ในกรณีนี้คุณสามารถใช้ฟังก์ชันย่อยภายในโดยไม่มีการส่งคืนโดยมีหนึ่งในค่าเริ่มต้นที่ส่งเป็นพารามิเตอร์

ตัวอย่าง ค้นหาส่วนกลับของผลรวมของฟังก์ชั่น exp สำหรับค่าในช่วงจาก a ถึง b

ทางยาว - 55 ไบต์

(a,b)=>{for(r=0,i=a;i<=b;i++)r+=Math.exp(i);return 1/r}

ด้วย eval - 54 ไบต์

(a,b)=>eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i);1/r")

ด้วยฟังก์ชั่นภายใน - 53 ไบต์

(a,b)=>(i=>{for(r=0;i<=b;i++)r+=Math.exp(i)})(a)||1/r

โปรดทราบว่าโดยไม่จำเป็นต้องมีขีด จำกัด ช่วงล่างaฉันสามารถผสานการเริ่มต้นของ i และ r และเวอร์ชัน eval นั้นสั้นลง


ในตัวอย่างของคุณไม่จำเป็นต้องเก็บไว้a
l4m2

@ l4m2 ฉันไม่สามารถรับคะแนนของคุณช่วยได้โปรด ...
edc65

(i,b)=>{for(r=0;i<=b;i++)r+=Math.exp(i);return 1/r}
l4m2

@ l4m2 เอ่อถูกต้อง return a/rน่าจะเป็นตัวอย่างที่ดีกว่า
edc65

1
eval ยังคงดีกว่า(a,b)=>1/eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i)")และในกรณีนี้(i,b)=>1/eval("for(r=0;i<=b;)r+=Math.exp(i++)")
JayXon

4

การใช้รูปแบบ currying สำหรับฟังก์ชัน dyadic และ recursive

ฟังก์ชัน Dyadic

เมื่อใดก็ตามที่ฟังก์ชั่นใช้สองอาร์กิวเมนต์ที่แน่นอนโดยไม่มีค่าเริ่มต้นการใช้รูปแบบ currying จะบันทึกหนึ่งไบต์

ก่อน

f =
(a,b)=>a+b  // 10 bytes

เรียกได้ว่ามี f(a,b)

หลังจาก

f =
a=>b=>a+b   // 9 bytes

เรียกได้ว่ามี f(a)(b)

หมายเหตุ : โพสต์นี้ใน Metaยืนยันความถูกต้องของไวยากรณ์นี้

ฟังก์ชั่นวนซ้ำ

การใช้ไวยากรณ์การแก้ปัญหาอาจบันทึกบางไบต์เมื่อฟังก์ชันเรียกซ้ำใช้อาร์กิวเมนต์หลายตัว แต่จำเป็นต้องอัพเดตบางส่วนระหว่างการทำซ้ำแต่ละครั้ง

ตัวอย่าง

ฟังก์ชันต่อไปนี้คำนวณผลรวมของจำนวนเต็มทั้งหมดในช่วง[a,b]:

f=(a,b)=>a>b?0:b+f(a,b-1)   // 25 bytes

เนื่องจากaยังคงไม่เปลี่ยนแปลงในระหว่างกระบวนการทั้งหมดเราสามารถบันทึก 3 ไบต์โดยใช้:

f =                         // no need to include this assignment in the answer anymore
a=>F=b=>a>b?0:b+F(b-1)      // 22 bytes

หมายเหตุ : ดังที่ Neil สังเกตเห็นในความคิดเห็นความจริงที่ว่าข้อโต้แย้งไม่ได้ถูกส่งผ่านไปยังฟังก์ชันเรียกซ้ำอย่างชัดเจนไม่ได้หมายความว่าควรจะถือว่าไม่สามารถเปลี่ยนแปลงได้ ถ้ามีความจำเป็นที่เราจะปรับเปลี่ยนaภายในรหัสฟังก์ชั่นที่มีa++, a--หรืออะไรก็ตามไวยากรณ์ที่คล้ายกัน


ตัวอย่างสุดท้ายสามารถเขียนเป็นa=>F=b=>a>b?0:a+++F(b)ปรับเปลี่ยนaสำหรับการโทรซ้ำแต่ละครั้ง สิ่งนี้ไม่ได้ช่วยในกรณีนั้น แต่มันอาจบันทึกไบต์ในกรณีที่มีอาร์กิวเมนต์มากกว่า
Neil

เฮ้ฉันแค่คิดถึงการเขียนเคล็ดลับสำหรับสิ่งนี้ :-)
ETHproductions

4

ฟังก์ชั่นการทดสอบเบื้องต้น

ฟังก์ชั่น 28- ไบต์ต่อไปนี้จะคืนค่าtrueสำหรับจำนวนเฉพาะและfalseสำหรับช่วงเวลาที่ไม่ใช่:

f=(n,x=n)=>n%--x?f(n,x):x==1

สามารถแก้ไขได้อย่างง่ายดายเพื่อคำนวณสิ่งอื่น ๆ ตัวอย่างเช่นฟังก์ชัน 39- ไบต์นี้นับจำนวนช่วงเวลาที่น้อยกว่าหรือเท่ากับจำนวน:

f=(n,x=n)=>n?n%--x?f(n,x):!--x+f(n-1):0

หากคุณมีตัวแปรnที่คุณต้องการตรวจสอบ primality อยู่แล้วฟังก์ชัน primality สามารถทำให้ง่ายขึ้นเล็กน้อย:

(f=x=>n%--x?f(x):x==1)(n)

มันทำงานอย่างไร

f = (         // Define a function f with these arguments:
  n,          //   n, the number to test;
  x = n       //   x, with a default value of n, the number to check for divisibility by.
) =>
  n % --x ?   //   If n is not divisible by x - 1,
  f(n, x)     //     return the result of f(n, x - 1).
              //   This loops down through all numbers between n and 0,
              //     stopping when it finds a number that divides n.
  : x == 1    //   Return x == 1; for primes only, 1 is the smallest number
              //     less than n that divides n.
              //   For 1, x == 0; for 0, x == -1.

หมายเหตุ: สิ่งนี้จะล้มเหลวด้วยข้อผิดพลาด "เรียกซ้ำมากเกินไป" เมื่อเรียกด้วยอินพุตที่มีขนาดใหญ่พอเช่น 12345 คุณสามารถแก้ไขได้ด้วยลูป:

f=n=>eval('for(x=n;n%--x;);x==1')

1
แต่ล้มเหลวด้วยการเรียกซ้ำมากเกินไปสำหรับอินพุตที่น้อยที่สุดเท่าที่ 12345
edc65

x==1อาจเป็นx<2เพื่อการออม
CalculatorFeline

@CalculatorFeline ขอบคุณ แต่แล้วมันล้มเหลว1หรือ0(เพราะxจะเป็น0หรือ-1ตามลำดับ)
ETHproductions

อาจมีประโยชน์ในบางกรณี นอกจากนี้!~-xสำหรับ -0 ไบต์
CalculatorFeline

3

Array#concat() และผู้ประกอบการแพร่กระจาย

สิ่งนี้ขึ้นอยู่กับสถานการณ์เป็นส่วนใหญ่


การรวมหลายอาร์เรย์

ชอบฟังก์ชั่น concat ยกเว้นการโคลนนิ่ง

บันทึก 0 ไบต์

a.concat(b)
[...a,...b]

เสีย 3 ไบต์

a.concat(b,c)
[...a,...b,...c]

บันทึก 3 ไบต์

a.concat()
[...a]

บันทึก 6 ไบต์

// Concatenate array of arrays
[].concat.apply([],l)
[].concat(...l)

Array#concat()ชอบใช้อาร์เรย์ที่มีอยู่แล้ว

บันทึกได้ง่าย4 ไบต์

[].concat(a,b)
a.concat(b)

3

ส่งคืนผลลัพธ์ระดับกลาง

คุณรู้ว่าการใช้ตัวดำเนินการจุลภาคคุณสามารถดำเนินการตามลำดับของนิพจน์ที่ส่งคืนค่าสุดท้าย แต่การใช้ไวยากรณ์อาเรย์ที่ไม่เหมาะสมคุณสามารถส่งคืนค่ากลาง มันมีประโยชน์ใน. map () เช่น

// capitalize words
// f is a flag indicating if prev char is space
[...x].map(c=>(f?c=c.toUpperCase():0,f=c<'!',c),f=1).join('')

// shortened to ...
[...x].map(c=>[f?c.toUpperCase():c,f=c<'!'][0],f=1).join('')

3
จำไว้แน่นอนว่า.join('')สามารถเป็นได้.join``
Cyoce

3

ตั้งค่าเริ่มต้นของพารามิเตอร์ฟังก์ชัน

($,a,b,_)=>_!=undefined?'asdf':_ // before
($,a,b,_)=>_!=[]._?'asdf':_ // before, but a bit golfed
($,a,b,_='asdf')=>_ // after

คนนี้มีประโยชน์จริง ๆ ...

อย่างไรก็ตามโปรดเข้าใจว่าบางสิ่งบางอย่างเช่น_=>_||'asdf'สั้นลงเมื่อคุณผ่านอาร์กิวเมนต์ (มีประโยชน์) ไปยังฟังก์ชัน


1
ฉันจะทราบว่าการใช้ OR _=>_||'asdf'มักจะสั้นกว่าในกรณีส่วนใหญ่
Downgoat

@Downgoat ฉันทราบว่าจะส่งกลับค่า"asdf"สำหรับอินพุต""(สตริงว่าง)
ETHproductions

2
โปรดทราบว่าจะมีการประเมินค่าเริ่มต้นเมื่อใดก็ตามที่มีการโต้แย้งundefinedแม้ว่าคุณจะผ่านค่านั้นอย่างชัดเจนก็ตาม ยกตัวอย่างเช่น[...Array(n)].map((a,b,c)=>b)มักจะผ่านไปundefinedสำหรับaคุณและคุณจึงสามารถให้ค่าเริ่มต้นสำหรับมัน (ถึงแม้จะไม่ได้อยู่ในเงื่อนไขของการb)
Neil

3

ใช้evalวงเล็บปีกกาสำหรับฟังก์ชั่นลูกศร

ฟังก์ชั่นลูกศรนั้นยอดเยี่ยม พวกเขาอยู่ในรูปแบบx=>yที่xเป็นข้อโต้แย้งและyเป็นค่าตอบแทน แต่ถ้าคุณจำเป็นต้องใช้โครงสร้างการควบคุมเช่นคุณจะต้องใส่วงเล็บเช่นwhile =>{while(){};return}อย่างไรก็ตามเราสามารถหลีกเลี่ยงสิ่งนี้ได้ โชคดีที่evalฟังก์ชั่นใช้เวลาสตริงประเมินสตริงที่เป็นรหัส JS และผลตอบแทนการแสดงออกการประเมินที่ผ่านมา ตัวอย่างเช่นเปรียบเทียบสองสิ่งนี้:

x=>{while(foo){bar};return baz} // before
x=>eval('while(foo){bar};baz')  // after
//                            ^

เราสามารถใช้ส่วนขยายของแนวคิดนี้เพื่อย่อโค้ดของเราให้สั้นลง: ในสายตาของevalโครงสร้างการควบคุมก็ส่งคืนนิพจน์ที่ประเมินล่าสุดของพวกเขา ตัวอย่างเช่น:

x=>{while(foo)bar++;return bar} // before
x=>eval('while(foo)++bar')      // after
//                        ^^^^^

3

การดำเนินการเชิงตรรกะของกอล์ฟใน ES6

"GLOE (S6)"

ลอจิกทั่วไป

สมมติว่าคุณได้สร้างงบและs tดูว่าคุณสามารถใช้หนึ่งในสิ่งทดแทนต่อไปนี้:

Traditional conjuction: s&&t
Equivalent conjuction: s*t OR s&t

Traditional disjunction: s||t
Equivalent disjunction: s+t OR s|t

(สิ่งเหล่านี้อาจไม่ทำงานหากคำสั่งซื้อไม่ถูกต้องเช่น+และ*มีลำดับความสำคัญต่ำกว่า||และ&&ทำ)

นอกจากนี้ต่อไปนี้เป็นนิพจน์เชิงตรรกะที่มีประโยชน์:

  • ไม่ว่าจะเป็นsหรือtเป็นจริง / XOR:s^t
  • sและtเป็นค่าความจริงเดียวกัน: !s^tหรือs==t

ตรรกะของอาร์เรย์

สมาชิกทุกคนaพึงพอใจกับเงื่อนไขp:

a.every(p)                             // 10 bytes (11 bytes saved)
a.map(x=>c&=p(x),c=1)                  // 21 bytes (16 bytes saved)
for(i=0,c=1;i<a.length;c&=p(a[i++]));  // 37 bytes (hideously long)

สมาชิกอย่างน้อยหนึ่งคนที่มีaคุณสมบัติตรงตามเงื่อนไขp:

a.some(p)                            // 9  bytes (13 bytes saved)
a.map(x=>c|=p(x),c=0)                // 21 bytes (14 bytes saved)
for(i=c=0;i<a.length;c|=p(a[i++]));  // 35 bytes (just please no)

ไม่มีสมาชิกที่aมีเงื่อนไขพึงพอใจp: !a.some(p).

องค์ประกอบeมีอยู่ในอาร์เรย์a:

a.includes(e)                        // 13 bytes, standard built-in
~a.indexOf(e)                        // 13 bytes, "traditional" method
a.find(x=>e==x)                      // 15 bytes, find (ES6)
a.some(x=>x==e)                      // 15 bytes, some (ES5)
(a+"").search(e)                     // 16 bytes, buggy
a.filter(t=>t==e).length             // 24 bytes, no reason to use this
for(i=c=0;i<a.length;c+=e==a[i++]);  // 35 bytes, super-traditional

องค์ประกอบที่eไม่ได้อยู่ในอาร์เรย์a:

!a.includes(e)
!~a.indexOf(e)
a.every(t=>t!=e)
!a.filter(t=>t==e).length
for(i=0,c=1;i<a.length;c*=e!=a[i++]);

ฉันมักจะใช้&&และ||เป็นx?y:xและx?x:yตามลำดับ แต่ฉันสามารถดูว่าสิ่งนี้จะมีประโยชน์ในโปรแกรมที่ใช้ตรรกะมากกว่า ปัญหาหนึ่งที่เกิดขึ้น+ก็คือเช่นนั้น3และ-3มีทั้งความจริง แต่3+-3ไม่ใช่
ETHproductions

@ETHproductions อาคุณพูดถูก นั่นคือกรณีที่ขอบ ยังสามารถทำงานถ้า- s != t
Conor O'Brien

a.filter(t=>t==e).length==a.lengthไม่ถูกต้อง มันควรเป็น!a.filter(t=>t==e).length
ETHproductions

@ ETHproductions ถูกต้องคุณ!
Conor O'Brien

3

ย่อการเรียกฟังก์ชันซ้ำ

หากคุณเรียกใช้ฟังก์ชันที่ชื่อยาว ๆ ซ้ำ ๆ เช่นการจัดการ Canvas:

c.lineTo(0,100);c.lineTo(100,100);c.lineTo(100,0);c.lineto(0,0);c.stroke()

วิธีดั้งเดิมในการย่อให้ใหญ่คือการใช้ชื่อแทนฟังก์ชัน:

c[l='lineTo'](0,100);c[l](100,100);c[l](100,0);c[l](0,0);c.stroke()

หากคุณมีการโทรเพียงพอวิธีที่ดีกว่าคือการสร้างฟังก์ชั่นที่ทำงานให้คุณ:

l=(x,y)=>c.lineTo(x,y);l(0,100);l(100,100);l(100,0);l(0,0);c.stroke()

หากการเรียกใช้ฟังก์ชันส่วนใหญ่ถูกผูกมัดคุณสามารถทำให้ฟังก์ชันส่งคืนตัวเองทำให้คุณสามารถตัดสองไบต์ออกจากการโทรแต่ละครั้งติดต่อกัน:

l=(x,y)=>c.lineTo(x,y)||l;l(0,100)(100,100)(100,0)(0,0);c.stroke()

ตัวอย่างการใช้: 1 , 2


1
คุณสามารถร่นกับตัวดำเนินการเชื่อมโยง :(l=::c.lineTo)(0,100)(100,100)(100,0)(0,0);c.stroke()
Downgoat

@Downgoat ขอบคุณเบราว์เซอร์ใดบ้างที่สนับสนุน (นอกจากนี้จากสิ่งที่ฉันเห็นว่าจะเกิดข้อผิดพลาดในการโทรครั้งที่สองเนื่องจากc.lineToไม่ส่งคืนเองตามธรรมชาติ)
ETHproductions

คุณต้องถูมันผ่าน babel เพราะมันเป็นคุณสมบัติของ ES7
Downgoat

3

ผู้ประกอบการผูก ::

ตัวดำเนินการเชื่อมโยงสามารถใช้เพื่อช่วยย่อไบต์บนฟังก์ชันที่ทำซ้ำ:

(x='abc'.search(a))+x.search(b) // Before
(x=::'abc'.search)(a)+x(b)      // 5 bytes saved

นอกจากนี้หากคุณต้องการใช้ฟังก์ชั่นที่แตกต่างกันthisเช่น:

s[r='replace'](/a/g,'b')+s[r](/c/g,'d') // Before
(r=s.replace)(/a/g,'b')+s::r(/c/g,'d')  // 1 byte saved

3

หลีกเลี่ยงเครื่องหมายจุลภาคเมื่อจัดเก็บข้อมูลจำนวนมาก

หากคุณมีข้อมูลจำนวนมาก (เช่นดัชนี, ตัวอักษร, ... ) ที่คุณต้องการเก็บไว้ในอาร์เรย์คุณอาจจะดีกว่าที่จะใช้คอมม่าทั้งหมด วิธีนี้จะได้ผลดีที่สุดถ้าข้อมูลทุกชิ้นมีความยาวสตริงเท่ากัน 1 จะดีที่สุด

43 ไบต์ (พื้นฐาน)

a=[[3,7,6,1,8,9,4,5,2],[5,4,3,2,7,6,5,4,3]]

34 ไบต์ (ไม่มีเครื่องหมายจุลภาค)

a=[[..."376189452"],[..."543276543"]]

หากคุณเต็มใจเปลี่ยนการเข้าถึงอาร์เรย์ของคุณคุณอาจลดค่านี้ลงไปอีกโดยเก็บค่าเดียวกันดังนี้:

27 ไบต์ (ข้อมูลเดียวกันเปลี่ยนการเข้าถึงอาร์เรย์ได้เท่านั้น)

a=[..."376189452543276543"]

เหตุใดเฉพาะบล็อกสุดท้ายที่ถูกไฮไลต์
CalculatorFeline

@CalculatorFeline ขอบคุณคงแล้ว
Chiru
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.