Apa ruang lingkup variabel dalam javascript? Apakah mereka memiliki ruang lingkup yang sama di dalam dibandingkan dengan di luar fungsi? Atau apakah itu penting? Juga, di mana variabel disimpan jika mereka didefinisikan secara global?
Apa ruang lingkup variabel dalam javascript? Apakah mereka memiliki ruang lingkup yang sama di dalam dibandingkan dengan di luar fungsi? Atau apakah itu penting? Juga, di mana variabel disimpan jika mereka didefinisikan secara global?
Jawaban:
JavaScript memiliki ruang lingkup dan penutupan leksikal (juga disebut statis). Ini berarti Anda dapat memberi tahu ruang lingkup pengidentifikasi dengan melihat kode sumber.
Keempat lingkup tersebut adalah:
Di luar kasus khusus lingkup global dan modul, variabel dideklarasikan menggunakan var
(lingkup fungsi), let
(lingkup blok) dan const
(lingkup blok). Sebagian besar bentuk lain dari pernyataan pengidentifikasi memiliki cakupan blok dalam mode ketat.
Lingkup adalah wilayah basis kode tempat pengidentifikasi valid.
Lingkungan leksikal adalah pemetaan antara nama pengidentifikasi dan nilai yang terkait dengannya.
Lingkup terbentuk dari sarang yang terhubung dari lingkungan leksikal, dengan setiap tingkat dalam sarang bersesuaian dengan lingkungan leksikal dari konteks eksekusi leluhur.
Lingkungan leksikal yang terhubung ini membentuk "rantai" lingkup. Resolusi pengidentifikasi adalah proses pencarian di sepanjang rantai ini untuk pengidentifikasi yang cocok.
Resolusi pengidentifikasi hanya terjadi dalam satu arah: luar. Dengan cara ini, lingkungan leksikal luar tidak dapat "melihat" ke dalam lingkungan leksikal dalam.
Ada tiga faktor yang bersangkutan dalam memutuskan lingkup dari sebuah identifier dalam JavaScript:
Beberapa cara pengidentifikasi dapat dinyatakan:
var
, let
danconst
var
dalam mode non-ketat)import
pernyataaneval
Beberapa pengidentifikasi lokasi dapat dinyatakan:
Pengidentifikasi yang dideklarasikan menggunakan var
lingkup fungsi , terpisah dari ketika mereka dideklarasikan secara langsung dalam konteks global, dalam hal ini mereka ditambahkan sebagai properti pada objek global dan memiliki cakupan global. Ada aturan terpisah untuk penggunaannya dalam eval
fungsi.
Pengidentifikasi dideklarasikan menggunakan let
dan const
memiliki cakupan blok , selain dari ketika mereka dinyatakan secara langsung dalam konteks global, dalam hal ini mereka memiliki lingkup global.
Catatan: let
, const
dan var
semua mengangkat . Ini berarti bahwa posisi logis dari definisi mereka adalah bagian atas dari ruang lingkup yang dilampirkan (blok atau fungsi). Namun, variabel dinyatakan menggunakan let
dan const
tidak dapat dibaca atau ditugaskan sampai kontrol telah melewati titik pernyataan dalam kode sumber. Periode sementara dikenal sebagai zona mati temporal.
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
Nama parameter fungsi dicakup ke badan fungsi. Perhatikan bahwa ada sedikit kerumitan dalam hal ini. Fungsi yang dideklarasikan sebagai argumen default menutup daftar parameter , dan bukan badan fungsi.
Deklarasi fungsi memiliki ruang lingkup blok dalam mode ketat dan ruang lingkup fungsi dalam mode non-ketat. Catatan: mode non-ketat adalah seperangkat aturan yang muncul berdasarkan pada implementasi historis unik dari browser yang berbeda.
Ekspresi fungsi yang dinamai dicakup untuk dirinya sendiri (mis. Untuk tujuan rekursi).
Dalam mode non-ketat, properti yang didefinisikan secara implisit pada objek global memiliki cakupan global, karena objek global berada di bagian atas rantai cakupan. Dalam mode ketat ini tidak diizinkan.
Dalam eval
string, variabel yang dideklarasikan menggunakan var
akan ditempatkan dalam lingkup saat ini, atau, jika eval
digunakan secara tidak langsung, sebagai properti pada objek global.
Berikut ini akan melempar ReferenceError karena nama x
, y
dan z
tidak memiliki arti di luar fungsi f
.
function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
Berikut ini akan melempar ReferenceError untuk y
dan z
, tetapi tidak untuk x
, karena visibilitas x
tidak dibatasi oleh blok. Blok yang menentukan tubuh struktur kontrol seperti if
, for
dan while
, berperilaku sama.
{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope
Berikut ini, x
terlihat di luar loop karena var
memiliki lingkup fungsi:
for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)
... karena perilaku ini, Anda harus berhati-hati dalam menutup variabel yang dideklarasikan menggunakan var
dalam loop. Hanya ada satu instance variabelx
dideklarasikan di sini, dan itu duduk secara logis di luar loop.
Cetakan berikut 5
, lima kali, dan kemudian mencetak 5
untuk keenam kalinya di console.log
luar loop:
for(var x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop
Cetakan berikut undefined
karena x
diblok-blok. Callback dijalankan satu per satu secara tidak sinkron. Perilaku baru untuk let
variabel berarti bahwa setiap fungsi anonim ditutup melalui variabel yang berbeda bernama x
(tidak seperti yang akan dilakukan dengan var
), dan bilangan bulat 0
melalui 4
dicetak.
for(let x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined
Berikut ini TIDAK akan melempar ReferenceError
karena visibilitas x
tidak dibatasi oleh blok; Namun, itu akan mencetak undefined
karena variabel belum diinisialisasi (karena if
pernyataan).
if(false) {
var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised
Variabel yang dideklarasikan di bagian atas for
loop menggunakan let
scoped ke badan loop:
for(let x = 0; x < 10; ++x) {}
console.log(typeof x) // undefined, because `x` is block-scoped
Berikut ini akan melempar ReferenceError
karena visibilitas x
dibatasi oleh blok:
if(false) {
let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped
Variabel yang dideklarasikan menggunakan var
, let
atau const
semuanya dicakup dalam modul:
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
Berikut ini akan mendeklarasikan properti pada objek global, karena variabel yang dideklarasikan menggunakan var
dalam konteks global, ditambahkan sebagai properti ke objek global:
var x = 1
console.log(window.hasOwnProperty('x')) // true
let
dan const
dalam konteks global tidak menambahkan properti ke objek global, tetapi masih memiliki cakupan global:
let x = 1
console.log(window.hasOwnProperty('x')) // false
Parameter fungsi dapat dianggap dideklarasikan di badan fungsi:
function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function
Parameter blok tangkap dicakup ke badan blok tangkap:
try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block
Ekspresi fungsi yang dinamai hanya mencakup ekspresi itu sendiri:
(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression
Dalam mode non-ketat, properti yang didefinisikan secara implisit pada objek global memiliki cakupan global. Dalam mode ketat Anda mendapatkan kesalahan.
x = 1 // implicitly defined property on the global object (no "var"!)
console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true
Dalam mode non-ketat, deklarasi fungsi memiliki cakupan fungsi. Dalam mode ketat mereka memiliki ruang lingkup blok.
'use strict'
{
function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped
Lingkup didefinisikan sebagai wilayah leksikal kode tempat pengidentifikasi valid.
Dalam JavaScript, setiap fungsi-objek memiliki [[Environment]]
referensi tersembunyi yang merupakan referensi ke lingkungan leksikal dari konteks eksekusi (stack frame) di mana ia dibuat.
Ketika Anda memanggil suatu fungsi, [[Call]]
metode tersembunyi disebut. Metode ini menciptakan konteks eksekusi baru dan membangun tautan antara konteks eksekusi baru dan lingkungan leksikal dari objek-fungsi. Itu melakukan ini dengan menyalin [[Environment]]
nilai pada objek-fungsi, ke referensi luar bidang pada lingkungan leksikal dari konteks eksekusi baru.
Perhatikan bahwa tautan ini antara konteks eksekusi baru dan lingkungan leksikal dari objek fungsi disebut closure .
Jadi, dalam JavaScript, ruang lingkup diimplementasikan melalui lingkungan leksikal yang dihubungkan bersama dalam "rantai" oleh referensi luar. Rantai lingkungan leksikal ini disebut rantai lingkup, dan resolusi pengidentifikasi terjadi dengan mencari rantai untuk pengidentifikasi yang cocok.
Cari tahu lebih lanjut .
Javascript menggunakan rantai lingkup untuk menetapkan ruang lingkup untuk fungsi yang diberikan. Biasanya ada satu lingkup global, dan setiap fungsi yang didefinisikan memiliki cakupan bersarangnya sendiri. Setiap fungsi yang didefinisikan dalam fungsi lain memiliki cakupan lokal yang terkait dengan fungsi luar. Selalu posisi dalam sumber yang menentukan ruang lingkup.
Elemen dalam rantai lingkup pada dasarnya adalah Peta dengan pointer ke lingkup induknya.
Saat menyelesaikan variabel, javascript dimulai pada cakupan terdalam dan mencari ke luar.
Variabel yang dinyatakan secara global memiliki cakupan global. Variabel yang dideklarasikan dalam suatu fungsi dibatasi untuk fungsi itu, dan membayangi variabel global dengan nama yang sama.
(Saya yakin ada banyak seluk-beluk yang dapat ditunjukkan oleh programmer JavaScript nyata dalam jawaban lain. Khususnya saya menemukan halaman ini tentang apa sebenarnya this
artinya setiap saat. Mudah-mudahan tautan yang lebih perkenalan ini cukup untuk membantu Anda memulai. .)
Secara tradisional, JavaScript benar-benar hanya memiliki dua jenis ruang lingkup:
Saya tidak akan menguraikan ini, karena sudah ada banyak jawaban lain yang menjelaskan perbedaannya.
The spesifikasi JavaScript terbaru kini juga memungkinkan lingkup ketiga:
Secara tradisional, Anda membuat variabel Anda seperti ini:
var myVariable = "Some text";
Variabel ruang lingkup blok dibuat seperti ini:
let myVariable = "Some text";
Untuk memahami perbedaan antara ruang lingkup fungsional dan ruang lingkup blok, pertimbangkan kode berikut:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Di sini, kita dapat melihat bahwa variabel kita j
hanya dikenal di awal untuk loop, tetapi tidak sebelum dan sesudah. Namun, variabel kami i
dikenal di seluruh fungsi.
Juga, pertimbangkan bahwa variabel blok ruang tidak diketahui sebelum mereka dinyatakan karena mereka tidak diangkat. Anda juga tidak diizinkan untuk mendeklarasikan ulang variabel scoping blok yang sama dalam blok yang sama. Hal ini membuat variabel yang dicakup blok lebih rentan kesalahan daripada variabel yang dicakup secara global atau fungsional, yang diangkat dan yang tidak menghasilkan kesalahan jika terjadi deklarasi berganda.
Apakah aman digunakan hari ini atau tidak, tergantung pada lingkungan Anda:
Jika Anda menulis kode JavaScript sisi-server ( Node.js ), Anda dapat menggunakan let
pernyataan dengan aman .
Jika Anda menulis kode JavaScript sisi klien dan menggunakan transpiler berbasis browser (seperti Traceur atau babel-standalone ), Anda dapat menggunakan let
pernyataan itu dengan aman , namun kode Anda kemungkinan tidak optimal sehubungan dengan kinerja.
Jika Anda menulis kode JavaScript sisi klien dan menggunakan transpiler berbasis Node (seperti skrip traceur shell atau Babel ), Anda dapat menggunakan let
pernyataan dengan aman . Dan karena browser Anda hanya akan tahu tentang kode yang diubahnya, kelemahan kinerja harus dibatasi.
Jika Anda menulis kode JavaScript sisi klien dan tidak menggunakan transpiler, Anda perlu mempertimbangkan dukungan browser.
Ini adalah beberapa browser yang tidak mendukung let
sama sekali:
Untuk gambaran umum terkini tentang browser yang mendukung let
pernyataan pada saat Anda membaca jawaban ini, lihat halaman iniCan I Use
.
(*) Variabel cakupan global dan fungsional dapat diinisialisasi dan digunakan sebelum mereka dinyatakan karena variabel JavaScript diangkat . Ini berarti bahwa deklarasi selalu jauh di atas cakupan.
Ini sebuah contoh:
<script>
var globalVariable = 7; //==window.globalVariable
function aGlobal( param ) { //==window.aGlobal();
//param is only accessible in this function
var scopedToFunction = {
//can't be accessed outside of this function
nested : 3 //accessible by: scopedToFunction.nested
};
anotherGlobal = {
//global because there's no `var`
};
}
</script>
Anda akan ingin menyelidiki penutupan, dan bagaimana menggunakannya untuk membuat anggota pribadi .
Kuncinya, seperti yang saya mengerti, adalah bahwa Javascript memiliki fungsi tingkat scoping vs ruang lingkup blok C yang lebih umum.
Dalam "Javascript 1.7" (ekstensi Mozilla ke Javascript) kita juga dapat mendeklarasikan variabel blok-lingkup dengan let
pernyataan :
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
let
.
Gagasan pelingkupan dalam JavaScript saat awalnya dirancang oleh Brendan Eich berasal dari bahasa penulisan HyperCard HyperTalk .
Dalam bahasa ini, tampilan dilakukan mirip dengan tumpukan kartu indeks. Ada kartu master yang disebut sebagai latar belakang. Itu transparan dan dapat dilihat sebagai kartu terbawah. Konten apa pun pada kartu dasar ini dibagikan dengan kartu yang diletakkan di atasnya. Setiap kartu yang ditempatkan di atas memiliki kontennya sendiri yang diutamakan daripada kartu sebelumnya, tetapi masih memiliki akses ke kartu sebelumnya jika diinginkan.
Inilah tepatnya bagaimana sistem pelingkupan JavaScript dirancang. Hanya saja namanya berbeda. Kartu-kartu dalam JavaScript dikenal sebagai Execution Contexts ECMA . Masing-masing dari konteks ini mengandung tiga bagian utama. Lingkungan variabel, lingkungan leksikal, dan ikatan ini. Kembali ke referensi kartu, lingkungan leksikal berisi semua konten dari kartu sebelumnya yang lebih rendah di tumpukan. Konteks saat ini adalah di bagian atas tumpukan dan konten yang dinyatakan di sana akan disimpan dalam lingkungan variabel. Lingkungan variabel akan didahulukan dalam kasus penamaan tabrakan.
Ikatan ini akan menunjuk ke objek yang berisi. Kadang-kadang lingkup atau konteks eksekusi berubah tanpa objek yang berubah berubah, seperti dalam fungsi yang dideklarasikan di mana objek yang berisi mungkin window
atau fungsi konstruktor.
Konteks eksekusi ini dibuat setiap kali kontrol waktu ditransfer. Kontrol ditransfer ketika kode mulai dijalankan, dan ini terutama dilakukan dari eksekusi fungsi.
Jadi itulah penjelasan teknisnya. Dalam praktiknya, penting untuk diingat dalam JavaScript
Menerapkan ini ke salah satu contoh sebelumnya (5. "Penutupan") di halaman ini, adalah mungkin untuk mengikuti tumpukan konteks eksekusi. Dalam contoh ini ada tiga konteks dalam tumpukan. Mereka didefinisikan oleh konteks luar, konteks dalam fungsi segera dipanggil oleh var enam, dan konteks dalam fungsi yang dikembalikan di dalam fungsi segera dipanggil var enam.
i ) Konteks luar. Ia memiliki lingkungan variabel dari a = 1
ii ) Konteks IIFE, ia memiliki lingkungan leksikal dari a = 1, tetapi lingkungan variabel dari a = 6 yang diutamakan dalam tumpukan
iii ) Konteks fungsi yang dikembalikan, ia memiliki konteks leksikal lingkungan a = 6 dan itu adalah nilai yang dirujuk dalam peringatan ketika dipanggil.
1) Ada ruang lingkup global, ruang lingkup fungsi, dan dengan dan lingkup menangkap. Tidak ada lingkup level 'blok' secara umum untuk variabel - pernyataan with dan catch menambahkan nama ke blok mereka.
2) Ruang lingkup disarang oleh fungsi sampai ke lingkup global.
3) Properti diselesaikan dengan melalui rantai prototipe. Pernyataan with membawa nama properti objek ke dalam ruang lingkup leksikal yang didefinisikan oleh blok with.
EDIT: ECMAAScript 6 (Harmony) dispesifikasi untuk mendukung let, dan saya tahu chrome memungkinkan bendera 'harmoni', jadi mungkin itu mendukungnya ..
Biarkan akan menjadi dukungan untuk pelingkupan tingkat blok, tetapi Anda harus menggunakan kata kunci untuk mewujudkannya.
EDIT: Berdasarkan Benjamin yang menunjukkan dengan dan menangkap pernyataan di komentar, saya telah mengedit posting, dan menambahkan lebih banyak. Pernyataan with with dan catch mengenalkan variabel ke dalam bloknya masing-masing, dan itu adalah lingkup blok. Variabel-variabel ini alias sifat-sifat objek yang diteruskan ke dalamnya.
//chrome (v8)
var a = { 'test1':'test1val' }
test1 // error not defined
with (a) { var test1 = 'replaced' }
test1 // undefined
a // a.test1 = 'replaced'
EDIT: Contoh klarifikasi:
test1 dicakup ke dalam dengan blok, tetapi alias a.test1. 'Var test1' menciptakan variabel test1 baru dalam konteks leksikal atas (fungsi, atau global), kecuali itu adalah properti dari a - yang mana itu.
Astaga! Hati-hati menggunakan 'with' - sama seperti var adalah noop jika variabel sudah didefinisikan dalam fungsi, itu juga noop sehubungan dengan nama yang diimpor dari objek! Sedikit mengungkit nama yang sudah didefinisikan akan membuat ini jauh lebih aman. Saya pribadi tidak akan pernah menggunakannya dengan ini.
with
pernyataan ini merupakan bentuk blok scoping tetapi catch
klausa adalah bentuk jauh lebih umum (Fun Bahkan, v8 alat catch
denganwith
) - itu cukup banyak satu-satunya bentuk blok scoping di JavaScript itu sendiri (Yaitu, fungsi, global, try / catch , dengan dan turunannya), namun lingkungan host memiliki gagasan pelingkupan yang berbeda - misalnya acara inline di browser dan modul vm NodeJS.
Saya menemukan bahwa banyak orang yang baru mengenal JavaScript mengalami kesulitan memahami bahwa pewarisan tersedia secara default dalam bahasa dan lingkup fungsi adalah satu-satunya ruang lingkup, sejauh ini. Saya memberikan ekstensi untuk ahli kecantikan yang saya tulis pada akhir tahun lalu yang disebut JSPretty. Fitur warna lingkup fungsi dalam kode dan selalu mengaitkan warna ke semua variabel yang dinyatakan dalam lingkup itu. Penutupan secara visual ditunjukkan ketika variabel dengan warna dari satu lingkup digunakan dalam lingkup yang berbeda.
Coba fitur di:
Lihat demo di:
Lihat kode di:
Saat ini fitur ini menawarkan dukungan untuk kedalaman 16 fungsi bersarang, tetapi saat ini tidak mewarnai variabel global.
JavaScript hanya memiliki dua jenis ruang lingkup:
var
kata kunci memiliki cakupan fungsional.Setiap kali suatu fungsi dipanggil, objek lingkup variabel dibuat (dan termasuk dalam rantai lingkup) yang diikuti oleh variabel dalam JavaScript.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
Rantai cakupan ->
a
danouter
fungsinya berada di level teratas dalam rantai lingkup.variable scope object
(dan termasuk dalam rantai lingkup) ditambahkan dengan variabel b
di dalamnya.Sekarang ketika sebuah variabel a
diperlukan, pertama-tama mencari ruang lingkup variabel terdekat dan jika variabel tidak ada di sana daripada pindah ke objek berikutnya dari rantai ruang lingkup variabel. Yang dalam hal ini adalah tingkat jendela.
Hanya untuk menambah jawaban lain, ruang lingkup adalah daftar pencarian dari semua pengidentifikasi yang dideklarasikan (variabel), dan menegakkan seperangkat aturan ketat tentang bagaimana ini dapat diakses oleh kode yang sedang dieksekusi. Pencarian ini mungkin untuk keperluan menugaskan ke variabel, yang merupakan referensi LHS (sisi kiri), atau mungkin untuk tujuan mengambil nilainya, yang merupakan referensi RHS (sisi kanan). Pencarian ini adalah apa yang dilakukan mesin JavaScript secara internal saat kompilasi dan eksekusi kode.
Jadi dari perspektif ini, saya berpikir bahwa sebuah gambar akan membantu yang saya temukan dalam ebook Scopes and Closures oleh Kyle Simpson:
Mengutip dari ebook-nya:
Bangunan tersebut merepresentasikan aturan lingkup ruang lingkup program kami. Lantai pertama bangunan mewakili ruang lingkup Anda saat ini mengeksekusi, dimanapun Anda berada. Tingkat teratas bangunan adalah ruang lingkup global. Anda menyelesaikan referensi LHS dan RHS dengan melihat lantai Anda saat ini, dan jika Anda tidak menemukannya, naik lift ke lantai berikutnya, lihat ke sana, lalu ke depan, dan seterusnya. Setelah Anda mencapai lantai atas (ruang lingkup global), Anda akan menemukan apa yang Anda cari, atau tidak. Tapi Anda harus berhenti.
Satu hal yang perlu diperhatikan adalah, "Lingkup pencarian berhenti begitu menemukan kecocokan pertama".
Gagasan "tingkat cakupan" ini menjelaskan mengapa "ini" dapat diubah dengan ruang lingkup yang baru dibuat, jika dilihat dalam fungsi bersarang. Berikut adalah tautan yang mencakup semua detail ini, Semua yang Anda ingin tahu tentang cakupan javascript
jalankan kodenya. berharap ini akan memberi gambaran tentang pelingkupan
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
Variabel global persis seperti bintang global (Jackie Chan, Nelson Mandela). Anda dapat mengaksesnya (mendapatkan atau mengatur nilai), dari bagian mana pun dari aplikasi Anda. Fungsi global seperti acara global (Tahun Baru, Natal). Anda dapat mengeksekusi (memanggil) mereka dari bagian mana pun dari aplikasi Anda.
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
Jika Anda berada di AS, Anda mungkin mengenal Kim Kardashian, selebritas terkenal (entah bagaimana ia berhasil membuat tabloid). Tetapi orang-orang di luar AS tidak akan mengenalinya. Dia adalah bintang lokal, terikat ke wilayahnya.
Variabel lokal seperti bintang lokal. Anda hanya dapat mengaksesnya (mendapatkan atau mengatur nilai) di dalam ruang lingkup. Fungsi lokal seperti acara lokal - Anda hanya dapat mengeksekusi (merayakan) di dalam lingkup itu. Jika Anda ingin mengaksesnya dari luar ruang lingkup, Anda akan mendapatkan kesalahan referensi
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
Periksa artikel ini untuk pemahaman mendalam tentang ruang lingkup
Hanya ada hampir dua jenis cakupan JavaScript:
Jadi, setiap blok selain fungsi tidak membuat ruang lingkup baru. Itu menjelaskan mengapa for-loop menimpa variabel cakupan luar:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
Sebagai gantinya menggunakan fungsi:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
Dalam contoh pertama, tidak ada ruang lingkup blok, jadi variabel yang dideklarasikan awalnya ditimpa. Dalam contoh kedua, ada ruang lingkup baru karena fungsi, sehingga variabel yang awalnya dideklarasikan dibagikan, dan tidak ditimpa.
Itu hampir semua yang perlu Anda ketahui dalam hal pelingkupan JavaScript, kecuali:
Jadi Anda dapat melihat pelingkupan JavaScript sebenarnya sangat sederhana, meskipun tidak selalu intuitif. Beberapa hal yang harus diperhatikan:
Jadi kode ini:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
setara dengan:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
Ini mungkin tampak berlawanan dengan intuisi, tetapi masuk akal dari perspektif perancang bahasa yang sangat penting.
const
' dan ' let
'Anda harus menggunakan scoping blok untuk setiap variabel yang Anda buat, seperti kebanyakan bahasa utama lainnya. var
sudah usang . Ini membuat kode Anda lebih aman dan lebih dapat dikelola.
const
harus digunakan untuk 95% kasus . Itu membuatnya sehingga referensi variabel tidak dapat berubah. Array, objek, dan properti DOM node dapat berubah dan seharusnya terjadi const
.
let
harus digunakan untuk variabel apa saja yang akan dipindahkan. Ini termasuk dalam for loop. Jika Anda pernah mengubah nilai di luar inisialisasi, gunakan let
.
Cakupan blok berarti bahwa variabel hanya akan tersedia dalam tanda kurung di mana ia dinyatakan. Ini meluas ke lingkup internal, termasuk fungsi anonim yang dibuat dalam ruang lingkup Anda.
Coba contoh menarik ini. Dalam contoh di bawah ini jika a adalah numerik yang diinisialisasi pada 0, Anda akan melihat 0 dan kemudian 1. Kecuali a adalah objek dan javascript akan memberikan f1 sebuah pointer dari bukan salinannya. Hasilnya adalah Anda mendapatkan peringatan yang sama di kedua kali.
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
Hanya ada lingkup fungsi di JS. Tidak memblokir cakupan! Anda dapat melihat apa yang mengangkat juga.
var global_variable = "global_variable";
var hoisting_variable = "global_hoist";
// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);
if (true) {
// The variable block will be global, on true condition.
var block = "block";
}
console.log("global_scope: - block: " + block);
function local_function() {
var local_variable = "local_variable";
console.log("local_scope: - local_variable: " + local_variable);
console.log("local_scope: - global_variable: " + global_variable);
console.log("local_scope: - block: " + block);
// The hoisting_variable is undefined at the moment.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
var hoisting_variable = "local_hoist";
// The hoisting_variable is now set as a local one.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}
local_function();
// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
Pemahaman saya adalah bahwa ada 3 lingkup: ruang lingkup global, tersedia secara global; cakupan lokal, tersedia untuk seluruh fungsi terlepas dari blok; dan ruang lingkup blok, hanya tersedia untuk blok, pernyataan, atau ekspresi yang digunakan. Ruang lingkup global dan lokal ditunjukkan dengan kata kunci 'var', baik di dalam fungsi atau di luar, dan ruang lingkup blok ditunjukkan dengan kata kunci 'let'.
Bagi mereka yang percaya hanya ada lingkup global dan lokal, tolong jelaskan mengapa Mozilla akan memiliki seluruh halaman yang menggambarkan nuansa ruang lingkup blok di JS.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Masalah yang sangat umum belum dijelaskan bahwa front-end coders sering mengalami adalah ruang lingkup yang terlihat oleh pengendali event inline dalam HTML - misalnya, dengan
<button onclick="foo()"></button>
Cakupan variabel yang on*
dapat dirujuk oleh atribut harus :
querySelector
sebagai variabel mandiri akan mengarah ke document.querySelector
; jarang)Kalau tidak, Anda akan mendapatkan ReferenceError ketika pawang dipanggil. Jadi, misalnya, jika inline handler mereferensikan fungsi yang didefinisikan di dalam window.onload
atau $(function() {
, referensi akan gagal, karena inline handler hanya boleh mereferensikan variabel dalam lingkup global, dan fungsinya bukan global:
Properti dari document
dan properti dari elemen handler dilampirkan juga dapat dirujuk sebagai variabel mandiri di dalam handler inline karena handler inline dipanggil dalam dua with
blok , satu untuk document
, satu untuk elemen. Rantai lingkup variabel di dalam penangan ini sangat tidak intuitif , dan penangan acara kerja mungkin akan memerlukan fungsi untuk menjadi global (dan polusi global yang tidak perlu mungkin harus dihindari ).
Karena rantai ruang lingkup di dalam penangan inline sangat aneh , dan karena penangan inline membutuhkan polusi global untuk bekerja, dan karena penangan inline kadang-kadang membutuhkan tali yang jelek keluar ketika melewati argumen, mungkin lebih mudah untuk menghindari mereka. Alih-alih, lampirkan penangan acara menggunakan Javascript (seperti dengan addEventListener
), bukan dengan markup HTML.
Pada catatan yang berbeda, tidak seperti <script>
tag normal , yang berjalan di tingkat atas, kode di dalam modul ES6 berjalan dalam cakupan privasinya sendiri. Variabel yang ditentukan di bagian atas <script>
tag normal adalah global, sehingga Anda dapat merujuknya ke <script>
tag lain , seperti ini:
Tetapi level teratas dari modul ES6 tidak bersifat global. Variabel yang dideklarasikan di bagian atas modul ES6 hanya akan terlihat di dalam modul itu, kecuali jika variabel tersebut secara eksplisit export
diedit, atau kecuali jika itu ditugaskan ke properti objek global.
Tingkat atas modul ES6 mirip dengan bagian dalam IIFE pada tingkat atas secara normal <script>
. Modul ini dapat merujuk variabel apa pun yang bersifat global, dan tidak ada yang dapat merujuk apa pun di dalam modul kecuali modul tersebut dirancang secara eksplisit untuknya.
Dalam JavaScript ada dua jenis ruang lingkup:
Fungsi di bawah ini memiliki variabel cakupan lokal carName
. Dan variabel ini tidak dapat diakses dari luar fungsi.
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
Kelas Di Bawah ini memiliki variabel lingkup Global carName
. Dan variabel ini dapat diakses dari mana saja di kelas.
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
ES5
dan sebelumnya:Variabel dalam Javascript pada awalnya (pra ES6
) secara fungsi scoped. Istilah yang dicakup secara leksikal berarti bahwa Anda dapat melihat ruang lingkup variabel dengan 'melihat' kode.
Setiap variabel yang dideklarasikan dengan var
kata kunci dicakup dalam fungsi. Namun, jika fungsi lain dideklarasikan di dalam fungsi itu fungsi-fungsi tersebut akan memiliki akses ke variabel fungsi luar. Ini disebut rantai lingkup . Ini bekerja dengan cara berikut:
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';
function outerFunc () {
// outerFunc scope
var foo = 'outerFunc';
var foobar = 'outerFunc';
innerFunc();
function innerFunc(){
// innerFunc scope
var foo = 'innerFunc';
console.log(foo);
console.log(bar);
console.log(foobar);
}
}
outerFunc();
Apa yang terjadi ketika kita mencoba untuk log variabel foo
, bar
dan foobar
ke konsol adalah sebagai berikut:
innerFunc
itu sendiri. Oleh karena itu, nilai foo diselesaikan ke string innerFunc
.innerFunc
itu sendiri. Karena itu, kita perlu mendaki rantai ruang lingkup . Pertama-tama kita melihat fungsi luar di mana fungsi innerFunc
itu didefinisikan. Ini fungsinya outerFunc
. Dalam lingkup outerFunc
kita dapat menemukan bar variabel, yang menampung string 'outerFunc'.ES6
(ES 2015) dan lebih lama:Konsep lingkup leksikal dan scopechain yang sama masih berlaku di ES6
. Namun cara baru untuk mendeklarasikan variabel diperkenalkan. Ada yang berikut ini:
let
: membuat variabel blok cakupanconst
: membuat variabel scoped blok yang harus diinisialisasi dan tidak dapat dipindahkanPerbedaan terbesar antara var
dan let
/ const
adalah bahwa var
adalah fungsi scoped sedangkan let
/ const
adalah blok scoped. Berikut adalah contoh untuk menggambarkan ini:
let letVar = 'global';
var varVar = 'global';
function foo () {
if (true) {
// this variable declared with let is scoped to the if block, block scoped
let letVar = 5;
// this variable declared with let is scoped to the function block, function scoped
var varVar = 10;
}
console.log(letVar);
console.log(varVar);
}
foo();
Dalam contoh di atas letVar mencatat nilai global karena variabel yang dideklarasikan dengan let
adalah blok scoped. Mereka tidak ada di luar blok masing-masing, sehingga variabel tidak dapat diakses di luar blok if.
Dalam EcmaScript5, terutama ada dua cakupan, cakupan lokal dan cakupan global, tetapi di EcmaScript6 kami memiliki tiga cakupan, cakupan lokal, cakupan global, dan cakupan baru yang disebut lingkup blok .
Contoh lingkup blok adalah: -
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
ECMAScript 6 memperkenalkan kata kunci let dan const. Kata kunci ini dapat digunakan sebagai pengganti kata kunci var. Bertentangan dengan kata kunci var, kata kunci let dan const mendukung deklarasi cakupan lokal di dalam pernyataan blokir.
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
Saya sangat suka jawaban yang diterima tetapi saya ingin menambahkan ini:
Lingkup mengumpulkan dan memelihara daftar pencarian dari semua pengidentifikasi yang dideklarasikan (variabel), dan menegakkan seperangkat aturan yang ketat tentang bagaimana ini dapat diakses oleh kode yang sedang dieksekusi.
Lingkup adalah seperangkat aturan untuk mencari variabel dengan nama pengenal mereka.
Ada dua jenis cakupan dalam JavaScript.
Ruang lingkup global : variabel yang diumumkan dalam ruang lingkup global dapat digunakan di mana saja dalam program dengan sangat lancar. Sebagai contoh:
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
Cakupan fungsional atau Cakupan lokal : variabel yang dideklarasikan dalam lingkup ini hanya dapat digunakan dalam fungsinya sendiri. Sebagai contoh:
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}