Apa itu Execution Context dan Execution Stack pada JavaScript ?

Karena rasa ingin tahu saya akan closure, yang benar-benar membuat saya pusing tujuh keliling. Saya akhirnya searching kesana kemari dan membuat saya merasa semakin bodoh dan tidak mengerti apa-apa tentang javascript. Bayangkan, ketika saya cari pengertian tentang closure, yang begini kurang lebih menurut MDN “A closure is the combination of a function and the lexical environment within which that function was declared.” Saya malah tambah bingung dengan definisinya. Saya ngga tahu maksud lexical environtment, apa sih sebenarnya ? Dalam pencarian saya, saya malah tersesat dan menemukan banyak artikel-artikel menarik tentang javascript, yang sayangnya tidak tersedia dalam bahasa indonesia.

untuk mempermudah membaca artikel, bisa dibaca disini juga <a href='https://paper.dropbox.com/doc/Apa-itu-Execution-Context-dan-Execution-Stack-pada-JavaScript-kB5xpmiOhyxum2EwMGHzI?_tk=share_copylink '>https://paper.dropbox.com/doc/Apa-itu-Execution-Context-dan-Execution-Stack-pada-JavaScript-kB5xpmiOhyxum2EwMGHzI?_tk=share_copylink </a>

Setelah beberapa waktu mempelajarinya, selain itu JavaScript ini juga ribet, tambah lagi hanya ada dalam bahasa Inggris, akhirnya saya bisa memahami secara perlahan bagaimana Javascript bekerja. Untungnya bahasa Inggris saya lumayan, gimana kalau ngga ? kan bingung. Nah saya dedikasikan tulisan ini, agar teman-teman yang masih belum terlalu PeDe dengan bahasa Inggris bisa juga paham dasar-dasar JavaScript. Semoga dengan Artikel ini, teman-teman bisa mendapatkan pemahaman yang lebih baik terhadap bahasa Pemrograman JavaScript.

Mungkin artikel ini akan terlihat seperti copy paste dari <a href=' http://davidshariff.com '> http://davidshariff.com </a> karena memang sumber utamanya dari situ. Saya hanya berusaha menyampaikan ulang dengan bahasa indonesia dan sedikit penyesuaian.

Artikel ini akan membahas salah satu bagian yang sangat fundamental pada JavaScript, yaitu Execution Context ( Konteks Eksekusi). Semoga teman-teman setelah membaca artikel ini akan menjadi lebih paham bagaimana interpreter bekerja dan mengapa terkadang fungsi / variabel bisa digunakan sebelum dideklarasikan dan bagaimana value dari variabel tersebut ditentukan.

Apa itu Konteks Eksekusi ?

Ketika kode javascript di run / dijalankan, environtment (lingkup) dimana kode tersebut dieksekusi sangatlah penting, interpreter akan menentukan kode tersebut termasuk pada environtment yang mana. Kode tersebut akan ditentukan menjadi salah satu dari 3 environtment :

- Kode Global (Global Code) : default environtment, dimana kode pertama kali dieksekusi (executed). - Kode Fungsi (Function Code) : Ketika kode yang dijalankan masuk ke dalam suatu fungsi. - Kode Eval (Eval Code) : Teks yang akan dieksekusi didalam internal fungsi Eval.

Agar mudah dipahami, anggap saja Konteks Eksekusi sebagai environtment / scope / lingkup lokasi dimana kode yang sedang di “baca” oleh interpreter. Langsung saja, contoh Kode yang telah di”baca” dan ditentukan global dan function/lokal konteksnya.

Kita memiliki satu Konteks Global yang berada di dalam border warna ungu, dan 3 Konteks Fungsi / Lokal yang berada di dalam border hijau, biru, dan orange. Konteks Global hanya ada satu, yang mana bisa diakses dari semua konteks-konteks fungsi / lokal yang ada di keseluruhan kode teman-teman.

Setiap kali fungsi dipanggil, maka konteks fungsi akan dibuat, konteks fungsi ini tidak ada batasan jumlahnya, bisa tak terbatas jumlahnya. Setiap konteks fungsi akan membuat private scope, yang berisi deklarasi-deklarasi di dalam fungsi tersebut dan ini akan bersifat lokal, dan tidak bisa diakses dari luar scope fungsi tersebut. Fungsi bisa mengakses variabel yang berada diluar konteks fungsi tersebut, tetapi yang diluar tidak bisa mengakses yang didalam. mengapa ? Bagaimana sebenarnya kode di”baca” oleh interpreter?

Tumpukan Konteks Eksekusi (Execution Context Stack)

Javascript interpreter pada browser dibuat dengan single thread, yang berarti hanya ada satu hal pada browser yang bisa dikerjakan dalam satu waktu. Action-action atau events harus menunggu untuk dieksekusi, dan dikumpulkan di tempat yang namanya Execution Stack / Tumpukan Eksekusi. Stack / Tumpukan itu menggunakan salah satu metode LIFO (Last In first Out), singkatnya yang masuk terakhir yang dieksekusi duluan. Agar lebih mudah, bisa dilihat pada diagram berikut.

