Apa ruang lingkup variabel dalam JavaScript?

2013

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?

lYriCAsSH
sumber
4
Berikut ini adalah tautan lain yang bagus untuk mengingat masalah ini: " Menjelaskan cakupan dan penutupan JavaScript ".
Insinyur Perangkat Lunak Full-Stack
9
Berikut adalah artikel yang menjelaskannya dengan sangat baik. Semua yang perlu Anda ketahui tentang lingkup variabel Javascript
Saurab Parakh
2
The disebutkan sebelumnya e-book dari Kyle Simpson tersedia untuk dibaca di Github, dan memberitahu Anda semua yang perlu Anda ketahui tentang JavaScript Scopes & Penutup. Anda dapat menemukannya di sini: github.com/getify/You-Dont-Know-JS/blob/master/… Ini adalah bagian dari seri buku "Anda tidak tahu JS" , yang sangat bagus untuk semua orang yang ingin tahu lebih lanjut tentang JavaScript.
3rik82

Jawaban:

2536

TLDR

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:

  1. Global - terlihat oleh segalanya
  2. Fungsi - terlihat dalam suatu fungsi (dan subfungsi dan bloknya)
  3. Blok - terlihat dalam blok (dan sub-bloknya)
  4. Modul - terlihat dalam modul

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.

Gambaran

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:

  1. Bagaimana pengidentifikasi dinyatakan
  2. Di mana pengidentifikasi diumumkan
  3. Apakah Anda dalam mode ketat atau mode tidak ketat

Beberapa cara pengidentifikasi dapat dinyatakan:

  1. var, letdanconst
  2. Parameter fungsi
  3. Tangkap parameter blok
  4. Deklarasi fungsi
  5. Ekspresi fungsi yang dinamai
  6. Properti yang didefinisikan secara implisit pada objek global (mis. Hilang vardalam mode non-ketat)
  7. import pernyataan
  8. eval

Beberapa pengidentifikasi lokasi dapat dinyatakan:

  1. Konteks global
  2. Fungsi tubuh
  3. Blok biasa
  4. Bagian atas struktur kontrol (mis. Loop, if, while dll)
  5. Kontrol struktur tubuh
  6. Modul

Gaya Deklarasi

var

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 evalfungsi.

biarkan dan const

Pengidentifikasi dideklarasikan menggunakan letdan const memiliki cakupan blok , selain dari ketika mereka dinyatakan secara langsung dalam konteks global, dalam hal ini mereka memiliki lingkup global.

Catatan: let, constdan 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 letdan consttidak 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

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

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

Ekspresi fungsi yang dinamai dicakup untuk dirinya sendiri (mis. Untuk tujuan rekursi).

Properti yang didefinisikan secara implisit pada objek global

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.

eval

Dalam evalstring, variabel yang dideklarasikan menggunakan varakan ditempatkan dalam lingkup saat ini, atau, jika evaldigunakan secara tidak langsung, sebagai properti pada objek global.

Contohnya

Berikut ini akan melempar ReferenceError karena nama x, ydan ztidak 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 ydan z, tetapi tidak untuk x, karena visibilitas xtidak dibatasi oleh blok. Blok yang menentukan tubuh struktur kontrol seperti if, fordan 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, xterlihat di luar loop karena varmemiliki 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 vardalam 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 5untuk keenam kalinya di console.logluar 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 undefinedkarena xdiblok-blok. Callback dijalankan satu per satu secara tidak sinkron. Perilaku baru untuk letvariabel berarti bahwa setiap fungsi anonim ditutup melalui variabel yang berbeda bernama x(tidak seperti yang akan dilakukan dengan var), dan bilangan bulat 0melalui 4dicetak.

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 ReferenceErrorkarena visibilitas xtidak dibatasi oleh blok; Namun, itu akan mencetak undefinedkarena variabel belum diinisialisasi (karena ifpernyataan).

