Ini mirip dengan "Tips untuk bermain golf di <...>" lainnya, tetapi secara khusus menargetkan fitur-fitur baru dalam JavaScript yang dibesarkan dalam ECMAScript 6 ke atas.
JavaScript inheren adalah bahasa yang sangat verbose, function(){}
, .forEach()
, mengkonversi string untuk array, array objek seperti ke array, dll, dll super bloats dan tidak sehat bagi Golf.
ES6 +, di sisi lain, memiliki beberapa fitur yang sangat berguna dan mengurangi jejak. x=>y
,, [...x]
dll. hanyalah beberapa contoh.
Silakan kirim beberapa trik bagus yang dapat membantu mengurangi beberapa byte tambahan dari kode Anda.
CATATAN: Trik untuk ES5 sudah tersedia di Tips untuk bermain golf di JavaScript ; jawaban utas ini harus fokus pada trik yang hanya tersedia di ES6 dan versi ES lainnya di masa depan.
Namun, utas ini juga untuk pengguna yang saat ini golf menggunakan fitur ES5. Jawaban mungkin juga berisi tips untuk membantu mereka memahami dan memetakan fitur ES6 dengan gaya pengkodean ES5.
sumber
Trik dipelajari di sini sejak saya bergabung
Bahasa pemrograman utama saya adalah JS dan kebanyakan ES6. Sejak saya bergabung dengan situs ini seminggu yang lalu, saya telah belajar banyak trik berguna dari sesama anggota. Saya menggabungkan beberapa di sini. Semua kredit untuk komunitas.
Fungsi panah dan loop
Kita semua tahu bahwa fungsi panah menyimpan banyak byts
Tetapi Anda harus mengingat beberapa hal
,
ie(a=b,a.map(d))
- Di sini, nilai yang dikembalikan adalah ekspresi terakhira.map(d)
do something
bagian Anda lebih dari satu pernyataan, maka Anda perlu menambahkan{}
tanda kurung di sekitarnya .{}
tanda kurung di sekitarnya , Anda perlu menambahkan pernyataan pengembalian eksplisit.Hal di atas berlaku banyak kali ketika Anda memiliki loop yang terlibat. Jadi sesuatu seperti:
Di sini saya membuang setidaknya 9 karakter karena pengembalian. Ini bisa dioptimalkan.
.map
atau.every
atau.some
sebagai gantinya. Perhatikan bahwa jika Anda ingin mengubah array yang sama dengan yang Anda pemetaan, itu akan gagal.Jadi yang di atas menjadi:
karakter yang dihapus:
{}return
karakter yang ditambahkan:
(){}>|
Perhatikan bagaimana saya memanggil metode penutupan, yang dengan benar mengisi variabel
n
dan kemudian karena metode penutupan tidak mengembalikan apa pun (yaitu mengembalikanundefined
), saya bitwise atau mengembalikan arrayn
semua dalam satu pernyataan tunggal dari fungsi panah luaru
Koma dan titik koma
Hindari mereka apa pun,
Jika Anda mendeklarasikan variabel dalam satu lingkaran, atau seperti yang disebutkan di bagian sebelumnya, menggunakan
,
pernyataan terpisah untuk memiliki fungsi tanda panah pernyataan tunggal, maka Anda dapat menggunakan beberapa trik yang cukup bagus untuk menghindari hal itu,
atau;
untuk mengurangi beberapa byte terakhir.Pertimbangkan kode ini:
Di sini, saya memanggil banyak metode untuk menginisialisasi banyak variabel. Setiap inisialisasi menggunakan a
,
atau;
. Ini dapat ditulis ulang sebagai:Perhatikan bagaimana saya menggunakan fakta bahwa metode ini tidak mengganggu variabel yang diteruskan ke sana dan menggunakan fakta itu untuk mencukur 3 byte.
Lain-lain
.search
dari pada.indexOf
Keduanya memberikan hasil yang sama, tetapi
search
lebih pendek. Meskipun pencarian mengharapkan Ekspresi Reguler, jadi gunakan dengan bijak.`String Template`
Ini sangat berguna ketika Anda harus membuat satu atau lebih bagian string berdasarkan kondisi tertentu.
Ambil contoh berikut untuk menampilkan quine di JS
vs.
Dalam string template, yang merupakan string di dalam dua backquotes (`), apa pun di dalam sebuah
${ }
diperlakukan sebagai kode dan dievaluasi untuk memasukkan jawaban yang dihasilkan dalam string.Saya akan memposting beberapa trik lagi nanti. Selamat bermain golf!
sumber
regexp
, bukan string. Coba'abc'.search('.')
.map
, rekursi adalah teknik lain yang terkadang dapat membantu Anda mengubahfor
perulangan menjadi ekspresi.Menggunakan steno properti
Properti singkatan memungkinkan Anda mengatur variabel ke nilai array:
Ini juga dapat digunakan seperti:
Anda bahkan dapat menggunakan ini untuk membalikkan variabel:
Anda juga dapat menggunakan ini untuk mempersingkat
slice()
fungsi.Konversi basis
ES6 menyediakan cara yang jauh lebih pendek untuk mengonversi bentuk Basis-2 (biner) dan Basis-8 (oktal) menjadi desimal:
+
dapat digunakan untuk mengkonversi string biner, oktal atau hex ke angka desimal. Anda dapat menggunakan0b
,,0o
dan0x
, masing-masing untuk biner, oktal, dan hex .:Jika Anda menggunakan ini> 7 kali, maka akan lebih pendek untuk menggunakan
parseInt
dan menamainya:Sekarang
p
dapat digunakan untukparseInt
, menghemat banyak byte dalam jangka panjang.sumber
'0x'+v-0
bahkan lebih pendek, tetapi mungkin tidak berfungsi dengan baik dalam beberapa skenario.0767
(ES5) lebih pendek dari0o767
notasi (ES6).0767
adalah ekstensi non-standar, dan itu secara eksplisit dilarang dalam mode ketat.0
-tepat literal oktal tidak pergi ke mana-mana, dan ecmascript sebagai valid0o
.Menggunakan templat string dengan fungsi
Ketika Anda memiliki fungsi dengan satu string sebagai argumen. Anda dapat menghilangkan
()
jika Anda tidak memiliki ekspresi:sumber
fun`string`
sama denganfun(["string"])
, tidakfun("string")
. Ini bagus untuk fungsi yang dilemparkan ke string, sepertialert
, tetapi untuk yang lain ini dapat menyebabkan masalah. Untuk informasi lebih lanjut, lihat artikel MDNfun`foo${1}bar${2}baz
sama dengan meneleponfun(["foo","bar","baz"],1,2)
Pemahaman Array (Firefox 30-57)
Catatan: pemahaman array tidak pernah distandarisasi, dan dibuat usang dengan Firefox 58. Gunakan dengan risiko Anda sendiri.
Awalnya, spesifikasi ECMAScript 7 berisi banyak fitur berbasis array baru. Meskipun sebagian besar tidak berhasil masuk ke versi final, Firefox mendukung (ed) kemungkinan yang terbesar dari fitur-fitur ini: sintaks baru yang bagus yang dapat menggantikan
.filter
dan.map
denganfor(a of b)
sintaksis. Ini sebuah contoh:Seperti yang Anda lihat, kedua baris tidak jauh berbeda, selain yang kedua tidak mengandung fungsi kata kunci dan panah yang besar. Tetapi ini hanya bertanggung jawab atas pesanan
.filter().map()
; apa yang terjadi jika Anda memilikinya.map().filter()
? Itu benar-benar tergantung pada situasi:Atau bagaimana jika Anda ingin baik
.map
atau.filter
? Yah, biasanya ternyata kurang OK:Jadi saran saya adalah menggunakan pemahaman array di mana pun Anda biasanya menggunakan
.map
dan.filter
, tetapi tidak hanya satu atau yang lain.Pemahaman String
Hal yang baik tentang comprehensions ES7 adalah bahwa, tidak seperti fungsi array-spesifik seperti
.map
dan.filter
, mereka dapat digunakan pada setiap objek iterable, bukan hanya array. Ini sangat berguna ketika berhadapan dengan string. Misalnya, jika Anda ingin menjalankan setiap karakterc
dalam string melaluic.charCodeAt()
:Itu dua byte yang disimpan dalam skala yang cukup kecil. Dan bagaimana jika Anda ingin memfilter karakter tertentu dalam sebuah string? Misalnya, yang ini hanya menyimpan huruf kapital:
Hmm, itu tidak lebih pendek. Tetapi jika kita menggabungkan keduanya:
Wow, seluruh 10 byte disimpan!
Keuntungan lain dari pemahaman string adalah string hardcoded menyimpan byte tambahan, karena Anda dapat menghilangkan spasi setelah
of
:Pengindeksan
Pemahaman array membuatnya sedikit lebih sulit untuk mendapatkan indeks saat ini di string / array, tetapi dapat dilakukan:
Hal utama yang harus diperhatikan adalah memastikan indeks bertambah setiap kali, bukan hanya ketika suatu kondisi terpenuhi.
Pemahaman generator
Pemahaman generator pada dasarnya memiliki sintaks yang sama dengan pemahaman array; cukup ganti tanda kurung dengan tanda kurung:
Ini membuat generator yang fungsinya hampir sama dengan array, tapi itu cerita untuk jawaban lain.
Ringkasan
Pada dasarnya, meskipun pemahaman biasanya lebih pendek daripada
.map().filter()
itu, semua berujung pada kekhasan situasi. Cara terbaik untuk mencobanya adalah sekaligus dan melihat mana yang lebih baik.PS Jangan ragu untuk menyarankan kiat terkait pemahaman lain atau cara untuk meningkatkan jawaban ini!
sumber
(x,y)=>[...Array(y-x)].map(a=>x++)
x=>[...Array(x).keys()]
n=>[for(x of Array(n).keys())if(/1/.test(x))x]
(menghemat 7 byte)Ekspresi fungsi di ES6 menggunakan notasi panah, dan ini membantu banyak menghemat byte jika dibandingkan dengan versi ES5:
Jika fungsi Anda hanya memiliki satu parameter, Anda dapat menghilangkan tanda kurung untuk menyimpan dua byte:
Jika fungsi Anda tidak memiliki parameter sama sekali, mendeklarasikannya seolah-olah ia memiliki satu untuk menyimpan satu byte:
Hati-hati: Fungsi panah tidak persis sama dengan
function () {}
. Aturanthis
untuknya berbeda (dan IMO lebih baik). Lihat dokumensumber
this
dll.f=(...x)=>x
akan memilikinyaf(1,2,3) => [1,2,3]
.(x,y)=>...
Anda dapat menyimpan byte dengan currying dengan menggantinya denganx=>y=>...
Menggunakan
eval
untuk fungsi panah dengan banyak pernyataan dan areturn
Salah satu trik konyol yang saya temukan ...
Bayangkan fungsi panah sederhana yang membutuhkan banyak pernyataan dan a
return
.Sebuah fungsi sederhana yang menerima parameter tunggal
a
, yang iterates atas semua bilangan bulat[0, a)
, dan mengaitkannya ke ujung string outputo
, yang dikembalikan. Misalnya, memanggil ini dengan4
sebagai parameter akan menghasilkan0123
.Perhatikan bahwa fungsi panah ini harus dibungkus dengan kawat gigi
{}
, dan milikireturn o
di bagian akhir.Upaya pertama ini berbobot 39 byte .
Tidak buruk, tetapi dengan menggunakan
eval
, kita dapat meningkatkan ini.Fungsi ini menghapus kawat gigi dan pernyataan kembali dengan membungkus kode dalam
eval
dan hanya membuat pernyataan terakhir dieval
evaluasio
. Ini menyebabkaneval
kembalio
, yang pada gilirannya menyebabkan fungsi kembalio
, karena sekarang menjadi pernyataan tunggal.Upaya yang ditingkatkan ini berbobot 38 byte , menghemat satu byte dari aslinya.
Tapi tunggu, masih ada lagi! Pernyataan valid mengembalikan apa pun pernyataan terakhir mereka dievaluasi. Dalam hal ini, lakukan
o+=i
evaluasio
, jadi kita tidak perlu;o
! (Terima kasih, edc65!)Upaya terakhir ini hanya berbobot 36 byte - penghematan 3 byte dari yang asli!
Teknik ini dapat diperluas ke kasus umum di mana fungsi panah perlu mengembalikan nilai dan memiliki beberapa pernyataan (yang tidak dapat digabungkan dengan cara lain)
menjadi
menghemat satu byte.
Jika
statement2
dievaluasiv
, ini bisamenghemat total 3 byte.
sumber
;o
- coba saja:a=>eval('for(o="",i=0;i<a;i++)o+=i')
Lebih suka string templat baris baru di atas "\ n"
Ini akan mulai menghasilkan bahkan pada satu baris karakter baru dalam kode Anda. Satu use case mungkin:
(16 byte)
(15 byte)
Pembaruan: Anda bahkan dapat meninggalkan kawat gigi karena string templat yang ditandai (terima kasih, edc65!):
(13 byte)
sumber
Mengisi Array - Nilai Statis & Rentang Dinamis
Saya awalnya meninggalkan ini sebagai komentar di bawah pemahaman, tetapi karena posting itu terutama difokuskan pada pemahaman, saya pikir itu akan baik untuk memberikan ini tempat itu sendiri.
ES6 memberi kami kemampuan untuk mengisi array dengan nilai-nilai statis tanpa menggunakan loop:
Keduanya mengembalikan array dengan panjang x, diisi dengan nilai 0.
Namun, jika Anda ingin mengisi array dengan nilai dinamis (seperti rentang dari 0 ... x), hasilnya sedikit lebih lama (meskipun masih lebih pendek dari cara lama):
Keduanya mengembalikan array dengan panjang x, dimulai dengan nilai 0 dan berakhir dengan x-1.
Alasan Anda membutuhkannya
.fill()
di sana adalah karena hanya menginisialisasi array tidak akan membiarkan Anda memetakannya. Artinya, melakukanx=>Array(x).map((a,i)=>i)
akan mengembalikan array kosong. Anda juga dapat menyiasati kebutuhan untuk mengisi (dan karenanya membuatnya lebih pendek) dengan menggunakan operator spread seperti:Dengan menggunakan operator dan
.keys()
fungsi spread , kini Anda dapat membuat kisaran 0 ... x pendek:Jika Anda ingin rentang khusus dari x ... y, atau rentang khusus sama sekali (seperti angka genap), Anda dapat menyingkirkan
.keys()
dan hanya menggunakan.map()
, atau menggunakan.filter()
, dengan operator spread:sumber
x=>Array(x).fill(i=0).map(a=>i++)
Juga, saya tidak yakin bahwa 0 in.fill(0)
diperlukan. Sudahkah Anda mencobanya tanpa?a=>a%2-1
berfungsi dengan baik, seperti halnyaa=>a%2<1
.[...Array(x)]
berfungsi dengan baikArray(x).fill()
, dan 2 byte lebih pendek.x=>[...Array(x)].map((a,i)=>i)
1/4
contohnya akan lebih pendek ditulis[0,0,0,0]
, dan 2) fungsi yang diketikkan adalah implementasi spesifik, jadi tidak akan menghasilkan panjang yang dapat diandalkan (Map
adalah 32 byte di Chrome, tetapi 36 byte di Firefox).Mengembalikan Nilai dalam Fungsi Panah
Sudah menjadi rahasia umum bahwa jika satu pernyataan mengikuti deklarasi fungsi panah, itu mengembalikan hasil pernyataan itu:
-7 byte
Jadi, jika memungkinkan, gabungkan beberapa pernyataan menjadi satu. Ini paling mudah dilakukan dengan mengelilingi pernyataan dengan tanda kurung dan memisahkannya dengan koma:
-8 byte
Tetapi jika hanya ada dua pernyataan, biasanya mungkin (dan lebih pendek) untuk menggabungkannya dengan
&&
atau||
:-9 byte
Akhirnya jika Anda menggunakan peta (atau yang serupa) dan perlu mengembalikan nomor dan Anda dapat menjamin peta tidak akan pernah mengembalikan array 1-panjang dengan nomor, Anda dapat mengembalikan nomor dengan
|
:sumber
Retasan template-string acak
Fungsi ini riffles dua string (yaitu berubah
"abc","de"
menjadi"adbec"
):Perhatikan bahwa ini hanya berfungsi bila
x
lebih lama dariy
. Bagaimana cara kerjanya, Anda bertanya?String.raw
dirancang untuk menjadi tag templat, seperti:Ini pada dasarnya panggilan
String.raw(["x: ", "\ny: ", "\nx + y: ", ""], x, y, x + y)
, meskipun tidak sesederhana itu. Array template juga memilikiraw
properti khusus , yang pada dasarnya adalah salinan array, tetapi dengan string mentah.String.raw(x, ...args)
pada dasarnya pengembalianx.raw[0] + args[0] + x.raw[1] + args[1] + x.raw[2] + ...
dan seterusnya sampaix
kehabisan barang.Jadi sekarang kita tahu cara
String.raw
kerjanya, kita bisa menggunakannya untuk keuntungan kita:Tentu saja, untuk yang terakhir,
f=(x,y)=>x.split``.join(y)
jauh lebih pendek, tetapi Anda mendapatkan idenya.Berikut adalah beberapa fungsi riffling yang juga berfungsi jika
x
dany
memiliki panjang yang sama:Anda dapat mempelajari lebih lanjut tentang
String.raw
MDN .sumber
Cara bermain golf dengan rekursi
Rekursi, meskipun bukan opsi tercepat, seringkali merupakan yang terpendek. Secara umum, rekursi adalah yang terpendek jika solusi dapat disederhanakan menjadi solusi untuk bagian tantangan yang lebih kecil, terutama jika inputnya berupa angka atau string. Misalnya, jika
f("abcd")
dapat dihitung dari"a"
danf("bcd")
, biasanya yang terbaik adalah menggunakan rekursi.Ambil, misalnya, faktorial:
Dalam contoh ini, rekursi jelas jauh lebih pendek daripada opsi lainnya.
Bagaimana dengan jumlah karakter:
Yang ini lebih sulit, tetapi kita dapat melihat bahwa ketika diimplementasikan dengan benar, rekursi menghemat 4 byte
.map
.Sekarang mari kita lihat berbagai jenis rekursi:
Pra rekursi
Ini biasanya jenis rekursi terpendek. Input dibagi menjadi dua bagian
a
danb
, dan fungsi menghitung sesuatu dengana
danf(b)
. Kembali ke contoh faktorial kami:Dalam hal ini,
a
adalah n ,b
adalah n-1 , dan nilai yang dikembalikan adalaha*f(b)
.Catatan penting: Semua fungsi rekursif harus memiliki cara untuk berhenti berulang ketika inputnya cukup kecil. Dalam fungsi faktorial, ini dikontrol dengan
n? :1
, yaitu jika inputnya 0 , kembalikan 1 tanpa meneleponf
lagi.Pasca rekursi
Pasca rekursi mirip dengan pra rekursi, tetapi sedikit berbeda. Input dibagi menjadi dua bagian
a
danb
, dan fungsi menghitung sesuatu dengana
, lalu memanggilf(b,a)
. Argumen kedua biasanya memiliki nilai default (yaituf(a,b=1)
).Pra-rekursi baik ketika Anda perlu melakukan sesuatu yang istimewa dengan hasil akhir. Misalnya, jika Anda ingin faktorial dari angka plus 1:
Namun demikian, post-tidak selalu lebih pendek dari menggunakan pra-rekursi dalam fungsi lain:
Jadi kapan lebih pendek? Anda mungkin memperhatikan bahwa pasca rekursi dalam contoh ini membutuhkan tanda kurung di sekitar argumen fungsi, sedangkan pra-rekursi tidak. Secara umum, jika kedua solusi membutuhkan tanda kurung di sekitar argumen, pasca-rekursi sekitar 2 byte lebih pendek:
(program di sini diambil dari jawaban ini )
Cara menemukan solusi terpendek
Biasanya satu-satunya cara untuk menemukan metode terpendek adalah dengan mencoba semuanya. Ini termasuk:
.map
(untuk string, baik[...s].map
ataus.replace
; untuk angka, Anda dapat membuat rentang )Dan ini hanyalah solusi yang paling umum; solusi terbaik mungkin merupakan kombinasi dari ini, atau bahkan sesuatu yang sama sekali berbeda . Cara terbaik untuk menemukan solusi terpendek adalah mencoba segalanya .
sumber
Cara yang lebih pendek untuk dilakukan
.replace
Jika Anda ingin mengganti semua instance dari satu substring tepat dengan yang lain dalam string, cara yang jelas adalah:
Namun, Anda dapat melakukan 1 byte lebih pendek:
Perhatikan bahwa ini tidak lagi lebih pendek jika Anda ingin menggunakan fitur regex apa pun selain
g
bendera. Namun, jika Anda mengganti semua instance variabel, biasanya jauh lebih pendek:Terkadang Anda ingin memetakan masing-masing char dalam sebuah string, mengganti masing-masing dengan yang lain. Saya sering menemukan diri saya melakukan ini:
Namun,
.replace
hampir selalu lebih pendek:Sekarang, jika Anda ingin memetakan masing-masing karakter dalam string tetapi tidak peduli dengan string yang dihasilkan,
.map
biasanya lebih baik karena Anda dapat menyingkirkan.join``
:sumber
/\w/g
) yang tertarik, maka menggunakan penggantian akan jauh lebih baik seperti dalam demo ini .Menulis literal RegEx dengan
eval
Konstruktor regex bisa sangat besar karena nama panjangnya. Alih-alih, tulis literal dengan eval dan backtick:
Jika variabelnya
i
sama denganfoo
, ini akan menghasilkan:Ini sama dengan:
Anda juga dapat menggunakan
String.raw
untuk menghindari keharusan berulang kali melarikan diri dari garis miring terbalik\
Ini akan menampilkan:
Yang sama dengan:
Ingatlah!
String.raw
membutuhkan banyak byte dan kecuali Anda memiliki setidaknya sembilan backslash,String.raw
akan lebih lama.sumber
new
di sana, jadi menggunakan konstruktor sebenarnya lebih pendek untuk contoh kedua.forEach
vsfor
loopSelalu lebih suka
.map
apa pun untuk loop. Mudah, penghematan instan.sumber
Menggunakan penghitung yang tidak diinisialisasi dalam rekursi
Catatan : Sebenarnya, ini tidak khusus untuk ES6. Akan lebih masuk akal untuk menggunakan dan menyalahgunakan rekursi dalam ES6, karena sifat fungsi panah yang ringkas.
Adalah lebih umum untuk menemukan fungsi rekursif yang menggunakan penghitung yang
k
awalnya disetel ke nol dan bertambah pada setiap iterasi:Dalam keadaan tertentu, dimungkinkan untuk mengabaikan inisialisasi penghitung seperti itu dan ganti
k+1
dengan-~k
:Trik ini biasanya menghemat 2 byte .
Mengapa dan kapan itu bekerja?
Formula yang memungkinkannya adalah
~undefined === -1
. Jadi, pada iterasi pertama,-~k
akan dievaluasi1
. Pada iterasi berikutnya,-~k
pada dasarnya setara dengan-(-k-1)
yang samak+1
, setidaknya untuk bilangan bulat dalam kisaran [0 ... 2 31 -1].Namun Anda harus memastikan bahwa memiliki
k = undefined
iterasi pertama tidak akan mengganggu perilaku fungsi. Anda harus selalu mengingat bahwa sebagian besar operasi aritmatika yang melibatkanundefined
akan menghasilkanNaN
.Contoh 1
Diberi bilangan bulat positif
n
, fungsi ini mencari bilangan bulat terkecilk
yang tidak membagin
:Ini dapat disingkat menjadi:
Ini bekerja karena
n % undefined
adalahNaN
, yang falsy. Itulah hasil yang diharapkan pada iterasi pertama.[Tautan ke jawaban asli]
Contoh # 2
Diberikan bilangan bulat positif
n
, fungsi ini mencari bilangan bulatp
sedemikian rupa sehingga(3**p) - 1 == n
:Ini dapat disingkat menjadi:
Ini berfungsi karena
p
tidak digunakan sama sekali pada iterasi pertama (n<k
menjadi salah).[Tautan ke jawaban asli]
sumber
Fungsi ES6
Matematika
Math.cbrt(x)
menyimpan karakter daripadaMath.pow(x,1/3)
.3 karakter disimpan
Math.hypot(...args)
berguna ketika Anda membutuhkan akar kuadrat dari jumlah kuadrat dari argumen. Membuat kode ES5 untuk melakukannya jauh lebih sulit daripada menggunakan built-in.Fungsi
Math.trunc(x)
tidak akan membantu, karenax|0
lebih pendek. (Terima kasih, Mwr247!)Ada banyak properti yang membutuhkan banyak kode untuk dilakukan di ES5, tetapi lebih mudah di ES6:
Math.acosh
,asinh
,atanh
,cosh
,sinh
,tanh
. Menghitung ekuivalen hiperbolik fungsi trigonometri.Math.clz32
. Mungkin bisa dilakukan di ES5, tetapi sekarang lebih mudah. Menghitung angka nol di depan dalam representasi 32-bit angka.Ada lebih banyak, jadi aku hanya akan daftar beberapa:
Math.sign
,Math.fround
,Math.imul
,Math.log10
,Math.log2
,Math.log1p
.sumber
Math.trunc(x)
empat kali lebih lama darix|0
.Math.hypot(a,b) => Math.sqrt(a*a+b*b)
(3 byte lebih lama; semakin panjang dengan lebih banyak argumen),Math.sign(a) => (a>0)-(a<0)
(1 byte lebih pendek, tetapi membutuhkan tanda kurung di sekitarnya dalam beberapa kasus; mungkin tidak bekerja denganNaN
)Mengoptimalkan rentang konstan kecil untuk
map()
Konteks
map()
for
dapat diganti dengan:
atau lebih umum:
Array(N)
NB : Panjang kode panggilan balik
F(i)
tidak dihitung.Optimalisasi tanpa penghitung
NB : Panjang kode panggilan balik
F()
tidak dihitung.sumber
2**26
seharusnya2**29
?.keys()
, Anda tidak perlu lambda:[...Array(10).keys()].map(do_something_with)
Merusak penugasan tugas
ES6 memperkenalkan sintaks baru untuk penugasan yang merusak, yaitu memotong nilai menjadi beberapa bagian dan menempatkan setiap bagian ke variabel yang berbeda. Berikut ini beberapa contoh:
String dan array
Benda
Tugas-tugas ini juga dapat digunakan dalam parameter fungsi:
sumber
Namun cara lain untuk menghindari
return
Anda tahu Anda harus menggunakan eval untuk fungsi panah dengan banyak pernyataan dan pengembalian . Dalam beberapa kasus yang tidak biasa Anda dapat menyimpan lebih banyak menggunakan subfungsi bagian dalam.
Saya katakan tidak biasa karena
Hasil yang dikembalikan tidak boleh berupa ekspresi terakhir yang dievaluasi dalam loop
Harus ada (setidaknya) 2 inisialisasi yang berbeda sebelum loop
Dalam hal ini Anda dapat menggunakan subfungsi dalam tanpa kembali, memiliki salah satu dari nilai awal yang dilewatkan sebagai parameter.
Contoh Temukan kebalikan dari jumlah fungsi exp untuk nilai dalam rentang dari a ke b.
Jalan panjang - 55 byte
Dengan eval - 54 byte
Dengan fungsi bagian dalam - 53 byte
Perhatikan bahwa tanpa persyaratan batas kisaran yang lebih rendah
a
, saya dapat menggabungkan inisialisasi i dan r dan versi eval lebih pendek.sumber
a
(i,b)=>{for(r=0;i<=b;i++)r+=Math.exp(i);return 1/r}
return a/r
akan menjadi contoh yang lebih baik(a,b)=>1/eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i)")
dan dalam hal ini(i,b)=>1/eval("for(r=0;i<=b;)r+=Math.exp(i++)")
Menggunakan sintaks currying untuk fungsi diad dan rekursif
Fungsi diad
Setiap kali suatu fungsi mengambil dua argumen tepat tanpa nilai default, menggunakan sintaks currying menghemat satu byte.
Sebelum
Dipanggil dengan
f(a,b)
Setelah
Dipanggil dengan
f(a)(b)
Catatan : Posting ini di Meta mengonfirmasi validitas sintaks ini.
Fungsi rekursif
Menggunakan sintaks currying juga dapat menyimpan beberapa byte ketika fungsi rekursif mengambil beberapa argumen tetapi hanya perlu memperbarui beberapa di antara setiap iterasi.
Contoh
Fungsi berikut menghitung jumlah semua bilangan bulat dalam rentang
[a,b]
:Karena
a
tetap tidak berubah selama seluruh proses, kita dapat menyimpan 3 byte dengan menggunakan:Catatan : Seperti yang diperhatikan oleh Neil dalam komentar, fakta bahwa argumen tidak secara eksplisit diteruskan ke fungsi rekursif tidak berarti bahwa argumen tersebut harus dianggap tidak dapat diubah. Jika perlu, kita dapat memodifikasi
a
dalam kode fungsi dengana++
,a--
atau sintaksis yang serupa.sumber
a=>F=b=>a>b?0:a+++F(b)
, memodifikasia
untuk setiap panggilan rekursif. Ini tidak membantu dalam kasus itu tetapi mungkin menyimpan byte dalam kasus dengan lebih banyak argumen.Fungsi pengujian utama
Fungsi 28-byte berikut ini mengembalikan
true
untuk bilangan prima danfalse
untuk non-bilangan prima:Ini dapat dengan mudah dimodifikasi untuk menghitung hal-hal lain. Sebagai contoh, fungsi 39 byte ini menghitung jumlah bilangan prima kurang dari atau sama dengan angka:
Jika Anda sudah memiliki variabel
n
yang ingin diperiksa primality, fungsi primality dapat disederhanakan sedikit:Bagaimana itu bekerja
Catatan: Ini akan gagal dengan kesalahan "terlalu banyak rekursi" ketika dipanggil dengan input yang cukup besar, seperti 12345. Anda bisa menyiasatinya dengan loop:
sumber
x==1
mungkin bisax<2
untuk penghematan.1
atau0
(karenax
akan0
atau-1
, masing-masing)!~-x
untuk -0 byte.Array#concat()
dan operator spreadIni sangat tergantung pada situasi.
Menggabungkan banyak array.
Lebih suka fungsi concat kecuali kloning.
0 byte disimpan
3 byte terbuang
3 byte disimpan
6 byte disimpan
Lebih suka menggunakan array yang sudah ada
Array#concat()
.Mudah 4 byte disimpan
sumber
Kembalikan hasil antara
Anda tahu bahwa menggunakan operator koma Anda dapat mengeksekusi urutan ekspresi yang mengembalikan nilai terakhir. Tetapi menyalahgunakan sintaks array literal, Anda dapat mengembalikan nilai perantara apa pun. Ini berguna dalam .map () misalnya.
sumber
.join('')
bisa.join``
Tetapkan default parameter fungsi
Yang ini sangat berguna ...
Namun, pastikan untuk memahami bahwa sesuatu seperti
_=>_||'asdf'
lebih pendek ketika Anda hanya menyampaikan satu argumen (berguna) ke fungsi tersebut.sumber
_=>_||'asdf'
biasanya lebih pendek dalam banyak kasus"asdf"
untuk input""
(string kosong).undefined
, bahkan jika Anda secara eksplisit melewatkan nilai itu. Misalnya,[...Array(n)].map((a,b,c)=>b)
selalu lewatiundefined
untuka
, dan karena itu Anda dapat memberikan nilai default untuk itu (meskipun tidak dalam halb
).Gunakan
eval
bukan kawat gigi untuk fungsi panahFungsi panah luar biasa. Mereka mengambil bentuk
x=>y
, di manax
argumen dany
adalah nilai balik. Namun, jika Anda perlu menggunakan struktur kontrol, sepertiwhile
, Anda harus meletakkan kawat gigi, misalnya=>{while(){};return}
. Namun, kita bisa menyiasatinya; untungnya,eval
fungsi tersebut mengambil string, mengevaluasi string itu sebagai kode JS, dan mengembalikan ekspresi yang terakhir dievaluasi . Sebagai contoh, bandingkan keduanya:Kita dapat menggunakan ekstensi dari konsep ini untuk lebih mempersingkat kode kita: di mata
eval
, struktur kontrol juga mengembalikan ekspresi terakhir yang dievaluasi. Sebagai contoh:sumber
Operasi Logical Golf dalam ES6
"GLOE (S6)"
Logika Umum
Katakanlah Anda telah membuat pernyataan
s
dant
. Lihat apakah Anda dapat menggunakan salah satu dari penggantian berikut:(Ini mungkin tidak berfungsi jika pesanan salah; yaitu
+
dan*
memiliki urutan prioritas lebih rendah daripada||
dan&&
lakukan.)Juga, berikut adalah beberapa ekspresi logis yang berguna:
s
ataut
benar / XOR:s^t
s
dant
memiliki nilai kebenaran yang sama:!s^t
ataus==t
Logika array
Semua anggota
a
kondisi memuaskanp
:Setidaknya satu anggota dengan
a
kondisi memuaskanp
:Tidak ada anggota dari
a
kondisi memuaskanp
:!a.some(p)
.Elemen
e
ada dalam arraya
:Elemen
e
tidak tidak ada dalam arraya
:sumber
&&
dan||
sebagaix?y:x
danx?x:y
, masing-masing. Tapi saya bisa melihat bagaimana ini akan berguna dalam program yang lebih berbasis logika. Satu masalah+
adalah eg3
dan-3
keduanya benar, tetapi3+-3
tidak.-
bisa juga bekerja, jikas != t
.a.filter(t=>t==e).length==a.length
salah. Seharusnya!a.filter(t=>t==e).length
Mempersingkat pemanggilan fungsi berulang
Jika Anda telah berulang kali memanggil ke suatu fungsi dengan nama panjang, seperti manipulasi kanvas:
Cara tradisional untuk mempersingkatnya adalah dengan menggunakan nama fungsi:
Jika Anda memiliki cukup panggilan, cara yang lebih baik adalah membuat fungsi yang berfungsi untuk Anda:
Jika sebagian besar panggilan fungsi dirantai, Anda dapat membuat fungsi kembali dengan sendirinya, memungkinkan Anda untuk memotong dua byte dari setiap panggilan berikutnya:
Contoh penggunaan: 1 , 2
sumber
(l=::c.lineTo)(0,100)(100,100)(100,0)(0,0);c.stroke()
c.lineTo
tidak secara alami kembali sendiri)Mengikat operator
::
Operator bind dapat digunakan untuk membantu mempersingkat byte dari fungsi yang berulang:
Selain itu jika Anda ingin menggunakan fungsi dengan yang berbeda
this
misalnya:sumber
Menghindari koma saat menyimpan banyak data
Jika Anda memiliki banyak data (yaitu indeks, karakter, ...) yang harus Anda simpan dalam array, Anda mungkin lebih baik meninggalkan semua koma. Ini berfungsi baik jika setiap bagian data memiliki panjang string yang sama, 1 jelas menjadi optimal.
43 Bytes (baseline)
34 Bytes (tanpa koma)
Jika Anda ingin mengubah akses array Anda, Anda mungkin mengurangi ini lebih jauh, menyimpan nilai yang sama seperti:
27 Bytes (data yang sama, hanya mengubah akses array)
sumber