Seperti yang kita ketahui, pertama kali browser menjalankan kode, maka langsung masuk ke global execution context / konteks eksekusi global, ini defaultnya, maka dari itu global execution context selalu berada dipaling bawah tumpukan eksekusi. Apabila kode globalmu memanggil sebuah fungsi, maka program akan memasuki fungsi yang dipanggil itu, membuat konteks eksekusi konteks baru dan kemudian di push ke bagian paling atas tumpukan eksekusi.

Jika teman-teman memanggil fungsi baru didalam fungsi yang tadi dipanggil, maka hal yang sama akan terjadi. Program akan masuk kedalam fungsi baru tersebut, dan membuat konteks eksekusi baru kemudian di push ke atas tumpukan konteks, ketika fungsi tersebut selesai mengeksekusi konteks eksekusi-nya, maka konteks eksekusi tersebut akan di “pop” dan dibuang dari tumpukan tadi. Kemudian lanjut ke konteks dibawahnya. Contoh kode dibawah ini menunjukan fungsi rekursif dan bagaimana tumpukan eksekusi-nya terlihat.


    (function foo(i) {
        if (i === 3) {
            return;
        }
        else {
            foo(++i);
        }
    }(0));

kode diatas, akan memanggil fungsi tersebut sebanyak 3 kali, increment nilai i sebanyak 1. Setiap kali fungsi foo dipanggil, maka konteks eksekusi dibuat dan ketika konteks eksekusi telah selesai dieksekusi maka konteks eksekusi tersebut di “pop” dari tumpukan dan lanjut ke tumpukan dibawahnya, sampai kembali ke konteks eksekusi global.

Hal-hal yang perlu diingat tentang tumpukan eksekusi