if(false) {
    var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised

Variabel yang dideklarasikan di bagian atas forloop menggunakan letscoped ke badan loop:

for(let x = 0; x < 10; ++x) {} 
console.log(typeof x) // undefined, because `x` is block-scoped

Berikut ini akan melempar ReferenceErrorkarena visibilitas xdibatasi oleh blok:

if(false) {
    let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped

Variabel yang dideklarasikan menggunakan var, letatau constsemuanya 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 vardalam konteks global, ditambahkan sebagai properti ke objek global:

var x = 1
console.log(window.hasOwnProperty('x')) // true

letdan constdalam 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

Cara kerjanya di bawah tenda

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 .

Triptych
sumber
280
Bahkan tidak terlalu komprehensif, tapi ini mungkin harus diketahui trik-trik lingkup Javascript yang diperlukan bahkan secara efektif BACA javascript modern.
Triptych
148
Jawaban yang berperingkat tinggi, tidak yakin mengapa. Itu hanya sekelompok contoh tanpa penjelasan yang tepat, maka tampaknya membingungkan prototipe warisan (yaitu resolusi properti) dengan rantai lingkup (yaitu resolusi variabel). Penjelasan komprehensif (dan akurat) tentang ruang lingkup dan resolusi properti ada di catatan FAQ comp.lang.javascript .
RobG
109
@RobG Ini sangat berperingkat karena berguna dan komprehensif untuk berbagai programer, meskipun katakres kecil. Tautan yang Anda poskan, meskipun bermanfaat bagi sebagian profesional, tidak dapat dipahami oleh kebanyakan orang yang menulis Javascript hari ini. Jangan ragu untuk memperbaiki masalah nomenklatur dengan mengedit jawabannya.
Triptych
7
@ triptych — Saya hanya mengedit jawaban untuk memperbaiki hal-hal kecil, bukan utama. Mengubah "ruang lingkup" menjadi "properti" akan memperbaiki kesalahan, tetapi tidak masalah pencampuran warisan dan ruang lingkup tanpa perbedaan yang sangat jelas.
RobG
24
Jika Anda mendefinisikan variabel di lingkup luar, dan kemudian memiliki pernyataan if mendefinisikan variabel di dalam fungsi dengan nama yang sama, bahkan jika itu jika cabang tidak tercapai itu didefinisikan ulang. Contoh - jsfiddle.net/3CxVm
Chris S
233

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.

krosenvold
sumber
1
Rantai lingkup adalah istilah lain untuk Penutup [memori] ... untuk mereka yang membaca di sini untuk mempelajari / masuk ke javascript.
New Alexandria
108

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 thisartinya setiap saat. Mudah-mudahan tautan yang lebih perkenalan ini cukup untuk membantu Anda memulai. .)

Jon Skeet
sumber
7
Saya bahkan takut untuk mulai menjawab pertanyaan ini. Sebagai Pemrogram Javascript Sungguhan, saya tahu seberapa cepat jawabannya bisa lepas kendali. Artikel bagus.
Triptych
10
@ Triptych: Saya tahu apa yang Anda maksud tentang hal-hal yang tidak terkendali, tapi tolong tambahkan jawaban. Saya mendapatkan di atas hanya dari melakukan beberapa pencarian ... jawaban yang ditulis oleh seseorang dengan pengalaman nyata pasti lebih baik. Harap perbaiki salah satu jawaban saya yang pastinya salah!
Jon Skeet
4
Entah bagaimana Jon Skeet bertanggung jawab atas jawaban paling populer MY di Stack Overflow.
Triptych
75

JavaScript sekolah tua

Secara tradisional, JavaScript benar-benar hanya memiliki dua jenis ruang lingkup:

  1. Lingkup Global : Variabel diketahui di seluruh aplikasi, dari awal aplikasi (*)
  2. Lingkup Fungsional : Variabel diketahui dalam fungsi tempat mereka dideklarasikan, dari awal fungsi (*)

Saya tidak akan menguraikan ini, karena sudah ada banyak jawaban lain yang menjelaskan perbedaannya.


JavaScript modern

The spesifikasi JavaScript terbaru kini juga memungkinkan lingkup ketiga:

  1. Blok Lingkup : Pengidentifikasi "diketahui" dari bagian atas lingkup yang dideklarasikan di dalamnya , tetapi mereka tidak dapat ditugaskan atau direferensikan (baca) sampai setelah baris deklarasi mereka. Periode sementara ini disebut "zona mati sementara."

Bagaimana cara membuat variabel lingkup blok?

Secara tradisional, Anda membuat variabel Anda seperti ini:

var myVariable = "Some text";

Variabel ruang lingkup blok dibuat seperti ini:

let myVariable = "Some text";

Jadi apa perbedaan antara ruang lingkup fungsional dan ruang lingkup blok?

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 jhanya dikenal di awal untuk loop, tetapi tidak sebelum dan sesudah. Namun, variabel kami idikenal 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 menggunakan variabel lingkup blok hari ini?

Apakah aman digunakan hari ini atau tidak, tergantung pada lingkungan Anda:

  • Jika Anda menulis kode JavaScript sisi-server ( Node.js ), Anda dapat menggunakan letpernyataan dengan aman .

  • Jika Anda menulis kode JavaScript sisi klien dan menggunakan transpiler berbasis browser (seperti Traceur atau babel-standalone ), Anda dapat menggunakan letpernyataan 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 letpernyataan 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 letsama sekali:

    • Internet explorer 10 ke bawah
    • Firefox 43 dan yang lebih baru
    • Safari 9 dan yang lebih baru
    • Browser Android 4 dan di bawah
    • Opera 27 ke bawah
    • Chome 40 ke bawah
    • Versi Opera Mini & Blackberry APAPUN

masukkan deskripsi gambar di sini


Bagaimana cara melacak dukungan browser

Untuk gambaran umum terkini tentang browser yang mendukung letpernyataan 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.

John Slegers
sumber
2
"TIDAK Diketahui" menyesatkan, karena variabel dideklarasikan di sana karena pengangkatan.
Oriol
Contoh di atas menyesatkan, variabel 'i' dan 'j' tidak dikenal di luar blok. Variabel 'Biarkan' hanya memiliki ruang lingkup di blok tertentu yang tidak di luar blok. Biarkan memiliki kelebihan lain juga, Anda tidak dapat mendeklarasikan ulang variabel lagi dan itu memegang ruang lingkup leksikal.
zakir
1
Ini sangat membantu, terima kasih! Saya pikir akan lebih membantu untuk lebih spesifik tentang apa yang Anda maksud dengan "JavaScript Modern" dan "JavaScript sekolah lama"; Saya pikir ini sesuai dengan ECMAScript 6 / ES6 / ECMAScript 2015, dan masing-masing versi sebelumnya?
Jon Schneider
1
@JonSchneider: Benar! Di mana saya mengatakan "JavaScript sekolah lama", saya sedang berbicara tentang ECMAScript 5 dan di mana saya mengacu pada "JavaScript modern", saya mengambil tentang ECMAScript 6 (alias ECMAScript 2015). Saya tidak berpikir itu benar-benar penting untuk masuk ke detail di sini, karena kebanyakan orang hanya ingin tahu (1) apa perbedaan antara ruang lingkup blok dan ruang lingkup fungsional, (2) browser apa yang mendukung ruang lingkup blok dan (3) apakah aman menggunakan lingkup blok hari ini untuk proyek apa pun yang mereka kerjakan. Jadi saya memfokuskan jawaban saya untuk mengatasi masalah-masalah itu.
John Slegers
1
@JonSchneider: (lanjutan) Namun, saya baru saja menambahkan tautan ke artikel Smashing Magazine di ES6 / ES2015 bagi mereka yang ingin mempelajari lebih lanjut tentang fitur yang telah ditambahkan ke JavaScript selama beberapa tahun terakhir ... dari siapa pun yang mungkin bertanya-tanya apa yang saya maksud dengan "JavaScript modern".
John Slegers
39

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 .

geowa4
sumber
26

Dalam "Javascript 1.7" (ekstensi Mozilla ke Javascript) kita juga dapat mendeklarasikan variabel blok-lingkup dengan letpernyataan :

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4
kennytm
sumber
2
Ya, tetapi apakah aman untuk digunakan? Maksud saya, apakah saya akan secara realistis memilih implementasi ini jika kode saya akan berjalan di WebKit?
IgorGanapolsky
10
@Python: Tidak, WebKit tidak mendukung let.
kennytm
Saya kira satu-satunya penggunaan yang valid untuk ini adalah jika Anda tahu semua klien akan menggunakan browser Mozilla seperti untuk sistem internal perusahaan.
GazB
Atau jika Anda pemrograman menggunakan kerangka kerja XUL, kerangka kerja antarmuka Mozilla tempat Anda membangun menggunakan css, xml, dan javascript.
Gerard ONeill
1
@ GazB bahkan itu adalah ide yang mengerikan! Jadi hari ini Anda tahu bahwa klien Anda menggunakan Mozilla kemudian keluar sebuah memo baru yang menyatakan bahwa sekarang mereka menggunakan sesuatu yang lain. IE alasan sistem pembayaran kami menyebalkan ... Anda harus menggunakan IE8 dan tidak pernah IE9 atau IE10 atau Firefox atau Chrome karena itu tidak berfungsi ...
buzzsawddog
25

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 windowatau 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

  • Lingkup secara teknis "Konteks Eksekusi"
  • Konteks membentuk tumpukan lingkungan tempat variabel disimpan
  • Bagian atas tumpukan diutamakan (bagian bawah adalah konteks global)
  • Setiap fungsi menciptakan konteks eksekusi (tetapi tidak selalu ini mengikat baru)

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.

masukkan deskripsi gambar di sini

Travis J
sumber
17

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.

Gerard ONeill
sumber
Anda memiliki beberapa kesalahan di sini, karena salah satu JavaScript memang memiliki bentuk pelingkupan blok.
Benjamin Gruenbaum
Telingaku (mata) terbuka, Benjamin - Pernyataan saya di atas adalah bagaimana saya telah memperlakukan pelingkupan Javascript, tetapi mereka tidak didasarkan pada membaca spek. Dan saya harap Anda tidak mengacu pada pernyataan with (yang merupakan bentuk pelingkupan objek), atau sintaks 'let' khusus Mozilla.
Gerard ONeill
Nah, withpernyataan ini merupakan bentuk blok scoping tetapi catchklausa adalah bentuk jauh lebih umum (Fun Bahkan, v8 alat catchdenganwith ) - 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.
Benjamin Gruenbaum
Benjamin - dari apa yang bisa saya lihat, baik dengan dan menangkap hanya memperkenalkan objek ke dalam lingkup saat ini (dan dengan demikian properti), tetapi kemudian setelah masing-masing blok berakhir, variabel-variabel diatur ulang. Tapi misalnya, variabel baru yang dimasukkan dalam tangkapan akan memiliki ruang lingkup fungsi / metode penutup.
Gerard ONeill
2
Yang persis seperti apa yang dimaksud dengan scoping :)
Benjamin Gruenbaum
9

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.

