Fungsi bersarang di javascript w3schools

Fungsi bersarang hanyalah sebuah fungsi di dalam fungsi lain, dan terkadang disebut "fungsi dalam". Ada banyak alasan mengapa Anda ingin menggunakan fungsi bersarang, dan kami akan membahas yang paling umum dalam artikel ini

Cara mendefinisikan fungsi bersarang

Untuk mendefinisikan fungsi bersarang, cukup inisialisasi fungsi lain di dalam fungsi dengan menggunakan kata kunci def

def greeting(first, last):
  # nested helper function
  def getFullName():
    return first + " " + last

  print("Hi, " + getFullName() + "!")

greeting('Quincy', 'Larson')

Keluaran

Hi, Quincy Larson!
_

Seperti yang Anda lihat, fungsi getFullName bersarang memiliki akses ke parameter fungsi

Hi, Quincy Larson!
0 luar,
Hi, Quincy Larson!
1 dan
Hi, Quincy Larson!
2. Ini adalah kasus penggunaan umum untuk fungsi bersarang–untuk berfungsi sebagai fungsi pembantu kecil untuk fungsi luar yang lebih kompleks

Alasan untuk menggunakan fungsi bersarang

Meskipun ada banyak alasan yang sah untuk menggunakan fungsi bersarang, di antara yang paling umum adalah fungsi enkapsulasi dan penutupan/pabrik

enkapsulasi data

Ada kalanya Anda ingin mencegah suatu fungsi atau data yang dapat diaksesnya diakses dari bagian lain kode Anda, sehingga Anda dapat mengenkapsulasinya dalam fungsi lain

Saat Anda menyusun fungsi seperti ini, fungsi tersebut tersembunyi dari cakupan global. Karena perilaku ini, enkapsulasi data terkadang disebut sebagai penyembunyian data atau privasi data. Sebagai contoh

def outer():
  print("I'm the outer function.")
  def inner():
    print("And I'm the inner function.")
  inner()

inner()

Keluaran

Traceback (most recent call last):
  File "main.py", line 16, in <module>
    inner()
NameError: name 'inner' is not defined
_

Pada kode di atas, fungsi

Hi, Quincy Larson!
_3 hanya tersedia dari dalam fungsi
Hi, Quincy Larson!
4. Jika Anda mencoba memanggil
Hi, Quincy Larson!
_3 dari luar fungsi, Anda akan mendapatkan kesalahan di atas

Sebagai gantinya, Anda harus memanggil fungsi

Hi, Quincy Larson!
_4 seperti itu

def outer():
  print("I'm the outer function.")
  def inner():
    print("And I'm the inner function.")
  inner()

outer()

Keluaran

I'm the outer function.
And I'm the inner function.

Penutupan

Tetapi apa yang akan terjadi jika fungsi luar mengembalikan fungsi dalam itu sendiri, daripada memanggilnya seperti pada contoh di atas?

Berikut ini adalah kondisi yang harus dipenuhi untuk membuat penutupan dengan Python

Ini adalah kondisi yang Anda perlukan untuk membuat penutupan dengan Python

1. Harus ada fungsi bersarang

2. Fungsi bagian dalam harus mengacu pada nilai yang didefinisikan dalam lingkup terlampir

3. Fungsi penutup harus mengembalikan fungsi bersarang

- Sumber. https. // penyalahgunaan tumpukan. com/fungsi-bersarang-python/

Berikut adalah contoh sederhana dari penutupan

def num1(x):
  def num2(y):
    return x + y
  return num2

print(num1(10)(5))

Keluaran

15

Penutupan memungkinkan untuk meneruskan data ke fungsi dalam tanpa terlebih dahulu meneruskannya ke fungsi luar dengan parameter seperti contoh

Hi, Quincy Larson!
0 di awal artikel. Mereka juga memungkinkan untuk memanggil fungsi dalam dari luar fungsi luar enkapsulasi. Semua ini dengan manfaat enkapsulasi / penyembunyian data yang disebutkan sebelumnya

Sekarang setelah Anda memahami bagaimana dan mengapa menyarangkan fungsi dengan Python, keluarlah dan buat sarang dengan yang terbaik dari mereka

IKLAN

IKLAN

IKLAN


Jika artikel ini bermanfaat, tweetlah

Belajar kode secara gratis. Kurikulum open source freeCodeCamp telah membantu lebih dari 40.000 orang mendapatkan pekerjaan sebagai pengembang. Memulai

