[Medium] π Hoisting
1. Apa itu Hoisting?β
Eksekusi JavaScript dapat dilihat sebagai dua fase: pembuatan (creation) dan eksekusi (execution).
var name = 'Pitt';
console.log(name); // mencetak Pitt
Dengan hoisting, engine secara konseptual menangani deklarasi terlebih dahulu dan penugasan kemudian:
// pembuatan
var name;
// eksekusi
name = 'Pitt';
console.log(name);
Fungsi berperilaku berbeda dari variabel. Deklarasi fungsi diikat selama fase pembuatan:
getName();
function getName() {
console.log('string'); // mencetak string
}
Ini berfungsi karena deklarasi fungsi di-hoist sebelum pemanggilan runtime:
// pembuatan
function getName() {
console.log('string');
}
// eksekusi
getName();
Catatan: dengan function expression, urutan deklarasi dan penugasan tetap penting.
Pada fase pembuatan, deklarasi fungsi memiliki prioritas lebih tinggi daripada deklarasi variabel.
Benarβ
name = 'Yumy';
console.log(name); // mencetak Yumy
var name;
// --- Setara dengan ---
// pembuatan
var name;
// eksekusi
name = 'Yumy';
console.log(name); // mencetak Yumy
Salahβ
console.log(name); // mencetak undefined
var name = 'Jane';
// --- Setara dengan ---
// pembuatan
var name;
// eksekusi
console.log(name); // mencetak undefined, karena penugasan belum terjadi
name = 'Pitt';
2. Apa yang dicetak untuk name?β
whoseName();
function whoseName() {
if (name) {
name = 'Nini';
}
}
var name = 'Pitt';
console.log(name);
Jawabanβ
// pembuatan
function whoseName() {
if (name) {
name = 'Nini';
}
}
var name;
// eksekusi
whoseName();
name = 'Pitt';
console.log(name); // mencetak Pitt
Di dalam whoseName(), name dimulai sebagai undefined, sehingga cabang if (name) tidak dijalankan.
Setelah itu, name diberi nilai 'Pitt', sehingga output akhir tetap Pitt.
3. Deklarasi Fungsi vs Deklarasi Variabel: Prioritas Hoistingβ
Pertanyaan: fungsi dan variabel dengan nama yang samaβ
Prediksi output dari kode ini:
console.log(foo);
var foo = '1';
function foo() {}
Jawaban yang salah yang umumβ
Banyak orang berpikir hasilnya akan:
- Mencetak
undefined(mengasumsikanvardi-hoist lebih dulu) - Mencetak
'1'(mengasumsikan penugasan sudah berlaku) - Menghasilkan error (mengasumsikan konflik nama yang sama)
Output sebenarnyaβ
[Function: foo]
Mengapa?β
Pertanyaan ini menguji aturan prioritas hoisting:
Prioritas hoisting: deklarasi fungsi > deklarasi variabel
// Kode asli
console.log(foo);
var foo = '1';
function foo() {}
// Setara setelah hoisting
// Fase 1: pembuatan (hoisting)
function foo() {} // 1. deklarasi fungsi di-hoist lebih dulu
var foo; // 2. deklarasi variabel di-hoist (tidak menimpa fungsi)
// Fase 2: eksekusi
console.log(foo); // foo adalah fungsi di sini
foo = '1'; // 3. penugasan menimpa fungsi
Konsep Kunciβ
1. Deklarasi fungsi di-hoist sepenuhnya
console.log(myFunc); // [Function: myFunc]
function myFunc() {
return 'Hello';
}
2. var hanya meng-hoist deklarasi, bukan penugasan
console.log(myVar); // undefined
var myVar = 'Hello';
3. Ketika deklarasi fungsi dan variabel berbagi nama yang sama
// Urutan hoisting
function foo() {} // fungsi di-hoist dan diinisialisasi lebih dulu
var foo; // deklarasi di-hoist, tapi tidak menimpa fungsi
// Oleh karena itu foo tetap fungsi
console.log(foo); // [Function: foo]
Alur Eksekusi Lengkapβ
// Kode asli
console.log(foo); // ?
var foo = '1';
function foo() {}
console.log(foo); // ?
// ======== Setara ========
// Fase pembuatan (hoisting)
function foo() {} // 1οΈβ£ deklarasi fungsi di-hoist sepenuhnya
var foo; // 2οΈβ£ deklarasi variabel di-hoist tapi tidak mengganti fungsi
// Fase eksekusi
console.log(foo); // [Function: foo]
foo = '1'; // 3οΈβ£ penugasan sekarang menimpa fungsi
console.log(foo); // '1'
Pertanyaan Lanjutanβ
Pertanyaan A: apakah urutan mengubah hasil?β
console.log(foo); // ?
function foo() {}
var foo = '1';
console.log(foo); // ?
Jawaban:
[Function: foo] // output pertama
'1' // output kedua
Alasan: urutan kode sumber tidak mengubah prioritas hoisting. Deklarasi fungsi tetap menang atas deklarasi variabel pada fase pembuatan.
Pertanyaan B: beberapa fungsi dengan nama yang samaβ
console.log(foo); // ?
function foo() {
return 1;
}
var foo = '1';
function foo() {
return 2;
}
console.log(foo); // ?
Jawaban:
[Function: foo] // output pertama (deklarasi fungsi yang lebih belakang menimpa yang sebelumnya)
'1' // output kedua (penugasan menimpa fungsi)
Alasan:
// Setelah hoisting
function foo() {
return 1;
} // fungsi pertama
function foo() {
return 2;
} // fungsi kedua menimpa yang pertama
var foo; // hanya deklarasi (tidak menimpa fungsi)
console.log(foo); // fungsi yang mengembalikan 2
foo = '1'; // penugasan menimpa fungsi
console.log(foo); // '1'
Pertanyaan C: function expression vs deklarasi fungsiβ
console.log(foo); // ?
console.log(bar); // ?
var foo = function () {
return 1;
};
function bar() {
return 2;
}
Jawaban:
undefined // foo adalah undefined
[Function: bar] // bar adalah fungsi
Alasan:
// Setelah hoisting
var foo; // deklarasi variabel di-hoist (body fungsi tidak)
function bar() {
return 2;
} // deklarasi fungsi di-hoist sepenuhnya
console.log(foo); // undefined
console.log(bar); // fungsi
foo = function () {
return 1;
}; // penugasan saat runtime
Perbedaan kunci:
- Deklarasi fungsi:
function foo() {}-> di-hoist sepenuhnya (termasuk body) - Function expression:
var foo = function() {}-> hanya nama variabel yang di-hoist
let/const menghindari pola iniβ
// β `var` memiliki jebakan hoisting
console.log(foo); // undefined
var foo = '1';
// β
let/const berada di TDZ sebelum inisialisasi
console.log(bar); // ReferenceError
let bar = '1';
// β
menggunakan nama yang sama dengan fungsi dan let/const menghasilkan error
function baz() {}
let baz = '1'; // SyntaxError: Identifier 'baz' has already been declared
Ringkasan Prioritas Hoistingβ
Prioritas hoisting (tinggi -> rendah):
1. Deklarasi Fungsi
- function foo() {} β
di-hoist sepenuhnya
- prioritas tertinggi
2. Deklarasi Variabel
- var foo β οΈ hanya deklarasi (tanpa penugasan)
- tidak menimpa deklarasi fungsi yang sudah ada
3. Penugasan Variabel
- foo = '1' β
bisa menimpa fungsi
- hanya terjadi pada fase eksekusi
4. Function Expression
- var foo = function() {} β οΈ diperlakukan sebagai penugasan
- hanya nama variabel yang di-hoist
Fokus Wawancaraβ
Saat menjawab pertanyaan jenis ini, Anda bisa mengikuti struktur ini:
- Jelaskan hoisting sebagai dua fase: pembuatan dan eksekusi.
- Tekankan prioritas: deklarasi fungsi > deklarasi variabel.
- Tulis ulang kode ke bentuk setelah hoisting untuk menunjukkan penalaran.
- Sebutkan best practice: gunakan
let/const, dan hindari polavaryang membingungkan.
Contoh jawaban wawancara:
Pertanyaan ini tentang prioritas hoisting. Di JavaScript, deklarasi fungsi di-hoist sebelum deklarasi variabel.
Engine melalui dua fase:
- Fase pembuatan:
function foo() {}di-hoist lebih dulu, laluvar foodi-hoist tanpa menimpa fungsi.- Fase eksekusi:
console.log(foo)mencetak fungsi, dan baru kemudianfoo = '1'menimpanya.Dalam praktik, gunakan
let/constsebagai penggantivaruntuk menghindari kebingungan ini.