austincheney
sumber
1
Tidak berfungsi untuk saya dengan Firefox 26. Saya menempelkan kode atau memuat file, klik eksekusi dan tidak ada yang terjadi.
mplwork
Lingkup dan warisan adalah dua hal yang berbeda.
Ben Aston
9

JavaScript hanya memiliki dua jenis ruang lingkup:

  1. Lingkup Global : Global tidak lain adalah ruang lingkup tingkat jendela. Di sini, variabel hadir di seluruh aplikasi.
  2. Lingkup Fungsional : Variabel yang dideklarasikan dalam suatu fungsi dengan varkata 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 ->

  1. Tingkat jendela - adanouter fungsinya berada di level teratas dalam rantai lingkup.
  2. ketika fungsi luar disebut baru variable scope object(dan termasuk dalam rantai lingkup) ditambahkan dengan variabel bdi dalamnya.

Sekarang ketika sebuah variabel adiperlukan, 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.

Anshul
sumber
1
Tidak yakin mengapa ini bukan jawaban yang diterima. Sebenarnya hanya ada ruang lingkup fungsional (sebelum ECMA6 tidak ada "ruang lingkup lokal") dan binding global
texasbruce
9

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:

gambar

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

James Drinkard
sumber
8

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);
Yeasin Abedin Siam
sumber
8