Penutupan adalah kombinasi dari fungsi yang dibundel bersama (terlampir) dengan referensi ke keadaan sekitarnya (lingkungan leksikal). Dengan kata lain, sebuah closure memberi Anda akses ke lingkup fungsi luar dari fungsi dalam. Dalam JavaScript, penutupan dibuat setiap kali fungsi dibuat, pada waktu pembuatan fungsi

Perhatikan contoh kode berikut

function init() {
  var name = 'Mozilla'; // name is a local variable created by init
  function displayName() {
    // displayName() is the inner function, a closure
    console.log(name); // use variable declared in the parent function
  }
  displayName();
}
init();

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
8 membuat variabel lokal bernama
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
9 dan fungsi bernama
function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
0. Fungsi
function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
_0 adalah fungsi dalam yang didefinisikan di dalam
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
8 dan hanya tersedia di dalam tubuh fungsi
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
8. Perhatikan bahwa fungsi
function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
_0 tidak memiliki variabel lokalnya sendiri. Namun, karena fungsi dalam memiliki akses ke variabel fungsi luar,
function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
0 dapat mengakses variabel
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
9 yang dideklarasikan dalam fungsi induk,
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
8

Jalankan kode menggunakan tautan JSFiddle ini dan perhatikan bahwa pernyataan

function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
8 dalam fungsi
function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
0 berhasil menampilkan nilai variabel
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
9, yang dideklarasikan dalam fungsi induknya. Ini adalah contoh pelingkupan leksikal, yang menjelaskan bagaimana parser menyelesaikan nama variabel saat fungsi bersarang. Kata leksikal mengacu pada fakta bahwa pelingkupan leksikal menggunakan lokasi di mana variabel dideklarasikan dalam kode sumber untuk menentukan di mana variabel itu tersedia. Fungsi bersarang memiliki akses ke variabel yang dideklarasikan dalam lingkup luarnya

Dalam contoh khusus ini, ruang lingkup disebut ruang lingkup fungsi, karena variabel dapat diakses dan hanya dapat diakses di dalam badan fungsi tempat ia dideklarasikan

Biasanya (sebelum ES6), JavaScript hanya memiliki dua jenis cakupan. ruang lingkup fungsi dan ruang lingkup global. Variabel yang dideklarasikan dengan

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
_1 adalah cakupan fungsi atau cakupan global, bergantung pada apakah variabel tersebut dideklarasikan di dalam fungsi atau di luar fungsi. Ini bisa rumit, karena balok dengan kurung kurawal tidak membuat cakupan

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);

Untuk orang-orang dari bahasa lain (mis. g. C, Java) di mana blok membuat ruang lingkup, kode di atas harus menimbulkan kesalahan pada baris

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
2, karena kita berada di luar ruang lingkup
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
3 di salah satu blok. Namun, karena blok tidak membuat cakupan untuk
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
1, pernyataan
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
1 di sini sebenarnya membuat variabel global. Ada juga yang diperkenalkan di bawah ini yang mengilustrasikan bagaimana hal ini dapat menyebabkan bug yang sebenarnya bila digabungkan dengan penutupan

Di ES6, JavaScript memperkenalkan deklarasi

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
_6 dan
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
7 , yang antara lain seperti , memungkinkan Anda membuat variabel dengan cakupan blok

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined

Intinya, blok akhirnya diperlakukan sebagai cakupan di ES6, tetapi hanya jika Anda mendeklarasikan variabel dengan

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
6 atau
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
7. Selain itu, ES6 memperkenalkan modul, yang memperkenalkan cakupan jenis lain. Penutupan dapat menangkap variabel di semua cakupan ini, yang akan kami perkenalkan nanti

Perhatikan contoh kode berikut

function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();

Menjalankan kode ini memiliki efek yang sama persis dengan contoh sebelumnya dari fungsi

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
8 di atas. Apa yang berbeda (dan menarik) adalah bahwa fungsi dalam
function makeFunc() {
  const name = 'Mozilla';
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
0 dikembalikan dari fungsi luar sebelum dieksekusi

Sekilas, sepertinya tidak intuitif bahwa kode ini masih berfungsi. Dalam beberapa bahasa pemrograman, variabel lokal dalam suatu fungsi hanya ada selama durasi eksekusi fungsi tersebut. Setelah

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}
_2 selesai dieksekusi, Anda mungkin berharap bahwa variabel
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
9 tidak lagi dapat diakses. Namun, karena kode masih berfungsi seperti yang diharapkan, hal ini jelas tidak berlaku di JavaScript

