Apa pengantar singkat untuk pelingkupan leksikal?
javascript
scoping
lexical-scope
Subba Rao
sumber
sumber
Jawaban:
Saya memahaminya melalui contoh. :)
Pertama, lingkup leksikal (juga disebut lingkup statis ), dalam sintaksis mirip C:
Setiap level dalam dapat mengakses level luarnya.
Ada cara lain, yang disebut lingkup dinamis yang digunakan oleh implementasi pertama Lisp , lagi-lagi dalam sintaksis mirip-C:
Berikut
fun
dapat baik aksesx
didummy1
ataudummy2
, ataux
dalam fungsi panggilanfun
denganx
menyatakan di dalamnya.akan mencetak 5,
akan mencetak 10.
Yang pertama disebut statis karena dapat disimpulkan pada waktu kompilasi, dan yang kedua disebut dinamis karena lingkup luarnya dinamis dan tergantung pada panggilan rantai fungsi.
Saya menemukan pelingkupan statis lebih mudah untuk mata. Sebagian besar bahasa berjalan seperti ini pada akhirnya, bahkan Lisp (dapat melakukan keduanya, bukan?). Pelingkupan dinamis seperti melewatkan referensi semua variabel ke fungsi yang dipanggil.
Sebagai contoh mengapa kompiler tidak dapat menyimpulkan ruang lingkup dinamis luar fungsi, pertimbangkan contoh terakhir kami. Jika kita menulis sesuatu seperti ini:
Rantai panggilan tergantung pada kondisi run time. Jika itu benar, maka rantai panggilan terlihat seperti:
Jika kondisinya salah:
Lingkup luar
fun
dalam kedua kasus adalah penelepon ditambah penelepon penelepon dan sebagainya .Hanya untuk menyebutkan bahwa bahasa C tidak memungkinkan fungsi bersarang atau pelingkupan dinamis.
sumber
JavaScript
. Karena itu saya pikir ini tidak boleh ditandai sebagai jawaban yang diterima. Ruang lingkup leksikal khusus di JS berbedafor
lingkaran adalah masalah umum. Lingkup leksikal untuk JavaScript hanya pada tingkat fungsi kecuali ES6let
atauconst
digunakan.Mari kita coba definisi sesingkat mungkin:
Lexical Scoping mendefinisikan bagaimana nama variabel dipecahkan dalam fungsi bersarang: fungsi dalam berisi lingkup fungsi induk bahkan jika fungsi induk telah kembali .
Hanya itu yang ada di sana!
sumber
Kode di atas akan mengembalikan "Saya hanya lokal". Itu tidak akan mengembalikan "Saya seorang global". Karena fungsi func () menghitung di mana awalnya didefinisikan yang berada di bawah lingkup fungsi whatismyscope.
Itu tidak akan mengganggu dari apa pun namanya (lingkup global / dari dalam fungsi lain bahkan), itu sebabnya nilai lingkup global saya global tidak akan dicetak.
Ini disebut pelingkupan leksikal di mana " fungsi dijalankan menggunakan rantai lingkup yang berlaku ketika didefinisikan " - menurut Panduan Definisi JavaScript.
Lingkup leksikal adalah konsep yang sangat kuat.
Semoga ini membantu..:)
sumber
Penjajakan leksikal (AKA statis) mengacu pada menentukan ruang lingkup variabel hanya berdasarkan posisinya dalam korpus teks kode. Variabel selalu mengacu pada lingkungan tingkat atasnya. Adalah baik untuk memahaminya dalam kaitannya dengan ruang lingkup dinamis.
sumber
Lingkup mendefinisikan area, di mana fungsi, variabel dan semacamnya tersedia. Ketersediaan variabel misalnya didefinisikan dalam konteksnya, katakanlah fungsi, file, atau objek, mereka didefinisikan. Kami biasanya memanggil variabel lokal ini.
Bagian leksikal berarti bahwa Anda dapat memperoleh ruang lingkup dari membaca kode sumber.
Lingkup leksikal juga dikenal sebagai lingkup statis.
Cakupan dinamis mendefinisikan variabel global yang dapat dipanggil atau dirujuk dari mana saja setelah ditetapkan. Kadang-kadang mereka disebut variabel global, meskipun variabel global dalam sebagian besar bahasa programmin memiliki ruang lingkup leksikal. Ini berarti, dapat diturunkan dari membaca kode bahwa variabel tersedia dalam konteks ini. Mungkin kita harus mengikuti kegunaan atau menyertakan klausa untuk menemukan instatiation atau definisi, tetapi kode / kompiler tahu tentang variabel di tempat ini.
Sebaliknya, dalam pelingkupan dinamis, Anda mencari di fungsi lokal, lalu Anda mencari di fungsi yang disebut fungsi lokal, lalu Anda mencari di fungsi yang memanggil fungsi itu, dan seterusnya, naik tumpukan panggilan. "Dinamis" mengacu pada perubahan, di mana tumpukan panggilan dapat berbeda setiap kali fungsi yang diberikan dipanggil, dan fungsi tersebut mungkin mengenai variabel yang berbeda tergantung dari mana ia dipanggil. (lihat disini )
Untuk melihat contoh menarik untuk ruang lingkup dinamis, lihat di sini .
Untuk perincian lebih lanjut lihat di sini dan di sini .
Beberapa contoh dalam Delphi / Object Pascal
Delphi memiliki ruang lingkup leksikal.
Delphi terdekat dengan ruang lingkup dinamis adalah pasangan fungsi RegisterClass () / GetClass (). Untuk penggunaannya lihat di sini .
Katakanlah waktu RegisterClass ([TmyClass]) dipanggil untuk mendaftar kelas tertentu tidak dapat diprediksi dengan membaca kode (dipanggil dengan metode klik tombol yang dipanggil oleh pengguna), kode panggilan GetClass ('TmyClass') akan mendapatkan sebuah hasil atau tidak. Panggilan ke RegisterClass () tidak harus dalam lingkup leksikal unit menggunakan GetClass ();
Kemungkinan lain untuk ruang lingkup dinamis adalah metode anonim (penutupan) dalam Delphi 2009, karena mereka tahu variabel dari fungsi panggilan mereka. Itu tidak mengikuti jalur panggilan dari sana secara rekursif dan karena itu tidak sepenuhnya dinamis.
sumber
Saya suka jawaban agnostik bahasa dan fitur lengkap dari orang-orang seperti @rak. Karena pertanyaan ini ditandai dengan JavaScript , saya ingin memasukkan beberapa catatan yang sangat spesifik untuk bahasa ini.
Dalam JavaScript, pilihan kami untuk pelingkupan adalah:
var _this = this; function callback(){ console.log(_this); }
callback.bind(this)
Perlu dicatat, saya pikir, bahwa JavaScript tidak benar-benar memiliki pelingkupan dinamis .
.bind
menyesuaikanthis
kata kunci, dan itu dekat, tetapi secara teknis tidak sama.Berikut adalah contoh yang menunjukkan kedua pendekatan. Anda melakukan ini setiap kali Anda membuat keputusan tentang bagaimana melakukan cakupan panggilan balik sehingga ini berlaku untuk janji, penangan acara, dan banyak lagi.
Leksikal
Inilah yang mungkin Anda sebut
Lexical Scoping
sebagai panggilan balik dalam JavaScript:Terikat
Cara lain untuk lingkup adalah menggunakan
Function.prototype.bind
:Metode-metode ini, sejauh yang saya tahu, setara secara perilaku.
sumber
bind
tidak memengaruhi cakupan.Ruang lingkup Lexical: Variabel dideklarasikan di luar fungsi adalah variabel global dan terlihat di mana-mana dalam program JavaScript. Variabel yang dideklarasikan di dalam fungsi memiliki cakupan fungsi dan hanya dapat dilihat oleh kode yang muncul di dalam fungsi tersebut.
sumber
IBM mendefinisikannya sebagai:
Contoh 1:
Contoh 2:
sumber
Lingkup leksikal berarti bahwa dalam kelompok fungsi bersarang, fungsi dalam memiliki akses ke variabel dan sumber daya lain dari lingkup induknya . Ini berarti bahwa fungsi anak terikat secara leksikal dengan konteks eksekusi orang tua mereka. Lingkup leksikal terkadang juga disebut sebagai lingkup statis .
Hal yang akan Anda perhatikan tentang ruang lingkup leksikal adalah bahwa ia bekerja maju, artinya nama dapat diakses oleh konteks eksekusi anak-anaknya. Tapi itu tidak bekerja mundur ke orang tuanya, artinya variabel
likes
tidak dapat diakses oleh orang tuanya.Ini juga memberi tahu kita bahwa variabel yang memiliki nama yang sama dalam konteks eksekusi yang berbeda mendapatkan prioritas dari atas ke bawah tumpukan eksekusi. Variabel, memiliki nama yang mirip dengan variabel lain, dalam fungsi terdalam (konteks paling atas dari tumpukan eksekusi) akan memiliki prioritas lebih tinggi.
Perhatikan bahwa ini diambil dari sini .
sumber
Dalam bahasa sederhana, ruang lingkup leksikal adalah variabel yang didefinisikan di luar ruang lingkup Anda atau ruang lingkup atas secara otomatis tersedia di dalam ruang lingkup Anda yang berarti Anda tidak perlu meneruskannya di sana.
Contoh:
// Output: JavaScript
sumber
bind
. Dengan mereka,bind
tidak lagi diperlukan. Untuk informasi lebih lanjut tentang perubahan ini, periksa stackoverflow.com/a/34361380/11127383Ada bagian penting dari percakapan seputar pelingkupan leksikal dan dinamis yang hilang: penjelasan sederhana tentang masa pakai dari variabel yang dicakup - atau ketika variabel dapat diakses.
Pelingkupan dinamis hanya sangat longgar sesuai dengan pelingkupan "global" dengan cara yang kita pikirkan secara tradisional (alasan saya mengemukakan perbandingan antara keduanya adalah karena hal itu telah disebutkan - dan saya tidak terlalu suka yang terkait penjelasan artikel yang ); mungkin yang terbaik adalah kita tidak membuat perbandingan antara global dan dinamis - meskipun menurut dugaan, menurut artikel yang ditautkan, "... [itu] berguna sebagai pengganti variabel yang dicakup secara global."
Jadi, dalam bahasa Inggris yang sederhana, apa perbedaan penting antara kedua mekanisme pelingkupan?
Pelingkupan leksikal telah didefinisikan dengan sangat baik di seluruh jawaban di atas: variabel yang dicakup secara leksikal tersedia - atau, dapat diakses - di tingkat lokal dari fungsi yang didefinisikan.
Namun - karena ini bukan fokus OP - pelingkupan dinamis belum menerima banyak perhatian dan perhatian yang diterimanya berarti mungkin perlu sedikit lebih banyak (itu bukan kritik atas jawaban lain, tetapi lebih merupakan "oh, jawaban itu membuat kami berharap ada sedikit lagi "). Jadi, ini sedikit lebih banyak:
Pelingkupan dinamis berarti bahwa suatu variabel dapat diakses oleh program yang lebih besar selama masa pemanggilan fungsi - atau, ketika fungsi tersebut dieksekusi. Sungguh, Wikipedia benar-benar melakukan pekerjaan yang baik dengan penjelasan tentang perbedaan antara keduanya. Agar tidak mengaburkannya, berikut adalah teks yang menjelaskan pelingkupan dinamis:
sumber
Ruang lingkup leksikal berarti bahwa suatu fungsi mencari variabel dalam konteks di mana ia didefinisikan, dan tidak dalam lingkup segera di sekitarnya.
Lihatlah bagaimana lingkup leksikal bekerja di Lisp jika Anda ingin lebih detail. Jawaban yang dipilih oleh Kyle Cronin dalam variabel Dynamic dan Lexical dalam Common Lisp jauh lebih jelas daripada jawaban di sini.
Secara kebetulan saya hanya belajar tentang ini di kelas Lisp, dan itu berlaku untuk JavaScript juga.
Saya menjalankan kode ini di konsol Chrome.
Keluaran:
sumber
Lingkup leksikal dalam JavaScript berarti bahwa variabel yang ditentukan di luar fungsi dapat diakses di dalam fungsi lain yang ditentukan setelah deklarasi variabel. Tetapi yang sebaliknya tidak benar; variabel yang didefinisikan di dalam suatu fungsi tidak akan dapat diakses di luar fungsi itu.
Konsep ini banyak digunakan dalam penutupan dalam JavaScript.
Katakanlah kita memiliki kode di bawah ini.
Sekarang, ketika Anda memanggil add () -> ini akan mencetak 3.
Jadi, fungsi add () mengakses variabel global
x
yang didefinisikan sebelum fungsi metode ditambahkan. Ini disebut karena pelingkupan leksikal dalam JavaScript.sumber
add()
fungsi yang dipanggil segera mengikuti potongan kode yang diberikan, itu juga akan mencetak 3. Ruang lingkup Lexical tidak hanya berarti bahwa suatu fungsi dapat mengakses variabel global di luar konteks lokal. Jadi kode contoh benar-benar tidak membantu menunjukkan apa arti pelingkupan leksikal. Menampilkan pelingkupan leksikal dalam kode benar-benar membutuhkan contoh balasan atau setidaknya penjelasan tentang kemungkinan interpretasi kode lainnya.Lingkup leksikal mengacu pada leksikon pengidentifikasi (misalnya, variabel, fungsi, dll.) Yang terlihat dari posisi saat ini di tumpukan eksekusi.
foo
danbar
selalu berada dalam leksikon pengidentifikasi yang tersedia karena bersifat global.Ketika
function1
dijalankan, ia memiliki akses ke leksikonfoo2
,bar2
,foo
, danbar
.Ketika
function2
dijalankan, ia memiliki akses ke leksikonfoo3
,bar3
,foo2
,bar2
,foo
, danbar
.Alasan fungsi global dan / atau luar tidak memiliki akses ke pengidentifikasi fungsi dalam adalah karena pelaksanaan fungsi itu belum terjadi dan oleh karena itu, tidak ada pengidentifikasi yang telah dialokasikan ke memori. Terlebih lagi, begitu konteks dalam dieksekusi, itu dihapus dari tumpukan eksekusi, yang berarti bahwa semua pengidentifikasi itu telah dikumpulkan dan tidak lagi tersedia.
Akhirnya, inilah sebabnya konteks eksekusi bersarang dapat SELALU mengakses konteks eksekusi leluhurnya dan karenanya mengapa ia memiliki akses ke leksikon pengidentifikasi yang lebih besar.
Lihat:
Terima kasih khusus kepada @ robr3rd untuk membantu menyederhanakan definisi di atas.
sumber
Inilah sudut pandang yang berbeda pada pertanyaan ini yang bisa kita dapatkan dengan mengambil langkah mundur dan melihat peran pelingkupan dalam kerangka interpretasi yang lebih besar (menjalankan program). Dengan kata lain, bayangkan Anda sedang membangun seorang juru bahasa (atau kompiler) untuk suatu bahasa dan bertanggung jawab untuk menghitung hasilnya, diberikan suatu program dan beberapa masukan untuk itu.
Interpretasi melibatkan mencatat tiga hal:
Status - yaitu, variabel dan lokasi memori yang dirujuk pada heap dan stack.
Operasi pada keadaan itu - yaitu, setiap baris kode dalam program Anda
The lingkungan di mana diberikan operasi berjalan - yaitu, proyeksi negara pada operasi.
Seorang penerjemah mulai pada baris pertama kode dalam suatu program, menghitung lingkungannya, menjalankan baris dalam lingkungan itu dan menangkap pengaruhnya pada keadaan program. Kemudian mengikuti alur kontrol program untuk mengeksekusi baris kode berikutnya, dan mengulangi proses sampai program berakhir.
Cara Anda menghitung lingkungan untuk operasi apa pun adalah melalui seperangkat aturan formal yang ditentukan oleh bahasa pemrograman. Istilah "mengikat" sering digunakan untuk menggambarkan pemetaan keadaan keseluruhan program ke nilai di lingkungan. Perhatikan bahwa dengan "keseluruhan negara" kami tidak berarti negara global, tetapi lebih merupakan jumlah total dari setiap definisi yang dapat dicapai, di setiap titik dalam eksekusi).
Ini adalah kerangka kerja di mana masalah pelingkupan didefinisikan. Sekarang ke bagian selanjutnya dari apa pilihan kita.
Ini adalah inti dari pelingkupan dinamis , di mana lingkungan tempat kode berjalan terikat dengan keadaan program sebagaimana ditentukan oleh konteks pelaksanaannya.
Dengan kata lain, dengan lingkup leksikal lingkungan yang dilihat oleh kode apa pun terikat dengan keadaan yang terkait dengan cakupan yang didefinisikan secara eksplisit dalam bahasa, seperti blok atau fungsi.
sumber
Pertanyaan kuno, tapi ini pendapat saya.
Lingkup leksikal (statis) mengacu pada cakupan variabel dalam kode sumber .
Dalam bahasa seperti JavaScript, di mana fungsi dapat diedarkan dan dilampirkan dan disambungkan kembali ke objek lain-lain, Anda mungkin memiliki cakupan yang tergantung pada siapa yang memanggil fungsi pada saat itu, tetapi tidak. Mengubah ruang lingkup seperti itu akan menjadi ruang lingkup dinamis, dan JavaScript tidak melakukan itu, kecuali mungkin dengan
this
referensi objek.Untuk mengilustrasikan poin:
Dalam contoh, variabel
a
didefinisikan secara global, tetapi dibayangi dalamdoit()
fungsi. Fungsi ini mengembalikan fungsi lain yang, seperti yang Anda lihat, bergantung padaa
variabel di luar cakupannya sendiri.Jika Anda menjalankan ini, Anda akan menemukan bahwa nilai yang digunakan adalah
aardvark
, bukanapple
yang, meskipun itu berada dalam ruang lingkuptest()
fungsi, bukan dalam ruang lingkup leksikal dari fungsi asli. Yaitu, ruang lingkup yang digunakan adalah ruang lingkup seperti yang muncul dalam kode sumber, bukan ruang lingkup di mana fungsi sebenarnya digunakan.Fakta ini dapat memiliki konsekuensi yang mengganggu. Misalnya, Anda mungkin memutuskan bahwa lebih mudah untuk mengatur fungsi Anda secara terpisah, dan kemudian menggunakannya ketika saatnya tiba, seperti dalam pengendali acara:
Contoh kode ini masing-masing. Anda dapat melihat bahwa karena pelingkupan leksikal, tombol
A
menggunakan variabel bagian dalam, sedangkan tombolB
tidak. Anda mungkin berakhir dengan fungsi bersarang lebih dari yang Anda inginkan.Ngomong-ngomong, dalam kedua contoh, Anda juga akan melihat bahwa variabel-variabel yang dicakup secara leksikal dalam tetap ada meskipun fungsi fungsi yang berisi telah berjalan dengan sendirinya. Ini disebut closure , dan mengacu pada akses fungsi bersarang ke variabel luar, bahkan jika fungsi luar telah selesai. JavaScript harus cukup pintar untuk menentukan apakah variabel-variabel itu tidak lagi diperlukan, dan jika tidak, dapatkah sampah mengumpulkannya.
sumber
Saya biasanya belajar dengan contoh, dan ini ada sesuatu:
sumber
Topik ini sangat terkait dengan
bind
fungsi bawaan dan diperkenalkan di ECMAScript 6 Arrow Functions . Itu benar-benar menjengkelkan, karena untuk setiap metode "kelas" (fungsi sebenarnya) baru yang ingin kami gunakan, kami harus melakukanbind
ini untuk memiliki akses ke ruang lingkup.JavaScript secara default tidak mengatur ruang lingkupnya
this
pada fungsi (tidak mengatur konteks padathis
). Secara default, Anda harus secara eksplisit mengatakan konteks mana yang ingin Anda miliki.Fungsi panah secara otomatis mendapatkan ruang lingkup leksikal yang disebut (memiliki akses ke definisi variabel dalam blok yang mengandungnya). Ketika menggunakan fungsi panah, ia secara otomatis mengikat
this
ke tempat di mana fungsi panah didefinisikan di tempat pertama, dan konteks fungsi panah ini adalah blok yang berisi.Lihat cara kerjanya dalam contoh sederhana di bawah ini.
Sebelum Fungsi Panah (tidak ada ruang lingkup leksikal secara default):
Dengan fungsi panah (lingkup leksikal secara default):
sumber