Lingkup Global:

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
}

Lingkup Lokal:

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

Jhankar Mahbub
sumber
6

Hanya ada hampir dua jenis cakupan JavaScript:

  • ruang lingkup setiap deklarasi var dikaitkan dengan fungsi terlampir yang paling segera
  • jika tidak ada fungsi terlampir untuk deklarasi var, itu adalah lingkup global

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:

  • Deklarasi var diangkat ke atas lingkup. Ini berarti di mana pun deklarasi var terjadi, bagi kompiler itu seolah-olah var itu sendiri terjadi di atas
  • beberapa deklarasi var dalam cakupan yang sama digabungkan

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.

jackbean818
sumber
5

Js Modern, ES6 +, ' const' dan ' let'

Anda harus menggunakan scoping blok untuk setiap variabel yang Anda buat, seperti kebanyakan bahasa utama lainnya. varsudah usang . Ini membuat kode Anda lebih aman dan lebih dapat dikelola.

constharus digunakan untuk 95% kasus . Itu membuatnya sehingga referensi variabel tidak dapat berubah. Array, objek, dan properti DOM node dapat berubah dan seharusnya terjadi const.

letharus 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.

Gibolt
sumber
3

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());
Mig82
sumber
3

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);
koredalin
sumber
(lama sejak jawaban diposting) Lingkup blok; developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Bob
2

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