Alasannya adalah bahwa fungsi dalam bentuk penutupan JavaScript. Penutupan adalah kombinasi dari fungsi dan lingkungan leksikal di mana fungsi itu dideklarasikan. Lingkungan ini terdiri dari variabel lokal apa pun yang berada dalam ruang lingkup pada saat penutupan dibuat. Dalam hal ini,

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}
4 adalah referensi ke turunan fungsi
body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}
5 yang dibuat saat
body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}
6 dijalankan. Contoh
body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}
5 mempertahankan referensi ke lingkungan leksikalnya, di mana variabel
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
9 ada. Untuk alasan ini, ketika
body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}
_4 dipanggil, variabel
if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
9 tetap tersedia untuk digunakan, dan "Mozilla" diteruskan ke
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
2

Inilah contoh yang sedikit lebih menarik—fungsi _

function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
2

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12

Dalam contoh ini, kami telah mendefinisikan sebuah fungsi

function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
3, yang menggunakan argumen tunggal
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
3, dan mengembalikan fungsi baru. Fungsi yang dikembalikan mengambil argumen tunggal
function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
5, dan mengembalikan jumlah
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
3 dan
function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
5

Intinya,

function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
2 adalah pabrik fungsi. Itu menciptakan fungsi yang dapat menambahkan nilai spesifik ke argumen mereka. Dalam contoh di atas, pabrik fungsi membuat dua fungsi baru—satu yang menambahkan lima ke argumennya, dan satu lagi yang menambahkan 10

function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
9 dan
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
0 keduanya penutupan. Mereka berbagi definisi tubuh fungsi yang sama, tetapi menyimpan lingkungan leksikal yang berbeda. Dalam lingkungan leksikal
function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
_9,
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
3 adalah 5, sedangkan dalam lingkungan leksikal untuk
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
0,
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
3 adalah 10

Penutupan berguna karena memungkinkan Anda mengaitkan data (lingkungan leksikal) dengan fungsi yang beroperasi pada data tersebut. Ini memiliki kesamaan yang jelas dengan pemrograman berorientasi objek, di mana objek memungkinkan Anda untuk mengaitkan data (properti objek) dengan satu atau lebih metode

Akibatnya, Anda dapat menggunakan penutupan di mana pun Anda biasanya menggunakan objek hanya dengan satu metode

Situasi di mana Anda mungkin ingin melakukan ini sangat umum di web. Sebagian besar kode yang ditulis dalam JavaScript front-end berbasis peristiwa. Anda menentukan beberapa perilaku, lalu melampirkannya ke peristiwa yang dipicu oleh pengguna (seperti klik atau penekanan tombol). Kode dilampirkan sebagai panggilan balik (satu fungsi yang dijalankan sebagai respons terhadap acara tersebut)

Misalnya, kita ingin menambahkan tombol ke halaman untuk menyesuaikan ukuran teks. Salah satu cara melakukannya adalah menentukan ukuran font elemen

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
5 (dalam piksel), lalu menyetel ukuran elemen lain pada halaman (seperti header) menggunakan unit
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
6 relatif

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}

Tombol ukuran teks interaktif seperti itu dapat mengubah properti

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
7 dari elemen
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
5, dan penyesuaian diambil oleh elemen lain di halaman berkat unit relatif

Inilah JavaScriptnya

function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
9,
<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
0, dan
<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
1 sekarang adalah fungsi yang mengubah ukuran teks isi masing-masing menjadi 12, 14, dan 16 piksel. Anda dapat melampirkannya ke tombol (dalam hal ini hyperlink) seperti yang ditunjukkan pada contoh kode berikut

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>

Jalankan kode menggunakan JSFiddle

Bahasa seperti Java memungkinkan Anda mendeklarasikan metode sebagai privat, artinya metode tersebut hanya dapat dipanggil oleh metode lain di kelas yang sama

JavaScript, sebelum kelas, tidak memiliki cara mendeklarasikan asli, tetapi dimungkinkan untuk meniru metode pribadi menggunakan penutupan. Metode pribadi tidak hanya berguna untuk membatasi akses ke kode. Mereka juga menyediakan cara yang ampuh untuk mengelola namespace global Anda

Kode berikut mengilustrasikan cara menggunakan closure untuk mendefinisikan fungsi publik yang dapat mengakses fungsi dan variabel privat. Perhatikan bahwa penutupan ini mengikuti Pola Desain Modul

const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.

