Pelingkupan leksikal dalam javascript didasarkan pada

Jika Anda seorang pemrogram JavaScript pemula, atau jika Anda telah mengutak-atik JQuery untuk melakukan beberapa animasi di situs web Anda, kemungkinan Anda kehilangan beberapa bagian penting dari pengetahuan tentang JavaScript

Salah satu konsep terpenting adalah bagaimana ruang lingkup mengikat "ini"

Untuk posting ini, saya akan berasumsi bahwa Anda memiliki pemahaman yang baik tentang sintaks/objek dasar JavaScript dan terminologi umum saat mendiskusikan ruang lingkup (blok vs. lingkup fungsi, kata kunci ini, leksikal vs. pelingkupan dinamis)

Lingkup Leksikal

Pertama, JavaScript memiliki pelingkupan leksikal dengan cakupan fungsi. Dengan kata lain, meskipun JavaScript sepertinya harus memiliki ruang lingkup blok karena menggunakan kurung kurawal {}, ruang lingkup baru dibuat hanya ketika Anda membuat fungsi baru

var outerFunction  = function(){

   if(true){
      var x = 5;
      //console.log(y); //line 1, ReferenceError: y not defined
   }

   var nestedFunction = function() {

      if(true){
         var y = 7;
         console.log(x); //line 2, x will still be known prints 5
      }

      if(true){
         console.log(y); //line 3, prints 7
       }
   }
   return nestedFunction;
}

var myFunction = outerFunction();
myFunction();

Dalam contoh ini, variabel x tersedia di mana saja di dalam outerFunction(). Juga, variabel y tersedia di mana saja dalam nestedFunction(), tetapi tidak ada yang tersedia di luar fungsi tempat mereka didefinisikan. Alasan untuk ini dapat dijelaskan dengan pelingkupan leksikal. Cakupan variabel ditentukan oleh posisinya dalam kode sumber. Untuk menyelesaikan variabel, JavaScript dimulai dari lingkup terdalam dan mencari keluar hingga menemukan variabel yang dicari. Pelingkupan leksikal bagus, karena kita dapat dengan mudah mengetahui nilai suatu variabel dengan melihat kodenya;

Penutupan

Fakta bahwa kita dapat mengakses variabel x mungkin masih membingungkan, karena biasanya variabel lokal di dalam suatu fungsi hilang setelah suatu fungsi selesai dieksekusi. Kami memanggil outerFunction() dan menugaskan hasilnya, nestedFunction(), ke

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

0. Bagaimana variabel x masih ada jika outerFunction() telah kembali?

Hanya mengakses variabel di luar lingkup langsung (tidak diperlukan pernyataan pengembalian) akan membuat sesuatu yang disebut penutupan. Jaringan Pengembangan Mozilla (MDN) memberikan definisi yang bagus

“Penutupan adalah jenis objek khusus yang menggabungkan dua hal. fungsi, dan lingkungan di mana fungsi itu dibuat. Lingkungan terdiri dari variabel lokal apa pun yang berada dalam ruang lingkup pada saat penutupan dibuat. ”

Karena x adalah anggota lingkungan yang membuat nestedFunction(), nestedFunction() akan memiliki akses ke sana. Cukup mudah? . Coba contoh ini, yang memiliki fungsi bersarang di dalam objek dengan beberapa properti

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

_

Mengapa warna dan usia tidak ditentukan pada baris 2?

JavaScript kehilangan cakupan ini saat digunakan di dalam fungsi yang terdapat di dalam fungsi lain. Ketika hilang, secara default, ini akan terikat ke objek jendela global. Dalam contoh kami, kebetulan objek jendela juga memiliki properti "nama" dengan nilai "jendela"

Mengontrol Konteks

Jadi bagaimana sekarang?

Kami tidak dapat mengubah cara kerja pelingkupan leksikal dalam JavaScript, tetapi kami dapat mengontrol konteks di mana kami memanggil fungsi kami. Konteks diputuskan saat runtime saat fungsi dipanggil, dan selalu terikat ke objek di mana fungsi dipanggil. Satu-satunya pengecualian untuk aturan ini adalah kasus fungsi bersarang di atas

Dengan mengatakan, ubah "konteks", maksud saya, kami mengubah apa sebenarnya "ini". Pada contoh di bawah ini, apa yang dicetak oleh “baris 1” dan “baris 2”?

var obj1 = {
   printThis: function() {
      console.log(this);
   }
};

var func1 = obj1.printThis;
obj1.printThis(); //line 1
func1(); //line 2

Baris 1 mencetak obj1. Baris 2 mencetak jendela. Konteks baris 1 adalah obj1, karena kami segera memanggil

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

4. Namun, di
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

_5, pertama-tama kita menyimpan referensi ke fungsi
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

4, lalu memanggilnya dalam konteks objek global; . Jika
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

_5 telah disarangkan dalam fungsi yang berbeda, itu akan menjadi konteksnya

Panggil, Ikat, dan Terapkan