mrmaclean89
sumber
2

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 :

  • global (penangan inline yang bekerja hampir selalu merujuk variabel global)
  • properti dokumen (misalnya, querySelectorsebagai variabel mandiri akan mengarah ke document.querySelector; jarang)
  • properti dari elemen yang dilampirkan pawang (seperti di atas; 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 documentdan properti dari elemen handler dilampirkan juga dapat dirujuk sebagai variabel mandiri di dalam handler inline karena handler inline dipanggil dalam dua withblok , 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 exportdiedit, 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.

Performa Tertentu
sumber
1

Dalam JavaScript ada dua jenis ruang lingkup:

  • Ruang lingkup lokal
  • Ruang lingkup global

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 
    }
}
Abdur Rahman
sumber
1

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 varkata 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:

  1. Ketika suatu fungsi terlihat untuk menyelesaikan nilai variabel, pertama-tama terlihat pada lingkupnya sendiri. Ini adalah fungsi tubuh, yaitu segala sesuatu di antara kurung keriting {} (kecuali untuk variabel di dalam fungsi lain yang ada dalam lingkup ini).
  2. Jika tidak dapat menemukan variabel di dalam fungsi tubuh itu akan naik ke rantai dan melihat ruang lingkup variabel dalam fungsi di mana fungsi itu didefinisikan . Inilah yang dimaksud dengan lingkup leksikal, kita dapat melihat dalam kode di mana fungsi ini didefinisikan dan dengan demikian dapat menentukan rantai lingkup dengan hanya melihat kode.

Contoh:

