Alur kontrol adalah urutan eksekusi penafsir JavaScript pernyataan pribadi Anda. Jika skrip tidak menyertakan pernyataan yang mengubah alurnya, itu adalah dieksekusi dari awal hingga akhir, satu baris pada satu waktu. Struktur kontrol yang digunakan untuk menentukan apakah satu set pernyataan dieksekusi atau tidak berdasarkan serangkaian kriteria yang ditentukan, mengeksekusi serangkaian pernyataan berulang kali, atau urutan pernyataan.
Pernyataan bersyarat
Pernyataan bersyarat menentukan apakah kode harus dieksekusi berdasarkan satu atau beberapa
kondisi lainnya. Pernyataan kondisional mengeksekusi kode yang dikandungnya jika
kondisi terkait (atau kumpulan kondisi) bernilai true
. Jika tidak,
kode dilewati.
if
…else
Pernyataan if
mengevaluasi kondisi di dalam tanda kurung yang cocok yang
mengikuti. Jika kondisi di dalam tanda kurung bernilai true
, atribut
atau pernyataan blokir
yang mengikuti tanda kurung yang cocok
dieksekusi:
if ( true ) console.log( "True." );
> "True."
if ( true ) {
const myString = "True.";
console.log( myString );
}
> "True."
Jika kondisi di dalam tanda kurung bernilai false
, pernyataan yang
mengikutinya, akan diabaikan:
if ( false ) console.log( "True." );
Kata kunci else
yang tepat setelah pernyataan if
dan kata kunci
yang dieksekusi bersyarat menentukan pernyataan yang akan dieksekusi jika
Kondisi if
bernilai false
:
if ( false ) console.log( "True." )''
else console.log( "False" );
> "False."
Untuk merangkai beberapa pernyataan if
, Anda dapat membuat
pernyataan yang dijalankan bersyarat setelah else
pernyataan if
lainnya:
const myCondition = 2;
if ( myCondition === 5 ) console.log( "Five." );
else if ( myCondition === 2 ) console.log( "Two." );
Kami sangat menyarankan penggunaan sintaks{i> block statement<i} dengan mengikuti kondisional untuk
meningkatkan keterbacaan, tetapi klausa else if
sering kali merupakan pengecualian untuk hal ini:
if ( myCondition === 5 ) {
console.log( "Five." );
} else if ( myCondition === 3 ) {
console.log( "Three" );
} else {
console.log( "Neither five nor three." );
}
> "Neither five nor three."
Operator ternary
if
mengeksekusi pernyataan secara bersyarat. Operator ternary (lebih akurat
tetapi kurang umum disebut operator bersyarat terner) adalah singkatan yang digunakan
untuk mengeksekusi
ekspresi secara bersyarat. Sesuai dengan namanya, ternary
operator adalah satu-satunya operator JavaScript yang menggunakan tiga operand:
- Kondisi yang akan dievaluasi, diikuti dengan tanda tanya (
?
). - Ekspresi yang akan dieksekusi jika kondisi bernilai
true
, diikuti dengan titik dua (:
). - Ekspresi yang akan dieksekusi jika kondisi bernilai
false
.
Hal ini sering digunakan untuk menetapkan atau meneruskan nilai secara bersyarat:
const myFirstResult = true ? "First value." : "Second value.";
const mySecondResult = false ? "First value." : "Second value.";
myFirstResult;
> "First value."
mySecondResult;
> "Second value."
switch
…case
Gunakan pernyataan switch
untuk membandingkan nilai ekspresi dengan daftar
nilai potensial yang ditentukan menggunakan satu atau beberapa kata kunci case
. Sintaks ini adalah
tidak biasa karena berasal dari beberapa keputusan desain JavaScript yang paling awal.
Sintaksis switch
...case
menggunakan kata kunci switch
, diikuti dengan ekspresi untuk
dievaluasi dan digabungkan dalam tanda kurung, diikuti oleh sepasang tanda kurung kurawal yang cocok.
Isi switch
dapat berisi case
kata kunci, biasanya satu atau beberapa,
diikuti dengan ekspresi atau nilai, diikuti dengan titik dua (:
).
Saat penafsir mencapai case
dengan nilai yang cocok dengan ekspresi yang
dievaluasi dalam tanda kurung setelah kata kunci switch
, model ini akan mengeksekusi
pernyataan yang mengikuti klausa case
tersebut:
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "True."
Semua pernyataan setelah case
yang cocok akan dijalankan, meskipun jika
yang disertakan dalam pernyataan blok.
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
let myVariable = "True.";
console.log( myVariable );
}
> "True."
Salah satu kesalahan penggunaan switch…case
adalah, setelah kecocokan ditemukan,
Penerjemah JavaScript mengeksekusi apa pun pernyataan yang mengikuti case
yang cocok,
bahkan yang ada dalam klausa case
lainnya. Hal ini disebut "tumpang-tindih" ke
case
berikutnya:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "False."
> "True."
Untuk mencegah kegagalan, akhiri setiap kasus dengan kata kunci break
, yang
langsung menghentikan evaluasi isi switch
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
break;
case true:
console.log( "True." );
break;
}
> "False."
Jika tidak ada case
yang cocok dengan nilai kondisional, switch
akan memilih default
jika ada:
switch ( 20 ) {
case 5:
console.log( "The value was five." );
break;
case 10:
console.log( "The value was ten." );
break;
default:
console.log( "The value was something unexpected." );
}
> "The value was something unexpected."
Namun, fallback juga berlaku untuk default
, yang berpotensi menyebabkan
hasil yang tidak diharapkan. Untuk memperbaikinya, akhiri pernyataan default
Anda dengan break
,
atau menempatkannya di urutan terakhir dalam daftar kasus.
switch ( 20 ) {
default:
console.log( "The value was something unexpected." );
case 10:
console.log( "The value was ten." );
break;
case 5:
console.log( "The value was five." );
break;
}
> The value was something unexpected.
> The value was ten.
Karena klausa case
tidak memerlukan
pernyataan blokir untuk pengelompokan
beberapa pernyataan, klausa case
dan default
tidak dibuat
cakupan leksikal mandiri:
let myVariable;
switch ( true ) {
case true:
let myVariable = "True.";
break;
default:
let myVariable = "False.";
break;
}
> Uncaught SyntaxError: redeclaration of let myVariable
Untuk mengelola cakupan, gunakan pernyataan blok:
let myVariable;
switch ( true ) {
case true: {
let myVariable = "True.";
break;
}
default: {
let myVariable = "False.";
break;
}
}
Loop dan iterasi
{i>Loop <i}memungkinkan Anda mengulangi serangkaian pernyataan selama suatu kondisi terpenuhi, atau hingga suatu kondisi terpenuhi. Menggunakan loop untuk menjalankan serangkaian petunjuk yang telah diperbaiki berkali-kali, hingga hasil tertentu tercapai, atau hingga penafsir mencapai akhir dari struktur data iterable (misalnya, elemen akhir dalam array, peta, atau set, properti akhir objek, atau karakter terakhir dalam suatu {i>string<i}).
Pengulangan menginterupsi bagian "atas ke bawah" alur eksekusi skrip dengan melakukan iterasi atas satu set pernyataan hingga satu atau lebih kondisi terpenuhi, atau tidak lagi dipenuhi, tergantung pada sintaks yang digunakan untuk membuat loop. Setelah loop berakhir, eksekusi dilanjutkan ke pernyataan yang mengikutinya. Dalam contoh berikut, pernyataan dalam isi loop dieksekusi tiga kali sebelum penerjemah akan melanjutkan:
let iterationCount = 0;
console.log( "Pre-loop." );
while( iterationCount < 3 ) {
iterationCount++;
console.log( "Loop iteration." );
}
console.log( "Continuing on." );
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Continuing on."
Jika kondisi tidak dapat dipenuhi selama eksekusi loop, loop akan berlanjut. tanpa batas waktu. Loop tak terbatas ini adalah kesalahan pemrograman umum yang dapat menyebabkan thread eksekusi utama untuk menjeda tanpa batas waktu, atau bahkan membuat tab browser error.
Contoh berikut dijalankan selama nilai boolean true
tetap ada
true
. Karena nilai boolean tidak dapat diubah,
hal ini menciptakan loop terus-menerus.
console.log( "Pre-loop." );
while( true ) {
console.log( "Loop iteration." );
}
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
…
Hindari loop tanpa henti dalam kode produksi Anda. Jika Anda secara tidak sengaja membuat satu selama pengembangan, Anda dapat memperbaikinya dengan menutup tab {i>browser<i} yang sedang dijalankan , memperbarui kode Anda sehingga loop tidak lagi tak terbatas, dan membuka kembali kami.
while
Loop while
dibuat menggunakan kata kunci while
, diikuti dengan sepasang
cocok dengan tanda kurung yang berisi
kondisi yang akan dievaluasi. Jika yang ditentukan
kondisi awalnya bernilai true
, pernyataan (atau
pernyataan blokir) yang mengikuti
tanda kurung itu
dieksekusi. Jika tidak, loop tidak pernah berjalan. Setelah setiap
iterasi, kondisi akan dievaluasi ulang. Jika masih true
, loop
berulang.
let iterationCount = 0;
while( iterationCount < 3 ) {
iterationCount++;
console.log( `Loop ${ iterationCount }.` );
}
> "Loop 1."
> "Loop 2."
Jika penafsir menemukan pernyataan continue
dalam loop while
, penafsir akan menghentikannya.
iterasi, mengevaluasi ulang kondisinya, dan melanjutkan loop jika memungkinkan:
let iterationCount = 0;
while( iterationCount <= 5 ) {
iterationCount++;
if( iterationCount === 3 ) {
continue;
}
console.log( `Loop ${ iterationCount }.` );
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Loop 4."
> "Loop 5."
> "Loop ended."
Jika penafsir menemukan pernyataan break
dalam loop while
, iterasi tersebut
berhenti dan kondisi tidak dievaluasi ulang, sehingga penerjemah dapat melanjutkan:
let iterationCount = 1;
while( iterationCount <= 5 ) {
if( iterationCount === 3 ) {
console.log(`Iteration skipped.``);`
break;
}
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Iteration skipped.
> "Loop ended."
Anda dapat menggunakan while
untuk melakukan iterasi beberapa kali, seperti yang terlihat dalam
contoh sebelumnya, tetapi kasus penggunaan yang paling umum untuk while
adalah loop
panjang tidak tentu:
let randomize = () => Math.floor( Math.random() * 10 );
let randomNum = randomize();
while( randomNum !== 3 ){
console.log( `The number is not ${ randomNum }.` );
randomNum = randomize();
}
console.log( `The correct number, ${ randomNum }, was found.` );
> "The number is not 0."
> "The number is not 6."
> "The number is not 1."
> "The number is not 8."
> "The correct number, 3, was found."
do
…while
do
...while
adalah varian dari loop while
yang menggunakan kondisional
evaluasi terjadi di akhir setiap iterasi loop. Ini berarti
body loop selalu dieksekusi minimal sekali.
Untuk membuat loop do
...while
, gunakan kata kunci do
yang diikuti dengan pernyataan
(atau pernyataan blok) yang akan
dijalankan pada setiap iterasi loop. Segera setelah
pernyataan itu, tambahkan
while
dan cocok dengan tanda kurung yang berisi kondisi yang akan dievaluasi. Kapan
kondisi ini tidak lagi bernilai true
, loop akan berakhir.
let iterationCount = 1;
do {
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
} while ( iterationCount < 3 );
> "Loop 1."
> "Loop 2."
> "Loop 3."
Seperti halnya loop while
, kasus penggunaan yang paling umum untuk do
...while
adalah loop dari
panjang tidak tentu:
let randomNum;
do {
randomNum = ( () => Math.floor( Math.random() * 10 ) )();
console.log( `Is the number ${ randomNum }?` );
} while ( randomNum !== 3 );
console.log( `Yes, ${ randomNum } was the correct number.` );
> "Is the number 9?"
> "Is the number 2?"
> "Is the number 8?"
> "Is the number 2?"
> "Is the number 3?"
> "Yes, 3 was the correct number."
for
Gunakan loop for
untuk melakukan iterasi pada kuantitas yang diketahui. Dalam codebase lama, ini adalah
yang sering digunakan untuk mengulangi elemen dalam sebuah array.
Untuk membuat loop for
, gunakan kata kunci for
, yang diikuti dengan sepasang tanda kurung
yang menerima tiga ekspresi berikut secara berurutan dan dipisahkan oleh
titik koma:
- Ekspresi yang akan dievaluasi saat loop dimulai
- Kondisi yang menentukan apakah loop harus dilanjutkan atau tidak
- Ekspresi yang akan dieksekusi pada akhir setiap loop
Setelah tanda kurung ini, tambahkan pernyataan (biasanya pernyataan blokir) menjadi yang dijalankan selama loop.
for( let i = 0; i < 3; i++ ) {
console.log( "This loop will run three times.")
}
Ekspresi pertama melakukan inisialisasi variabel yang bertindak sebagai penghitung. Ini
ekspresi dievaluasi sekali, sebelum iterasi pertama loop. Anda dapat
lakukan inisialisasi variabel ini menggunakan let
(atau var
, secara historis) seperti yang lainnya
variabel, dan cakupannya adalah
isi dari loop. Variabel-variabel ini dapat memiliki
ID yang valid, tetapi sering disebut i
untuk "iterasi" atau "indeks".
Hal ini tampaknya bertentangan dengan
praktik terbaik untuk nama ID yang dapat diprediksi,
tetapi konvensi ini cukup mapan untuk
jelas bagi pengembang lain di
secara sekilas. Karena koleksi yang diindeks tidak diindeks,
variabel ini hampir selalu memiliki nilai awal 0
.
Seperti halnya bentuk loop lainnya, kondisinya adalah ekspresi yang menentukan
apakah loop harus dijalankan. Ini paling sering digunakan untuk menetapkan nilai
ke penghitung iterasi. Penafsir mengevaluasi kondisi sebelum
mengeksekusi loop for
untuk pertama kalinya.Jika kondisi awal tidak
dievaluasi ke true
, isi loop tidak dijalankan.
Ekspresi akhir dieksekusi pada akhir setiap iterasi melalui loop. Ini biasanya digunakan untuk menambah {i>ID <i}satu per satu.
Anda akan sering melihat loop for
melakukan iterasi melalui array di
codebase. Dalam kasus ini, kondisi yang ditentukan untuk melanjutkan loop adalah
jumlah iterasi kurang dari atau sama dengan panjang array yang diiterasi
dilewatkan. Variabel yang digunakan untuk melacak jumlah iterasi
ini digunakan untuk melihat
nilai yang terkait dengan indeks itu dalam {i>array<i}, memungkinkan setiap elemen dalam
himpunan (array) yang akan ditindaklanjuti secara berurutan:
var myArray = [ true, false, true ];
for( let i = 0; i <= myArray.length; i++ ) {
console.log( myArray[ i ] );
}
> true
> false
> true
Pendekatan ini tidak lagi digunakan dan mendukung pendekatan yang lebih modern untuk melakukan loop melalui struktur data yang dapat dikonversi.
for
[...] of
[...]
Gunakan loop for
...of
... untuk melakukan iterasi pada nilai yang disimpan di
struktur data iterable, seperti array, set, atau peta.
Loop for
...of
... menggunakan kata kunci for
diikuti dengan sepasang tanda kurung
berisi variabel, diikuti dengan of
, lalu struktur datanya akan diiterasi
berakhir. Variabel dapat berupa deklarasi yang dijalankan di sini menggunakan let
, const
, atau
var
, variabel yang dideklarasikan sebelumnya dalam cakupan saat ini, yaitu objek
properti, atau instance dari
penugasan destrukturisasi.
Ini berisi nilai elemen yang sesuai dengan iterasi saat ini
dari loop.
const myIterable = [ true, false, true ];
for( const myElement of myIterable ) {
console.log( myElement );
}
> true
> false
> true
Dalam contoh ini, penggunaan const
untuk myElement
berfungsi meskipun myElement
diberi nilai baru dalam setiap iterasi loop. Hal ini karena variabel
yang dideklarasikan dengan let
atau const
dicakup dalam pernyataan blok dalam
. Variabel diinisialisasi pada awal setiap iterasi, dan dihapus pada
akhir dari iterasi itu.
for
...in
...
Gunakan loop for
...in
... untuk melakukan iterasi pada properti yang dapat dienumerasi dari suatu objek,
termasuk properti turunan yang
dapat dienumerasi. Seperti halnya loop for
...of
...,
Loop for
...in
... menggunakan kata kunci for
diikuti dengan sepasang tanda kurung
berisi variabel yang berisi nilai
kunci properti yang sesuai
dengan iterasi loop saat ini. Variabel ini diikuti oleh
Kata kunci in
, lalu objek yang diiterasi:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
console.log( myKey );
}
> "myProperty"
> "mySecondProperty"
Sekali lagi, meskipun nilai myKey
berubah dengan setiap iterasi loop,
Anda dapat menggunakan const
tanpa error karena variabel dihapus secara efektif
di akhir setiap iterasi, lalu dibuat ulang di awal.
Nilai yang terkait dengan setiap kunci properti tidak tersedia langsung untuk
for
...in
.... Namun, karena {i>loop <i}memiliki
akses kunci properti pada
setiap iterasi, Anda dapat menggunakan
kunci itu untuk "mencari" nilainya:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "mySecondProperty : false"
Properti yang diwarisi dari konstruktor bawaan tidak dapat dihitung, artinya
for
...in
... tidak melakukan iterasi melalui properti yang diwarisi dari Object
. Namun, setiap properti yang bisa
dienumerasi dalam atribut
rantai prototipe disertakan:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "protoProperty : true"
JavaScript menyediakan metode bawaan untuk menentukan apakah suatu properti merupakan
properti langsung objek daripada properti pada prototipe objek
jaringan: mesin modern
Metode Object.hasOwn()
dan Object.prototype.hasOwnProperty()
lama. Ini
mengevaluasi apakah properti yang ditentukan diwarisi (atau tidak dideklarasikan),
menampilkan true
hanya untuk properti langsung dari objek yang ditentukan:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
if ( Object.hasOwn( myObject, myKey ) ) {
console.log( `${ myKey } : ${ myValue }` );
}
}
> "myProperty : true"
Ada juga tiga metode statis yang masing-masing mengembalikan Array yang terdiri dari
Kunci yang dapat dihitung objek (Object.keys()
), nilai (Object.values()
), atau
pasangan nilai kunci (Object.entries()
):
const myObject = { "myProperty" : true, "mySecondProperty" : false };
Object.keys( myObject );
> Array [ "myProperty", "mySecondProperty" ]
Hal ini memungkinkan Anda melakukan iterasi kunci Objek, nilai, atau pasangan nilai kunci (menggunakan penugasan destrukturisasi) tanpa menyertakan properti yang dimiliki oleh prototipe Object tersebut:
const myPrototype = { "protoProperty" : "Non-enumerable property value." };
const myObject = Object.create( myPrototype, {
myProperty: {
value: "Enumerable property value.",
enumerable: true
}
});
for ( const propKey of Object.keys( myObject ) ) {
console.log( propKey );
}
> "myProperty"
for ( const propValue of Object.values( myObject ) ) {
console.log( propValue );
}
> "Enumerable property value."
for ( const [ propKey, propValue ] of Object.entries( myObject ) ) {
console.log( `${ propKey } : ${ propValue }` );
}
> "myProperty : Enumerable property value."
forEach()
Metode forEach()
yang disediakan oleh Array,
Peta, Tetapkan,
dan konstruktor NodeList menyediakan cara pintas
yang berguna untuk melakukan iterasi pada data
dalam konteks fungsi callback. Tidak seperti bentuk loop lainnya,
loop yang dibuat dengan metode forEach()
apa pun tidak dapat diputus menggunakan break
atau
continue
.
forEach
adalah metode yang dimiliki oleh prototipe setiap struktur data. Setiap forEach
mengharapkan fungsi callback sebagai argumen, walaupun keduanya sedikit berbeda
suku argumen yang disertakan ketika fungsi itu dipanggil. Kedua, opsional
menentukan nilai this
yang akan digunakan sebagai konteks pemanggil untuk
fungsi callback.
Fungsi callback yang digunakan dengan Array.forEach
menyediakan parameter yang berisi
nilai elemen saat ini, indeks elemen saat ini, dan array metode forEach
dipanggil:
const myArray = [ true, false ];
myArray.forEach( ( myElement, i, originalArray ) => {
console.log( i, myElement, originalArray );
});
> 0 true Array(3) [ true, false ]
> 1 false Array(3) [ true, false ]
Fungsi callback yang digunakan dengan Map.forEach
menyediakan parameter yang berisi
nilai yang terkait dengan elemen saat ini, kunci yang terkait dengan elemen saat ini
, dan Map tempat metode forEach
dipanggil:
const myMap = new Map([
['myKey', true],
['mySecondKey', false ],
]);
myMap.forEach( ( myValue, myKey, originalMap ) => {
console.log( myValue, myKey, originalMap );
});
> true "myKey" Map { myKey → true, mySecondKey → false }
> false "mySecondKey" Map { myKey → true, mySecondKey → false }
Callback Set.forEach
menyertakan parameter yang serupa. Karena Set tidak memiliki
indeks atau kunci yang berbeda dari nilai, argumen kedua justru menyediakan
nilai yang redundan dan dapat diabaikan, secara ketat
agar {i>syntax<i} tetap konsisten dengan
metode forEach
lainnya.
const mySet = new Set([ true, false ]);
mySet.forEach( ( myValue, myKey, originalSet ) => {
console.log( myValue, myKey, originalSet );
});
> true true Set [ true, false ]
> false false Set [ true, false ]
Iterator
Iterable adalah struktur data apa pun yang terdiri dari elemen individual yang dapat
melakukan iterasi menggunakan pendekatan
yang telah dijelaskan sebelumnya. iterator adalah
objek iterable yang mengikuti protokol iterator, yang berarti ia harus mengimplementasikan
metode next()
yang maju melalui elemen-elemen yang dikandungnya satu per satu,
setiap kali metode tersebut dipanggil, menampilkan objek untuk setiap metode
ke dalam format tertentu.
Struktur data iterable bawaan JavaScript (seperti
Array,
Peta, dan
Set) bukan iterator di dan dari
sendiri, tetapi mereka semua mewarisi metode iterator
, yang dapat diakses menggunakan
@@iterator
Simbol terkenal,
yang mengembalikan objek iterator yang dibuat dari struktur data iterable:
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterable;
> (3) [1, 2, 3]
myIterator;
> Array Iterator {}
Memanggil metode next()
pada iterator akan melalui elemen-elemen yang
berisi satu per satu, di mana setiap panggilan menampilkan objek yang berisi dua
properti: value
, yang berisi nilai elemen saat ini, dan
done
, boolean yang memberi tahu kita apakah iterator telah meneruskan elemen terakhir dalam
struktur data. Nilai done
adalah true
hanya saat panggilan ke next()
mengakibatkan upaya untuk mengakses elemen di luar elemen terakhir dalam
iterator.
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: undefined, done: true }
Fungsi Generator
Gunakan kata kunci function*
(perhatikan tanda bintang) untuk mendeklarasikan generator
atau menentukan ekspresi fungsi generator:
function* myGeneratorFunction() { };
Seperti iterator, fungsi generator mempertahankan status. Memanggil fungsi generator menampilkan objek Generator baru tetapi tidak langsung jalankan kode dalam isi fungsi:
function* myGeneratorFunction() {
console.log( "Generator function body ")
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject;
> Generator { }
typeof myGeneratorObject;
> "object"
Objek generator mengikuti protokol iterator. Nilai setiap panggilan ke
next()
pada fungsi generator yang ditampilkan ditentukan oleh ekspresi yield
,
yang menjeda eksekusi fungsi generator dan mengembalikan nilai
yang berisi kata kunci yield
. Panggilan nanti ke next()
melanjutkan eksekusi fungsi, berhenti sejenak pada ekspresi yield
berikutnya dan
yang menampilkan nilai yang terkait.
function* myGeneratorFunction() {
yield "My first yielded value.";
yield "My second yielded value.";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: "My first yielded value.", done: false }
myGeneratorObject.next();
> Object { value: "My second yielded value.", done: false }
Saat next()
dipanggil setelah tidak ada nilai lebih lanjut yang ditentukan menggunakan yield
,
return
, atau throw
(jika terjadi error), fungsi lainnya
body dieksekusi, dan Objek yang ditampilkan memiliki value
undefined
dan done
properti true
:
function* myGeneratorFunction() {
console.log( "Start of the generator function." );
yield "First";
console.log( "Second part of the generator function." );
yield "Second";
console.log( "Third part of the generator function." );
yield "Third";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> "Start of the generator function."
> Object { value: "First", done: false }
myGeneratorObject.next();
> "Second part of the generator function."
> Object { value: "Second", done: false }
myGeneratorObject.next();
> "Third part of the generator function."
> Object { value: "Third", done: false }
myGeneratorObject.next();
> Object { value: undefined, done: true }
Gunakan next()
hanya pada Objek yang ditampilkan oleh fungsi generator, bukan
fungsi generator itu sendiri. Jika tidak, setiap panggilan ke fungsi generator
membuat Object generator baru:
function* myGeneratorFunction() {
yield "First";
yield "Second";
};
myGeneratorFunction().next();
> Object { value: "First", done: false }
myGeneratorFunction().next();
> Object { value: "First", done: false }
Seperti fungsi lainnya, fungsi generator akan berhenti saat menemukan return
kata kunci. Metode ini kemudian menampilkan Objek ke konteks pemanggil yang berisi
nilai yang ditampilkan dan properti done
dengan nilai true
.
function* myGeneratorFunction() {
yield 1;
yield 2;
return 3;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next().done;
> Object { value: 1, done: false }
myGeneratorObject.next().done;
> Object { value: 2, done: false }
myGeneratorObject.next();
> Object { value: 3, done: true }
Ekspresi yield
dapat mengambil beberapa semantik ID,
memungkinkan "komunikasi" dua arah dari dan kembali ke bagian yang ditangguhkan
fungsi generator. Saat nilai diteruskan ke metode next()
generator sebagai
argumen, argumen ini menggantikan nilai yang terkait dengan argumen sebelumnya,
Ekspresi yield
:
function* myGeneratorFunction() {
const firstYield = yield;
yield firstYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
Perlu diingat bahwa ini menggantikan seluruh ekspresi yang terkait dengan
sebelumnya yield
, dan tidak hanya menetapkan ulang nilai yield
sebelumnya ke
nilai yang ditentukan dalam next()
:
function* myGeneratorFunction() {
const firstYield = yield;
const secondYield = yield firstYield + 100;
yield secondYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 10 ); // Can be thought of as changing the value of the `firstYield` variable to `10
> Object { value: 110, done: false }
myGeneratorObject.next( 20 ); // Can be thought of as changing the value of the `secondYield` variable to `20`, _not_ `20 + 100;`
> Object { value: 30, done: false }
Argumen apa pun yang diteruskan ke panggilan pertama ke next()
akan diabaikan, karena tidak ada
ekspresi yield
sebelumnya untuk menerima nilai tersebut. Seperti fungsi lainnya,
argumen yang diteruskan ke panggilan fungsi generator awal tersedia di seluruh
cakupan isi fungsi generator:
function* myGeneratorFunction( startingValue ) {
let newValue = yield startingValue + 1;
newValue = yield newValue + 10;
yield startingValue + 20;
};
const myGeneratorObject = myGeneratorFunction( 2 );
myGeneratorObject.next( 1 );
> Object { value: 3, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
myGeneratorObject.next( 10 );
Object { value: 22, done: false }
Operator yield*
(perhatikan tanda bintang) digunakan dengan iterable, seperti
fungsi generator lain, untuk melakukan iterasi dan menghasilkan setiap nilai operand-nya
akan menampilkan:
function* mySecondaryGenerator() {
yield 2;
yield 3;
}
function* myGenerator() {
yield 1;
yield* mySecondaryGenerator();
yield 4;
return 5;
}
const myIterator = myGenerator();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: 4, done: false }
myIterator.next();
> Object { value: 5, done: true }
JavaScript Asinkron
Meskipun pada dasarnya JavaScript bersifat sinkron. dalam eksekusinya, ada mekanisme yang memungkinkan pengembang untuk memanfaatkan loop peristiwa untuk menjalankan dan asinkron.
Promise
Promise adalah placeholder untuk nilai yang tidak diketahui kapan promise tersebut dibuat. Ini adalah kontainer yang menentukan operasi asinkron, persyaratan oleh operasi dianggap berhasil atau gagal, tindakan yang harus diambil dalam kedua kasus tersebut, dan nilai yang dihasilkan.
Membuat instance Promise menggunakan operator new
dengan Promise
bawaan
fungsi konstruktor. Konstruktor ini menerima fungsi yang disebut executor
sebagai argumen. Fungsi eksekutor itu biasanya digunakan
untuk melakukan satu atau lebih
tindakan asinkron, kemudian menentukan persyaratan yang akan digunakan untuk Promise
dianggap berhasil
dipenuhi atau ditolak. Promise didefinisikan sebagai pending
saat fungsi eksekutor berjalan. Setelah eksekutor selesai, sebuah Promise
dianggap terpenuhi (atau diselesaikan, dalam beberapa sumber dokumentasi) jika
fungsi eksekutor dan tindakan asinkron yang dilakukannya selesai
berhasil, dan ditolak jika fungsi eksekutor mengalami error, atau
tindakan asinkron yang dilakukan akan gagal. Setelah Promise terpenuhi atau
ditolak, hal tersebut dianggap selesai.
const myPromise = new Promise( () => { });
Konstruktor memanggil fungsi eksekutor dengan dua argumen. Argumen tersebut adalah fungsi yang memungkinkan Anda memenuhi atau menolak Promise secara manual:
const myPromise = new Promise( ( fulfill, reject ) => { });
Fungsi yang digunakan untuk memenuhi atau menolak Promise dipanggil dengan hasil Promise sebagai argumen (biasanya kesalahan karena penolakan):
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was successful." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 10000);
});
myPromise;
> Promise { <state>: "pending" }
myPromise;
> Promise { <state>: "fulfilled", <value>: "This Promise was successful." }
Perantaian Promise
Objek Promise yang dihasilkan dapat ditindaklanjuti menggunakan then()
, catch()
, dan
Metode finally()
diwarisi dari konstruktor Promise. Tiap-tiap
metode akan menampilkan Promise, yang dapat segera ditindaklanjuti dengan then()
,
catch()
, atau finally()
lagi, memungkinkan Anda merantai Promise yang dihasilkan.
then()
menyediakan dua fungsi callback sebagai argumen. Gunakan yang pertama untuk memenuhi
Promise yang dihasilkan, dan yang kedua untuk menolaknya. Kedua metode menerima satu
yang memberikan nilai pada Promise.
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise.then( successfulResult => console.log( successfulResult ), failedResult => console.error( failedResult ) );
> "This Promise was successful."
Anda juga dapat menggunakan then()
untuk menangani status yang terpenuhi saja, dan catch
untuk
menangani status ditolak. Panggil catch
dengan satu argumen yang berisi
yang diberikan dalam metode penolakan Promise:
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = false;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise
.then( fulfilledResult => console.log(fulfilledResult ) )
.catch( rejectedResult => console.log( rejectedResult ) )
.finally( () => console.log( "The Promise has settled." ) );
> "Error: This Promise has been rejected."
> "The Promise has settled."
Tidak seperti then
dan catch
, yang memungkinkan fungsi pengendali berjalan saat Promise
terpenuhi atau ditolak, fungsi yang diteruskan sebagai argumen ke finally
akan dipanggil terlepas dari apakah Promise terpenuhi atau ditolak.
Fungsi pengendali dipanggil tanpa argumen karena tidak dimaksudkan untuk
dengan nilai yang diteruskan dari Promise, hanya untuk mengeksekusi kode setelah
Promise selesai.
Serentak
Konstruktor Promise menyediakan empat metode untuk bekerja dengan beberapa metode terkait
Promise, menggunakan iterable yang berisi objek Promise. Ini
masing-masing menampilkan Promise, yang terpenuhi atau ditolak berdasarkan status
dari Promise yang diteruskan kepadanya. Misalnya, Promise.all()
membuat Promise
yang hanya terpenuhi jika setiap Promise yang diteruskan ke metode tersebut terpenuhi:
const firstPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const secondPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const thirdPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const failedPromise = new Promise( ( fulfill, reject ) => reject( "Failed.") );
const successfulPromises = [ firstPromise, secondPromise, thirdPromise ];
const oneFailedPromise = [ failedPromise, ...successfulPromises ];
Promise.all( successfulPromises )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> Array(3) [ "Successful. ", "Successful. ", "Successful. " ]
Promise.all( oneFailedPromise )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> "Failed."
Metode konkurensi Promise adalah sebagai berikut:
Promise.all()
- Terpenuhi hanya jika semua Promise yang disediakan terpenuhi.
Promise.any()
- Terpenuhi jika salah satu Promise yang disediakan terpenuhi, dan hanya ditolak jika semua Promise ditolak.
Promise.allSettled()
- Terpenuhi saat Promise telah selesai, terlepas dari hasilnya.
Promise.race()
- Ditolak atau dipenuhi berdasarkan hasil dari Janji pertama yang harus diselesaikan, mengabaikan semua Promise yang ditetapkan nanti.
async
/await
Saat Anda menggunakan kata kunci async
sebelum deklarasi fungsi
atau ekspresi fungsi, nilai apa pun
nilai yang ditampilkan fungsi ditampilkan sebagai Promise yang terpenuhi yang berisi nilai tersebut
dengan sejumlah nilai. Dengan demikian, Anda dapat menjalankan dan mengelola operasi asinkron menggunakan
sebagai pengembangan sinkron.
async function myFunction() {
return "This is my returned value.";
}
myFunction().then( myReturnedValue => console.log( myReturnedValue ) );
> "This is my returned value."
Ekspresi await
menjeda eksekusi fungsi asinkron saat
Promise terkait diselesaikan. Setelah Promise diselesaikan, nilai
ekspresi await
adalah nilai Promise yang terpenuhi atau ditolak.
async function myFunction() {
const myPromise = new Promise( ( fulfill, reject ) => { setTimeout( () => fulfill( "Successful. "), 5000 ); });
const myPromisedResult = await myPromise;
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "Successful."
Setiap nilai non-Promise yang disertakan dalam ekspresi await
ditampilkan sebagai
Promise terpenuhi:
async function myFunction() {
const myPromisedResult = await "String value.";
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "String value."
Menguji pemahaman Anda
Jenis loop apa yang Anda gunakan untuk melakukan iterasi pada kuantitas yang diketahui?
for
while
do...while