- tumpukan eksekusi terdiri dari satu atau lebih konteks eksekusi (global atau fungsional - Hanya memiliki satu thread (single threaded - eksekusinya syncronous - 1 konteks global - konteks fungsi bisa tak terbatas - setiap pemanggilan fungsi akan membuat satu konteks eksekusi baru Konteks Eksekusi secara Detail

Kita telah tahu bahwa setiap kali fungsi dipanggil, maka konteks eksekusi baru akan tercipta. Nah, pada javascript interpreter setiap panggilan fungsi yang menghasilkan konteks eksekusi melalui 2 tahapan, yaitu :

1. Tahap Pembuatan (Creation Stage) : terjadi saat fungsi dipanggil, namun belum mengeksekusi kode yang ada didalamnya - Membuat Scope Chain - Membuat variabel, fungsi dan argumen - Menentukan nilai dari “this” 2. Tahap Aktivasi / Eksekusi Kode : - Memberikan nilai, mereferensikan fungsi dan meng-interpretasikan / mengeksekusi kode didalam fungsi tersebut.

Konsep Konteks eksekusi bisa digambarkan seperti objek dengan 3 properti :


    executionContextObj = {
        'scopeChain': {
            // variableObject + semua variableObject dari parent-parent-nya
        },
        'variableObject': {
            // function arguments / parameters, lokal variabel and function declarations
        },
        'this': {}
    }

executionContextObj ini dibuat ketika suatu fungsi dipanggil, tetapi tepat “sebelum” fungsinya benar-benar dieksekusi. Jadi interpreternya akan ngescan parameter / argumen yang dipass kedalam fungsi, deklarasi fungsi, dan lokal variabel dari keseluruhan fungsi yang dipanggil tadi. Nah, itu yang dinamakan tahap 1, Tahap Pembuatan.

In a nutshell, singkat kata, begini cara kerja interpreter :

1. kode kita mulai di interpretasi, bertemu fungsi yang minta dipanggil (contoh : foo();), maka interpreter mulai masuk ke dalam fungsi foo() 2. sebelum mengeksekusi kode pada fungsi tersebut, dibuatlah konteks eksekusi-nya. 3. Masuk pada Tahap Pembuatan : a. menginisiasi Scope Chain. b. Membuat variable object : 1. Membuat objek argumen, mengecek konteks apakah memiliki parameter, menginisiasi nama parameternya dan memberikan nilainya. Kemudian membuat referensi pada fungsi yang ada didalamnya. 2. men-scan konteks, apakah ada deklarasi fungsi : - Jika ditemukan fungsi didalamnya, buat properti pada variable object yang namanya sama dengan nama fungsinya, dimana properti tersebut menyimpan referensi (pointer) ke fungsi tersebut di memori. - Jika sebelumnya nama fungsi telah ada / digunakan, maka pointer untuk merefensikan nilai akan di overwrite.

3. men-scan konteks, apakah ada deklarasi variabel : - Jika ditemukan deklarasi variabel, buat properti di variable object yang namanya sama dengan variabel tersebut, dan initialisasi nilainya (value) dengan undefined. - jika namanya telah digunakan pada variable object, hanya lewat dan tidak melakukan apapun. c. Tentukan value dari “this” pada konteks

4. Tahap Aktivasi / Eksekusi Kode : Menjalankan / interpret kode di dalam konteks tersebut dan assign nilai pada variable ketika kode di jalankan baris demi baris.

mari kita lihat contohnya :


     function foo(i) {
        var a = 'hello';
        var b = function privateB() {

        };
        function c() {

        }
    }

    foo(22);

Ketika memanggil fungsi foo(22) , tahap Pembuatan akan terlihat seperti ini :


    fooExecutionContext = {
        scopeChain: { ... },
        variableObject: {
            arguments: {
                0: 22,
                length: 1
            },
            i: 22,
            c: pointer to function c()
            a: undefined,
            b: undefined
        },
        this: { ... }
    }

Seperti terlihat diatas, Tahap Pembuatan bertanggung jawan untuk menentukan nama-nama properti, bukan memberikan nilai, kecuali argument / parameter. Ketika Tahap Pembuatan selesai, eksekusi akan berlanjut masuk kedalam fungsi dan masuk ke Tahap Aktivasi / Eksekusi Kode Dan akan terlihat seperti ini setelah selesai dieksekusi :


    fooExecutionContext = {
        scopeChain: { ... },
        variableObject: {
            arguments: {
                0: 22,
                length: 1
            },
            i: 22,
            c: pointer to function c()
            a: 'hello',
            b: pointer to function privateB()
        },
        this: { ... }
    }


Hoisting

Pada tulisan saya sebelumnya disini https://www.sekolahkoding.com/forum/apa-itu-hoisting, saya sudah memberikan rambu-rambu bahwa pengertian yang saya berikan kurang tepat, dan disini lah jawaban yang sebenarnya, ini dikarenakan cara kerja interpreter pada Tahap Pembuatan yang mengakibatkan Hoisting . Sekarang teman-teman jadi paham mengapa Hoisting terjadi. dan ini ada contoh lagi :


    (function() {

        console.log(typeof foo); // function pointer
        console.log(typeof bar); // undefined

        var foo = 'hello',
            bar = function() {
                return 'world';
            };

        function foo() {
            return 'hello';
        }

    }());

sekarang muncul pertanyaan :

1. Mengapa kita bisa mengakses foo sebelum fungsi tersebut dideklarasikan? - Jika kita paham bagaimana Tahap Pembuatan terjadi, maka kita tahu bahwa variabel telah dibuat sebelum Tahap Aktivasi / Eksekusi kode. Jadi ketika fungsi mulai dieksekusi, foo sudah didefinisikan di dalam variable object. 2. Foo dideklarasikan dua kali, tetapi kenapa malah terdefinisi sebagai fungsi dan bukan undefined atau string ? - Meskipun foo dideklarasikan dua kali, kita tahu bahwa pada Tahap Pembuatan fungsi dibuat terlebih dahulu pada properti variable object sebelum variable, dan jika ingin membuat variable pada variable object tetepi namanya telah terpakai pada variable object , maka tidak akan terjadi apa-apa(hanya lewat). - Oleh sebab itu pada variable object, referensi ke function foo() dibuat terlebih dahulu, dan saat interpreter bertemu dengan variabel foo, dan ingin membuat pada variable object, interpreter tahu bahwa nama foo telah dipakai (oleh function foo() ), makanya variabel foo tidak dibuat (hanya lewat / bypass) 3. Mengapa bar undefined ? - Bar sebenarnya adalah variabel yang memiliki nilai (assigned) sebuah fungsi, dan kita tahu juga bahwa ketika variable yang dibuat pada Tahap Pembuatan akan diberi nilai “undefined”.

Apakah teman-teman merasa bahwa tulisan ini bisa dipahami ? Kalau tidak silakan bisa comment dan diskusikan lebih lanjut dengan para penghuni forum disini. Semoga dengan tulisan ini, teman-teman jadi bisa lebih paham bagaimana JavaScript interpreter bekerja. Dengan demikian, teman-teman bisa menulis kode yang lebih berkualitas, dan dengan ilmu tersebut bisa lebih bermanfaat lagi.

oh ya, bagi yang belum kenal sama saya, bisa kenalan dlu. bisa add fb saya disini

<a href='https://www.facebook.com/yudhatamadanang '>https://www.facebook.com/yudhatamadanang </a>

untuk mempermudah membaca artikel, bisa dibaca disini juga <a href='https://paper.dropbox.com/doc/Apa-itu-Execution-Context-dan-Execution-Stack-pada-JavaScript-kB5xpmiOhyxum2EwMGHzI?_tk=share_copylink '>https://paper.dropbox.com/doc/Apa-itu-Execution-Context-dan-Execution-Stack-pada-JavaScript-kB5xpmiOhyxum2EwMGHzI?_tk=share_copylink </a>

avatar timelord
@timelord

140 Kontribusi 86 Poin

Dipost 6 tahun yang lalu

Belum ada Jawaban. Jadi yang pertama Jawaban

Login untuk ikut Jawaban