// 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, bardan foobarke konsol adalah sebagai berikut:

  1. Kami mencoba masuk foo ke konsol, foo dapat ditemukan di dalam fungsi innerFuncitu sendiri. Oleh karena itu, nilai foo diselesaikan ke string innerFunc.
  2. Kami mencoba masuk ke bilah konsol, bilah tidak dapat ditemukan di dalam fungsi innerFuncitu sendiri. Karena itu, kita perlu mendaki rantai ruang lingkup . Pertama-tama kita melihat fungsi luar di mana fungsi innerFuncitu didefinisikan. Ini fungsinya outerFunc. Dalam lingkup outerFunckita dapat menemukan bar variabel, yang menampung string 'outerFunc'.
  3. foobar tidak dapat ditemukan di fungsi dalam. . Oleh karena itu, kita perlu menaiki rantai lingkup ke lingkup fungsi internal. Itu juga tidak dapat ditemukan di sini, kami naik ke tingkat lain ke lingkup global (yaitu lingkup terluar). Kami menemukan foobar variabel di sini yang memegang string 'global'. Jika tidak akan menemukan variabel setelah naik rantai lingkup mesin JS akan melempar ReferenceError .

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 cakupan
  • const: membuat variabel scoped blok yang harus diinisialisasi dan tidak dapat dipindahkan

Perbedaan terbesar antara vardan let/ constadalah bahwa varadalah fungsi scoped sedangkan let/ constadalah 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 letadalah blok scoped. Mereka tidak ada di luar blok masing-masing, sehingga variabel tidak dapat diakses di luar blok if.

Willem van der Veen
sumber
0

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.
}
Vivek Mehta
sumber
0

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
Davaakhuu Erdenekhuu
sumber
0

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.

  • Jika variabel tidak dapat ditemukan dalam lingkup langsung, Engine berkonsultasi dengan ruang lingkup yang mengandung berikutnya, terus sampai ditemukan atau sampai lingkup terluar (alias, global) telah tercapai.
  • Apakah seperangkat aturan yang menentukan di mana dan bagaimana suatu variabel (pengidentifikasi) dapat dicari. 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) .
  • Referensi LHS dihasilkan dari operasi penugasan. Penugasan terkait lingkup dapat terjadi baik dengan operator = atau dengan meneruskan argumen ke (menetapkan ke) parameter fungsi.
  • Mesin JavaScript pertama mengkompilasi kode sebelum dieksekusi, dan dengan demikian, itu membagi pernyataan seperti var a = 2; menjadi dua langkah terpisah: 1. Pertama, var menyatakannya dalam lingkup itu. Ini dilakukan di awal, sebelum eksekusi kode. Ke-2 Kemudian, a = 2 untuk mencari variabel (referensi LHS) dan menetapkannya jika ditemukan.
  • Baik pencarian referensi LHS dan RHS dimulai pada ruang lingkup yang saat ini sedang dijalankan, dan jika perlu (yaitu, mereka tidak menemukan apa yang mereka cari di sana), mereka bekerja sampai ruang lingkup bersarang, satu ruang lingkup (lantai ) pada suatu waktu, mencari pengenal, sampai mereka mencapai global (lantai atas) dan berhenti, dan entah menemukannya, atau tidak. Referensi RHS yang tidak terpenuhi menghasilkan ReferenceError yang dilemparkan. Referensi LHS yang tidak terpenuhi menghasilkan global secara otomatis, yang secara global menciptakan nama itu (jika tidak dalam Mode Ketat), atau ReferenceError (jika dalam Mode Ketat).
  • ruang lingkup terdiri dari serangkaian "gelembung" yang masing-masing bertindak sebagai wadah atau ember, di mana pengidentifikasi (variabel, fungsi) dinyatakan. Gelembung-gelembung ini bersarang dengan rapi di dalam satu sama lain, dan sarang ini ditentukan pada waktu penulis.
Ahmed KhaShaba
sumber
-3

Ada dua jenis cakupan dalam JavaScript.

  1. 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 
    }
  2. 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
    }
A. Randhawa
sumber