Dalam contoh sebelumnya, setiap penutupan memiliki lingkungan leksikalnya sendiri. Namun di sini, ada lingkungan leksikal tunggal yang digunakan bersama oleh ketiga fungsi tersebut.

<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
2,
<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
3, dan
<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
4

Lingkungan leksikal bersama dibuat di badan fungsi anonim, yang dijalankan segera setelah didefinisikan (juga dikenal sebagai IIFE). Lingkungan leksikal berisi dua item pribadi. sebuah variabel bernama

<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
_5, dan sebuah fungsi bernama
<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
6. Anda tidak dapat mengakses anggota pribadi ini dari luar fungsi anonim. Sebagai gantinya, Anda dapat mengaksesnya menggunakan tiga fungsi publik yang dikembalikan dari pembungkus anonim

Ketiga fungsi publik tersebut merupakan closure yang memiliki lingkungan leksikal yang sama. Berkat pelingkupan leksikal JavaScript, mereka masing-masing memiliki akses ke variabel

<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
5 dan fungsi
<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
6

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
0

Perhatikan bagaimana kedua penghitung mempertahankan independensinya satu sama lain. Setiap penutupan mereferensikan versi yang berbeda dari variabel

<button id="size-12">12</button>
<button id="size-14">14</button>
<button id="size-16">16</button>
5 melalui penutupannya sendiri. Setiap kali salah satu penghitung dipanggil, lingkungan leksikalnya berubah dengan mengubah nilai variabel ini. Perubahan pada nilai variabel di satu penutupan tidak memengaruhi nilai di penutupan lainnya

Catatan. Menggunakan penutupan dengan cara ini memberikan manfaat yang biasanya diasosiasikan dengan pemrograman berorientasi objek. Secara khusus, penyembunyian dan enkapsulasi data

Setiap penutupan memiliki tiga cakupan

  • Cakupan lokal (Cakupan sendiri)
  • Melampirkan ruang lingkup (dapat berupa blok, fungsi, atau ruang lingkup modul)
  • Cakupan global

Kesalahan umum adalah tidak menyadari bahwa dalam kasus di mana fungsi luar itu sendiri adalah fungsi bersarang, akses ke ruang lingkup fungsi luar mencakup ruang lingkup terlampir dari fungsi luar — secara efektif membuat rangkaian ruang lingkup fungsi. Untuk mendemonstrasikan, perhatikan kode contoh berikut

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
1

Anda juga dapat menulis tanpa fungsi anonim

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
2

Dalam contoh di atas, ada serangkaian fungsi bersarang, yang semuanya memiliki akses ke lingkup fungsi luar. Dalam konteks ini, kita dapat mengatakan bahwa penutupan memiliki akses ke semua cakupan fungsi luar

Penutupan dapat menangkap variabel dalam cakupan blok dan cakupan modul juga. Misalnya, berikut ini membuat penutupan atas variabel cakupan blok

function makeSizer(size) {
  return function () {
    document.body.style.fontSize = `${size}px`;
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);
5

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
3

Penutupan modul bisa lebih menarik

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
4

Di sini, modul mengekspor sepasang fungsi getter-setter, yang menutup variabel cakupan modul

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
3. Bahkan ketika
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
_3 tidak dapat diakses langsung dari modul lain, itu dapat dibaca dan ditulis dengan fungsi

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
5

Penutupan juga dapat menutup nilai yang diimpor, yang dianggap sebagai pengikat langsung, karena ketika nilai asli berubah, nilai yang diimpor juga berubah.

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
6

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
7

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
8

Sebelum pengenalan kata kunci

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
_6, masalah umum dengan penutupan terjadi saat Anda membuatnya di dalam satu lingkaran. Untuk mendemonstrasikan, perhatikan kode contoh berikut

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
_9

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
0

Coba jalankan kode di JSFiddle

Larik

const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
_4 mendefinisikan tiga petunjuk bermanfaat, masing-masing terkait dengan ID bidang masukan dalam dokumen. Loop menggilir definisi ini, mengaitkan peristiwa
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
5 ke masing-masing yang menunjukkan metode bantuan terkait

Jika Anda mencoba kode ini, Anda akan melihat bahwa itu tidak berfungsi seperti yang diharapkan. Apa pun bidang yang Anda fokuskan, pesan tentang usia Anda akan ditampilkan

Alasannya adalah karena fungsi yang ditetapkan ke

const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
5 adalah penutupan; . Tiga penutupan telah dibuat oleh loop, tetapi masing-masing berbagi lingkungan leksikal tunggal yang sama, yang memiliki variabel dengan nilai yang berubah (
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
8). Ini karena variabel
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
_8 dideklarasikan dengan
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
1 dan dengan demikian memiliki ruang lingkup fungsi karena mengangkat. Nilai
if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
_01 ditentukan saat callback
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
5 dijalankan. Karena loop telah berjalan pada saat itu, objek variabel
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
8 (dibagi oleh ketiga penutupan) dibiarkan menunjuk ke entri terakhir dalam daftar
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
4

Salah satu solusi dalam hal ini adalah menggunakan lebih banyak penutupan. khususnya, untuk menggunakan fungsi pabrik seperti yang dijelaskan sebelumnya

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
1

Jalankan kode menggunakan tautan JSFiddle ini

Ini bekerja seperti yang diharapkan. Alih-alih semua panggilan balik berbagi satu lingkungan leksikal, fungsi

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
05 membuat lingkungan leksikal baru untuk setiap panggilan balik, di mana
if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
06 merujuk ke string yang sesuai dari larik
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
4

Salah satu cara lain untuk menulis di atas menggunakan penutupan anonim adalah

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
2

Jika Anda tidak ingin menggunakan lebih banyak penutupan, Anda dapat menggunakan kata kunci

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
6 atau
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
7

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
3

Contoh ini menggunakan

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
7 alih-alih
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12
1, sehingga setiap penutupan mengikat variabel cakupan blok, artinya tidak diperlukan penutupan tambahan

Alternatif lain bisa menggunakan

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
_12 untuk mengulang array
const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },

    value() {
      return privateCounter;
    },
  };
})();

