Bisakah kita memanggil fungsi dalam di javascript?

JavaScript adalah bahasa yang sangat berorientasi pada fungsi. Ini memberi kita banyak kebebasan. Suatu fungsi dapat dibuat kapan saja, diteruskan sebagai argumen ke fungsi lain, dan kemudian dipanggil dari tempat kode yang sama sekali berbeda nanti

Kita sudah tahu bahwa suatu fungsi dapat mengakses variabel di luarnya (variabel "luar")

Tetapi apa yang terjadi jika variabel luar berubah sejak suatu fungsi dibuat?

Dan bagaimana jika suatu fungsi diteruskan sebagai argumen dan dipanggil dari tempat kode lain, apakah ia akan mendapatkan akses ke variabel luar di tempat baru?

Mari perluas pengetahuan kita untuk memahami skenario ini dan yang lebih kompleks

Kami akan berbicara tentang

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
3 variabel di sini

Dalam JavaScript, ada 3 cara untuk mendeklarasikan variabel.

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
4,
{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
5 (yang modern), dan
{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
6 (sisa masa lalu)

  • Dalam artikel ini kita akan menggunakan
    {
      // show message
      let message = "Hello";
      alert(message);
    }
    
    {
      // show another message
      let message = "Goodbye";
      alert(message);
    }
    4 variabel sebagai contoh
  • Variabel, dideklarasikan dengan
    {
      // show message
      let message = "Hello";
      alert(message);
    }
    
    {
      // show another message
      let message = "Goodbye";
      alert(message);
    }
    _5, berperilaku sama, jadi artikel ini juga tentang
    {
      // show message
      let message = "Hello";
      alert(message);
    }
    
    {
      // show another message
      let message = "Goodbye";
      alert(message);
    }
    5
  • {
      // show message
      let message = "Hello";
      alert(message);
    }
    
    {
      // show another message
      let message = "Goodbye";
      alert(message);
    }
    _6 lama memiliki beberapa perbedaan penting, mereka akan dibahas dalam artikel "var" lama

Jika sebuah variabel dideklarasikan di dalam blok kode

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
1, itu hanya terlihat di dalam blok itu

Sebagai contoh

{
  // do some job with local variables that should not be seen outside

  let message = "Hello"; // only visible in this block

  alert(message); // Hello
}

alert(message); // Error: message is not defined
_

Kita dapat menggunakan ini untuk mengisolasi sepotong kode yang melakukan tugasnya sendiri, dengan variabel yang hanya menjadi miliknya

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}

Akan ada kesalahan tanpa blok

Perlu diketahui, tanpa blok terpisah akan terjadi kesalahan, jika kita menggunakan

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
4 dengan nama variabel yang ada

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
_

Untuk

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
_3,
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
4,
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
5 dan seterusnya, variabel yang dideklarasikan dalam
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
1 juga hanya terlihat di dalam

if (true) {
  let phrase = "Hello!";

  alert(phrase); // Hello!
}

alert(phrase); // Error, no such variable!

Di sini, setelah

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
3 selesai,
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
8 di bawah tidak akan melihat
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
9, maka kesalahan

Itu bagus, karena memungkinkan kita membuat variabel blok-lokal, khusus untuk cabang

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
3

Hal serupa berlaku untuk

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
_4 dan
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
5 loop

for (let i = 0; i < 3; i++) {
  // the variable i is only visible inside this for
  alert(i); // 0, then 1, then 2
}

alert(i); // Error, no such variable

Secara visual,

if (true) {
  let phrase = "Hello!";

  alert(phrase); // Hello!
}

alert(phrase); // Error, no such variable!
_3 berada di luar
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
1. Tapi konstruksi
// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
_4 spesial di sini. variabel, yang dideklarasikan di dalamnya, dianggap sebagai bagian dari blok

Suatu fungsi disebut "bersarang" ketika dibuat di dalam fungsi lain

Sangat mudah untuk melakukan ini dengan JavaScript

Kita dapat menggunakannya untuk mengatur kode kita, seperti ini

function sayHiBye(firstName, lastName) {

  // helper nested function to use below
  function getFullName() {
    return firstName + " " + lastName;
  }

  alert( "Hello, " + getFullName() );
  alert( "Bye, " + getFullName() );

}

Di sini fungsi bersarang

if (true) {
  let phrase = "Hello!";

  alert(phrase); // Hello!
}

alert(phrase); // Error, no such variable!
_6 dibuat untuk kenyamanan. Itu dapat mengakses variabel luar dan dapat mengembalikan nama lengkap. Fungsi bersarang cukup umum dalam JavaScript

Yang jauh lebih menarik, fungsi bersarang dapat dikembalikan. baik sebagai properti objek baru atau sebagai hasil dengan sendirinya. Ini kemudian dapat digunakan di tempat lain. Di mana pun, ia masih memiliki akses ke variabel luar yang sama

Di bawah,

if (true) {
  let phrase = "Hello!";

  alert(phrase); // Hello!
}

alert(phrase); // Error, no such variable!
_7 membuat fungsi "penghitung" yang mengembalikan angka berikutnya pada setiap pemanggilan

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2

Meskipun sederhana, varian kode yang sedikit dimodifikasi memiliki kegunaan praktis, misalnya, sebagai penghasil angka acak untuk menghasilkan nilai acak untuk pengujian otomatis

Bagaimana cara kerjanya?

Memahami hal-hal seperti itu bagus untuk keseluruhan pengetahuan JavaScript dan bermanfaat untuk skenario yang lebih kompleks. Jadi mari kita sedikit lebih dalam

Di sini jadilah naga

Penjelasan teknis mendalam ada di depan

Sejauh saya ingin menghindari detail bahasa tingkat rendah, pemahaman apa pun tanpanya akan kurang dan tidak lengkap, jadi bersiaplah

Untuk kejelasan, penjelasannya dibagi menjadi beberapa langkah

Dalam JavaScript, setiap fungsi yang berjalan, blok kode

// show message
let message = "Hello";
alert(message);

// show another message
let message = "Goodbye"; // Error: variable already declared
alert(message);
1, dan skrip secara keseluruhan memiliki objek terkait internal (tersembunyi) yang dikenal sebagai Lingkungan Lexical

Objek Lexical Environment terdiri dari dua bagian

  1. Rekaman Lingkungan – objek yang menyimpan semua variabel lokal sebagai propertinya (dan beberapa informasi lain seperti nilai
    if (true) {
      let phrase = "Hello!";
    
      alert(phrase); // Hello!
    }
    
    alert(phrase); // Error, no such variable!
    9)
  2. Referensi ke lingkungan leksikal luar, yang terkait dengan kode luar

"Variabel" hanyalah properti dari objek internal khusus,

for (let i = 0; i < 3; i++) {
  // the variable i is only visible inside this for
  alert(i); // 0, then 1, then 2
}

alert(i); // Error, no such variable
0. "Untuk mendapatkan atau mengubah variabel" berarti "mendapatkan atau mengubah properti dari objek itu"

Dalam kode sederhana tanpa fungsi ini, hanya ada satu Lingkungan Lexical

Inilah yang disebut Lingkungan Leksikal global, yang terkait dengan keseluruhan skrip

Pada gambar di atas, persegi panjang berarti Rekam Lingkungan (penyimpanan variabel) dan tanda panah berarti referensi luar. Lingkungan Leksikal global tidak memiliki referensi luar, itu sebabnya panah menunjuk ke

for (let i = 0; i < 3; i++) {
  // the variable i is only visible inside this for
  alert(i); // 0, then 1, then 2
}

alert(i); // Error, no such variable
1

Saat kode mulai dijalankan dan berlanjut, Lingkungan Lexical berubah

Ini kode yang sedikit lebih panjang

Persegi panjang di sisi kanan menunjukkan bagaimana Lingkungan Leksikal global berubah selama eksekusi

  1. Saat skrip dimulai, Lingkungan Lexical telah diisi sebelumnya dengan semua variabel yang dideklarasikan
    • Awalnya, mereka berada dalam status "Tidak diinisialisasi". Itu adalah keadaan internal khusus, artinya mesin tahu tentang variabel, tetapi tidak dapat direferensikan sampai dideklarasikan dengan
      {
        // show message
        let message = "Hello";
        alert(message);
      }
      
      {
        // show another message
        let message = "Goodbye";
        alert(message);
      }
      4. Ini hampir sama seperti jika variabelnya tidak ada
  2. Kemudian
    for (let i = 0; i < 3; i++) {
      // the variable i is only visible inside this for
      alert(i); // 0, then 1, then 2
    }
    
    alert(i); // Error, no such variable
    _3 definisi muncul. Belum ada tugas, jadi nilainya adalah
    for (let i = 0; i < 3; i++) {
      // the variable i is only visible inside this for
      alert(i); // 0, then 1, then 2
    }
    
    alert(i); // Error, no such variable
    4. Kita dapat menggunakan variabel dari titik ini ke depan
  3. // show message
    let message = "Hello";
    alert(message);
    
    // show another message
    let message = "Goodbye"; // Error: variable already declared
    alert(message);
    _9 diberi nilai
  4. // show message
    let message = "Hello";
    alert(message);
    
    // show another message
    let message = "Goodbye"; // Error: variable already declared
    alert(message);
    _9 mengubah nilainya

Semuanya terlihat sederhana untuk saat ini, bukan?

  • Variabel adalah properti dari objek internal khusus, terkait dengan blok/fungsi/skrip yang sedang dieksekusi
  • Bekerja dengan variabel sebenarnya bekerja dengan properti objek itu

Leksikal Lingkungan adalah objek spesifikasi

"Lexical Environment" adalah objek spesifikasi. itu hanya ada "secara teoritis" untuk menggambarkan cara kerja sesuatu. Kami tidak bisa mendapatkan objek ini dalam kode kami dan memanipulasinya secara langsung

Mesin JavaScript juga dapat mengoptimalkannya, membuang variabel yang tidak digunakan untuk menghemat memori dan melakukan trik internal lainnya, selama perilaku yang terlihat tetap seperti yang dijelaskan

Fungsi juga merupakan nilai, seperti variabel

Perbedaannya adalah Deklarasi Fungsi langsung diinisialisasi sepenuhnya

Ketika Lingkungan Leksikal dibuat, Deklarasi Fungsi segera menjadi fungsi siap pakai (tidak seperti

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
4, yang tidak dapat digunakan sampai deklarasi)

Itu sebabnya kita bisa menggunakan fungsi, dideklarasikan sebagai Deklarasi Fungsi, bahkan sebelum deklarasi itu sendiri

Misalnya, inilah keadaan awal Lingkungan Lexical global saat kita menambahkan sebuah fungsi

Secara alami, perilaku ini hanya berlaku untuk Deklarasi Fungsi, bukan Ekspresi Fungsi di mana kami menetapkan fungsi ke variabel, seperti

for (let i = 0; i < 3; i++) {
  // the variable i is only visible inside this for
  alert(i); // 0, then 1, then 2
}

alert(i); // Error, no such variable
8

Ketika suatu fungsi berjalan, pada awal panggilan, Lingkungan Lexical baru dibuat secara otomatis untuk menyimpan variabel lokal dan parameter panggilan

Misalnya, untuk

for (let i = 0; i < 3; i++) {
  // the variable i is only visible inside this for
  alert(i); // 0, then 1, then 2
}

alert(i); // Error, no such variable
_9, tampilannya seperti ini (eksekusinya ada di baris, diberi tanda panah)

Selama pemanggilan fungsi, kami memiliki dua Lingkungan Lexical. bagian dalam (untuk pemanggilan fungsi) dan bagian luar (global)

  • Lingkungan Leksikal bagian dalam sesuai dengan eksekusi
    function sayHiBye(firstName, lastName) {
    
      // helper nested function to use below
      function getFullName() {
        return firstName + " " + lastName;
      }
    
      alert( "Hello, " + getFullName() );
      alert( "Bye, " + getFullName() );
    
    }
    0 saat ini. Ia memiliki satu properti.
    function sayHiBye(firstName, lastName) {
    
      // helper nested function to use below
      function getFullName() {
        return firstName + " " + lastName;
      }
    
      alert( "Hello, " + getFullName() );
      alert( "Bye, " + getFullName() );
    
    }
    1, argumen fungsi. Kami memanggil
    for (let i = 0; i < 3; i++) {
      // the variable i is only visible inside this for
      alert(i); // 0, then 1, then 2
    }
    
    alert(i); // Error, no such variable
    _9, jadi nilai
    function sayHiBye(firstName, lastName) {
    
      // helper nested function to use below
      function getFullName() {
        return firstName + " " + lastName;
      }
    
      alert( "Hello, " + getFullName() );
      alert( "Bye, " + getFullName() );
    
    }
    1 adalah
    function sayHiBye(firstName, lastName) {
    
      // helper nested function to use below
      function getFullName() {
        return firstName + " " + lastName;
      }
    
      alert( "Hello, " + getFullName() );
      alert( "Bye, " + getFullName() );
    
    }
    4
  • Lingkungan Leksikal luar adalah Lingkungan Leksikal global. Ia memiliki variabel
    // show message
    let message = "Hello";
    alert(message);
    
    // show another message
    let message = "Goodbye"; // Error: variable already declared
    alert(message);
    _9 dan fungsi itu sendiri

Lingkungan Leksikal batin memiliki referensi ke

function sayHiBye(firstName, lastName) {

  // helper nested function to use below
  function getFullName() {
    return firstName + " " + lastName;
  }

  alert( "Hello, " + getFullName() );
  alert( "Bye, " + getFullName() );

}
6

Ketika kode ingin mengakses variabel – Lingkungan Lexical bagian dalam dicari terlebih dahulu, lalu yang terluar, lalu yang lebih terluar dan seterusnya hingga yang global

Jika variabel tidak ditemukan di mana pun, itu adalah kesalahan dalam mode ketat (tanpa

function sayHiBye(firstName, lastName) {

  // helper nested function to use below
  function getFullName() {
    return firstName + " " + lastName;
  }

  alert( "Hello, " + getFullName() );
  alert( "Bye, " + getFullName() );

}
7, penugasan ke variabel yang tidak ada membuat variabel global baru, untuk kompatibilitas dengan kode lama)

Dalam contoh ini hasil pencarian sebagai berikut

  • Untuk variabel
    function sayHiBye(firstName, lastName) {
    
      // helper nested function to use below
      function getFullName() {
        return firstName + " " + lastName;
      }
    
      alert( "Hello, " + getFullName() );
      alert( "Bye, " + getFullName() );
    
    }
    1,
    // show message
    let message = "Hello";
    alert(message);
    
    // show another message
    let message = "Goodbye"; // Error: variable already declared
    alert(message);
    8 di dalam
    function sayHiBye(firstName, lastName) {
    
      // helper nested function to use below
      function getFullName() {
        return firstName + " " + lastName;
      }
    
      alert( "Hello, " + getFullName() );
      alert( "Bye, " + getFullName() );
    
    }
    0 menemukannya langsung di Lingkungan Leksikal bagian dalam
  • Ketika ingin mengakses
    // show message
    let message = "Hello";
    alert(message);
    
    // show another message
    let message = "Goodbye"; // Error: variable already declared
    alert(message);
    9, maka tidak ada
    // show message
    let message = "Hello";
    alert(message);
    
    // show another message
    let message = "Goodbye"; // Error: variable already declared
    alert(message);
    9 secara lokal, sehingga mengikuti referensi ke Lingkungan Lexical luar dan menemukannya di sana

Mari kembali ke contoh

if (true) {
  let phrase = "Hello!";

  alert(phrase); // Hello!
}

alert(phrase); // Error, no such variable!
_7

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

Di awal setiap panggilan

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
_4, objek Lexical Environment baru dibuat, untuk menyimpan variabel untuk proses
if (true) {
  let phrase = "Hello!";

  alert(phrase); // Hello!
}

alert(phrase); // Error, no such variable!
7 ini

Jadi kami memiliki dua Lingkungan Leksikal bersarang, seperti pada contoh di atas

Apa yang berbeda adalah, selama eksekusi

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
4, fungsi bersarang kecil dibuat hanya dari satu baris.
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
7. Kami belum menjalankannya, hanya membuat

Semua fungsi mengingat Lingkungan Leksikal tempat mereka dibuat. Secara teknis, tidak ada keajaiban di sini. semua fungsi memiliki properti tersembunyi bernama

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
_8, yang menyimpan referensi ke Lingkungan Lexical tempat fungsi dibuat

Jadi,

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
_9 memiliki referensi ke
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
0 Leksikal Lingkungan. Begitulah fungsi mengingat di mana ia dibuat, di mana pun ia dipanggil. Referensi
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
_8 disetel sekali dan selamanya pada waktu pembuatan fungsi

Kemudian, ketika

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
2 dipanggil, Lingkungan Leksikal baru dibuat untuk panggilan tersebut, dan referensi Lingkungan Leksikal luarnya diambil dari
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
9

Sekarang ketika kode di dalam

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
2 mencari variabel
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
5, pertama-tama ia mencari Lingkungan Lexical-nya sendiri (kosong, karena tidak ada variabel lokal di sana), kemudian Lingkungan Lexical dari panggilan
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
4 luar, di mana ia menemukan dan mengubahnya

Variabel diperbarui di Lingkungan Lexical tempatnya berada

Inilah keadaan setelah eksekusi

Jika kita memanggil

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
2 beberapa kali, variabel
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
5 akan dinaikkan menjadi
function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
9,
function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
// of the corresponding f() call
0 dan seterusnya, di tempat yang sama

Penutupan

Ada istilah pemrograman umum "penutupan", yang umumnya harus diketahui oleh pengembang

Penutupan adalah fungsi yang mengingat variabel luarnya dan dapat mengaksesnya. Dalam beberapa bahasa, itu tidak mungkin, atau sebuah fungsi harus ditulis dengan cara khusus untuk mewujudkannya. Tapi seperti yang dijelaskan di atas, dalam JavaScript, semua fungsi secara alami adalah penutupan (hanya ada satu pengecualian, untuk dicakup dalam sintaks "Fungsi baru")

Itu adalah. mereka secara otomatis mengingat di mana mereka dibuat menggunakan properti

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
8 tersembunyi, dan kemudian kode mereka dapat mengakses variabel luar

Ketika dalam sebuah wawancara, pengembang frontend mendapat pertanyaan tentang "apa itu penutupan?", Jawaban yang valid adalah definisi penutupan dan penjelasan bahwa semua fungsi dalam JavaScript adalah penutupan, dan mungkin beberapa kata lagi tentang detail teknis. properti

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
_8 dan bagaimana Leksikal Lingkungan bekerja

Biasanya, Lingkungan Lexical dihapus dari memori dengan semua variabel setelah pemanggilan fungsi selesai. Itu karena tidak ada referensi untuk itu. Seperti objek JavaScript apa pun, itu hanya disimpan dalam memori saat dapat dijangkau

Namun, jika ada fungsi bersarang yang masih dapat dijangkau setelah fungsi berakhir, maka fungsi tersebut memiliki properti

function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
8 yang mereferensikan lingkungan leksikal

Dalam hal itu Lingkungan Leksikal masih dapat dijangkau bahkan setelah fungsi selesai, sehingga tetap hidup

Sebagai contoh

function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
// of the corresponding f() call

Perhatikan bahwa jika

function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
// of the corresponding f() call
4 dipanggil berkali-kali, dan fungsi yang dihasilkan disimpan, maka semua objek Leksikal Lingkungan yang sesuai juga akan disimpan di memori. Dalam kode di bawah ini, ketiganya

function f() {
  let value = Math.random();

  return function() { alert(value); };
}

// 3 functions in array, every one of them links to Lexical Environment
// from the corresponding f() run
let arr = [f(), f(), f()];

Objek Lingkungan Leksikal mati ketika menjadi tidak terjangkau (sama seperti objek lainnya). Dengan kata lain, itu hanya ada jika setidaknya ada satu fungsi bersarang yang mereferensikannya

Dalam kode di bawah ini, setelah fungsi bersarang dihapus, Lingkungan Lexical terlampir (dan karenanya

function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
// of the corresponding f() call
5) dibersihkan dari memori

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
0

Seperti yang telah kita lihat, dalam teori saat sebuah fungsi aktif, semua variabel luar juga dipertahankan

Namun dalam praktiknya, mesin JavaScript mencoba mengoptimalkannya. Mereka menganalisis penggunaan variabel dan jika jelas dari kode bahwa variabel luar tidak digunakan – itu akan dihapus

Efek samping yang penting di V8 (Chrome, Edge, Opera) adalah bahwa variabel tersebut tidak akan tersedia dalam proses debug

Coba jalankan contoh di bawah ini di Chrome dengan Alat Pengembang terbuka

Saat dijeda, di konsol ketik

function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
// of the corresponding f() call
6

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
_1

Seperti yang Anda lihat – tidak ada variabel seperti itu. Secara teori, itu harus dapat diakses, tetapi mesin mengoptimalkannya

Itu dapat menyebabkan masalah debug yang lucu (jika tidak memakan waktu). Salah satunya – kita bisa melihat variabel luar dengan nama yang sama, bukan yang diharapkan

{
  // show message
  let message = "Hello";
  alert(message);
}

{
  // show another message
  let message = "Goodbye";
  alert(message);
}
_2

Fitur V8 ini baik untuk diketahui. Jika Anda melakukan debug dengan Chrome/Edge/Opera, cepat atau lambat Anda akan menemukannya

Itu bukan bug di debugger, melainkan fitur khusus V8. Mungkin suatu saat akan diubah. Anda selalu dapat memeriksanya dengan menjalankan contoh di halaman ini

Bagaimana cara memanggil fungsi dalam di JS?

Pendekatan. .
Tulis satu fungsi di dalam fungsi lain
Lakukan panggilan ke fungsi dalam di pernyataan pengembalian fungsi luar
Sebut saja fun(a)(b) di mana a adalah parameter ke luar dan b ke fungsi dalam
Terakhir, kembalikan output gabungan dari fungsi bersarang

Bisakah kita memanggil fungsi di dalam fungsi dalam JavaScript?

Dalam JavaScript, fungsi adalah objek kelas satu. Ini berarti mereka dapat dibuat dan digunakan seperti objek lainnya dalam bahasa. Fungsi dapat diteruskan sebagai argumen ke fungsi lain, ditetapkan ke variabel, dan bahkan dikembalikan ke fungsi lain .

Bisakah Anda memanggil fungsi di dalam fungsi?

Memanggil fungsi dari dalam dirinya sendiri disebut rekursi dan jawaban sederhananya adalah, ya.

Apakah boleh meletakkan fungsi di dalam fungsi?

Kita dapat mendeklarasikan sebuah fungsi di dalam sebuah fungsi, tetapi itu bukan fungsi bersarang . Karena definisi fungsi bersarang tidak dapat mengakses variabel lokal dari blok sekitarnya, mereka hanya dapat mengakses variabel global dari modul yang memuatnya.