Ada beberapa cara untuk mengontrol nilai ini, termasuk yang berikut ini

  • menyimpan referensi untuk ini di variabel lain
  • panggilan()
  • menerapkan()
  • mengikat()

Yang pertama

var cat = {
   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      var that = this;
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //prints correctly

      nestedFunction = function() {
         console.log("Name:", that.name, "Color:", that.color, "Age:", that.age); //prints correctly
      }
   nestedFunction();
   }
}
cat.printInfo();

_

Karena kami mengikat ini ke variabel itu, itu akan tersedia seperti variabel lainnya. Mari kita lihat sekarang

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

_8,
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

9, dan
var obj1 = {
   printThis: function() {
      console.log(this);
   }
};

var func1 = obj1.printThis;
obj1.printThis(); //line 1
func1(); //line 2
0, yang menurut saya sedikit lebih bersih

var cat = {
   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age);
      nestedFunction = function() {
         console.log("Name:", this.name, "Color:", this.color, "Age:", this.age);
      }
      nestedFunction.call(this);
      nestedFunction.apply(this);

      var storeFunction = nestedFunction.bind(this);
         storeFunction();
      }
}
cat.printInfo();

Fokus pada argumen pertama dari setiap fungsi. ini. Ini mengacu pada objek kucing. Sekarang, nestedFunction()_ ini mengacu pada objek kucing. Jika, alih-alih menyampaikan ini sebagai argumen, kami meneruskan objek "anjing", maka nestedFunction() ini mengacu pada anjing. Pada dasarnya, apa pun argumen pertama menjadi Fungsi bersarang () adalah ini

Jadi apa perbedaan antara ketiganya?

Perbedaan utama antara

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

8 dan
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

9 terletak pada cara menyampaikan argumen tambahan.
var obj1 = {
   printThis: function() {
      console.log(this);
   }
};

var func1 = obj1.printThis;
obj1.printThis(); //line 1
func1(); //line 2
5 mengambil beberapa argumen, dipisahkan dengan koma, yang memungkinkan nestedFunction() untuk memanfaatkannya.
var obj1 = {
   printThis: function() {
      console.log(this);
   }
};

var func1 = obj1.printThis;
obj1.printThis(); //line 1
func1(); //line 2
7 juga mengambil argumen tambahan dengan cara ini. Namun,
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

_9 menggunakan satu larik argumen, bukan beberapa argumen

Penting untuk diingat bahwa menggunakan

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

8 dan
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

9 sebenarnya memanggil fungsi Anda — jadi ini salah (perhatikan () pada nestedFunction)

   nestedFunction().call(this);

var obj1 = {
   printThis: function() {
      console.log(this);
   }
};

var func1 = obj1.printThis;
obj1.printThis(); //line 1
func1(); //line 2
7, di sisi lain, bagus karena memungkinkan Anda untuk mengubah apa referensi ini dan kemudian menyimpan referensi ke fungsi yang diubah dalam variabel untuk digunakan di lain waktu (lihat storeFunction dalam contoh kode di atas). Sementara itu, karena
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

8 dan
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

9 segera menjalankan fungsi tersebut, mereka mengembalikan hasil pemanggilan fungsi tersebut

Aplikasi praktis

Sejauh ini, kami telah melihat penutupan,

var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

8,
var cat = {

   name: "Gus",
   color: "gray",
   age: 15,

   printInfo: function() {
      console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 1, prints correctly

      nestedFunction = function() {
          console.log("Name:", this.name, "Color:", this.color, "Age:", this.age); //line 2, loses cat scope
      }

   nestedFunction();
   }
}
cat.printInfo(); //prints Name: window Color: undefined Age: undefined

9, dan
var obj1 = {
   printThis: function() {
      console.log(this);
   }
};

var func1 = obj1.printThis;
obj1.printThis(); //line 1
func1(); //line 2
0, tetapi kami belum membahas aplikasi praktis apa pun dan kapan harus menggunakan masing-masing untuk mendapatkan pengikatan yang benar dari ini

Apa itu pelingkupan leksikal?

Lingkup leksikal mengatur ruang lingkup fungsionalitas variabel tertentu menggunakan metode, yang memfasilitasi pemanggilan variabel dari blok kode di mana ia didefinisikan. Hanya selama fase kompilasi di mana ruang lingkup ditentukan

Apa aturan utama pelingkupan leksikal?

Apa aturan dasar pelingkupan leksikal? . Aturan dasar pelingkupan leksikal adalah bahwa fungsi JavaScript dijalankan menggunakan rantai cakupan yang berlaku saat didefinisikan .

Apa itu struktur leksikal dalam JavaScript?

Struktur leksikal bahasa pemrograman adalah kumpulan aturan dasar yang menentukan cara Anda menulis program dalam bahasa tersebut .

Apa itu pelingkupan leksikal dan dinamis dalam JavaScript?

Pelingkupan leksikal mengacu pada saat lokasi definisi fungsi menentukan variabel mana yang dapat Anda akses. Di sisi lain, pelingkupan dinamis menggunakan lokasi pemanggilan fungsi untuk menentukan variabel mana yang tersedia