console.log(counter.value()); // 0.

counter.increment();
counter.increment();
console.log(counter.value()); // 2.

counter.decrement();
console.log(counter.value()); // 1.
4 dan melampirkan pendengar ke setiap
if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
14, seperti yang ditunjukkan

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
_4

Seperti disebutkan sebelumnya, setiap instance fungsi mengelola ruang lingkup dan penutupannya sendiri. Oleh karena itu, tidak bijaksana untuk tidak perlu membuat fungsi di dalam fungsi lain jika penutupan tidak diperlukan untuk tugas tertentu, karena akan berdampak negatif pada kinerja skrip baik dalam hal kecepatan pemrosesan dan konsumsi memori

Misalnya, saat membuat objek/kelas baru, metode biasanya harus dikaitkan dengan prototipe objek daripada didefinisikan ke dalam konstruktor objek. Alasannya adalah setiap kali konstruktor dipanggil, metode akan dipindahkan (yaitu, untuk setiap pembuatan objek)

Pertimbangkan kasus berikut

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
5

Karena kode sebelumnya tidak mengambil manfaat dari penggunaan closure dalam contoh khusus ini, kita dapat menulis ulang untuk menghindari penggunaan closure sebagai berikut

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
6

Namun, mendefinisikan ulang prototipe tidak disarankan. Contoh berikut malah ditambahkan ke prototipe yang ada

if (Math.random() > 0.5) {
  const x = 1;
} else {
  const x = 2;
}
console.log(x); // ReferenceError: x is not defined
7

Dalam dua contoh sebelumnya, prototipe yang diwariskan dapat digunakan bersama oleh semua objek dan definisi metode tidak perlu muncul di setiap pembuatan objek. Lihat Pewarisan dan rantai prototipe untuk lebih lanjut

Apa saja 3 jenis fungsi dalam JavaScript?

Ada 3 cara penulisan fungsi di JavaScript. .
Deklarasi Fungsi
Ekspresi Fungsi
Fungsi Panah

Bagaimana cara memanggil fungsi 3 kali dalam JavaScript?

Untuk menjalankan fungsi berkali-kali setelah waktu yang tetap, kami menggunakan beberapa fungsi. Metode JavaScript setInterval() . Metode ini memanggil fungsi pada interval tertentu (dalam ms). Metode ini akan terus memanggil fungsi hingga clearInterval() dijalankan, atau jendela ditutup.

Bagaimana Anda membuat fungsi bersarang di JavaScript?

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

Apa fungsi bersarang di JavaScript?

Karena fungsi bersarang adalah penutupan, ini berarti bahwa fungsi bersarang dapat "mewarisi" argumen dan variabel dari fungsi yang memuatnya . Dengan kata lain, inner function berisi cakupan dari outer function. Untuk meringkas. Fungsi bagian dalam hanya dapat diakses dari pernyataan di fungsi bagian luar.