Pertanyaan Apa ruang lingkup variabel dalam JavaScript?


Apa ruang lingkup variabel dalam javascript? Apakah mereka memiliki ruang lingkup yang sama di dalam bukannya di luar fungsi? Atau apakah itu penting? Juga, di mana variabel disimpan jika mereka didefinisikan secara global?


1711
2018-02-01 08:27


asal


Jawaban:


Saya pikir yang terbaik yang bisa saya lakukan adalah memberi Anda banyak contoh untuk dipelajari. Programmer Javascript praktis diberi peringkat oleh seberapa baik mereka memahami ruang lingkup. Kadang-kadang bisa sangat kontra-intuitif.

  1. Variabel yang mencakup global

    // global scope
    var a = 1;
    
    function one() {
      alert(a); // alerts '1'
    }
    
  2. Lingkup lokal

    // global scope
    var a = 1;
    
    function two(a) {
      // local scope
      alert(a); // alerts the given argument, not the global value of '1'
    }
    
    // local scope again
    function three() {
      var a = 3;
      alert(a); // alerts '3'
    }
    
  3. Menengah: Tidak ada yang namanya lingkup blok di JavaScript (ES5; ES6 memperkenalkan let)

    Sebuah.

    var a = 1;
    
    function four() {
      if (true) {
        var a = 4;
      }
    
      alert(a); // alerts '4', not the global value of '1'
    }
    

    b.

    var a = 1;
    
    function one() {
      if (true) {
        let a = 4;
      }
    
      alert(a); // alerts '1' because the 'let' keyword uses block scoping
    }
    
  4. Menengah: Properti objek

    var a = 1;
    
    function Five() {
      this.a = 5;
    }
    
    alert(new Five().a); // alerts '5'
    
  5. Maju: Penutupan

    var a = 1;
    
    var six = (function() {
      var a = 6;
    
      return function() {
        // JavaScript "closure" means I have access to 'a' in here,
        // because it is defined in the function in which I was defined.
        alert(a); // alerts '6'
      };
    })();
    
  6. Maju: Resolusi ruang lingkup prototipe

    var a = 1;
    
    function seven() {
      this.a = 7;
    }
    
    // [object].prototype.property loses to
    // [object].property in the lookup chain. For example...
    
    // Won't get reached, because 'a' is set in the constructor above.
    seven.prototype.a = -1;
    
    // Will get reached, even though 'b' is NOT set in the constructor.
    seven.prototype.b = 8;
    
    alert(new seven().a); // alerts '7'
    alert(new seven().b); // alerts '8'
    

  7. Global + Lokal: Kasus ekstra rumit

    var x = 5;
    
    (function () {
        console.log(x);
        var x = 10;
        console.log(x); 
    })();
    

    Ini akan dicetak undefined dan 10 daripada 5 dan 10 karena JavaScript selalu memindahkan deklarasi variabel (bukan inisialisasi) ke bagian atas ruang lingkup, membuat kode setara dengan:

    var x = 5;
    
    (function () {
        var x;
        console.log(x);
        x = 10;
        console.log(x); 
    })();
    
  8. Tangkap variabel klausa-cakupan

    var e = 5;
    console.log(e);
    try {
        throw 6;
    } catch (e) {
        console.log(e);
    }
    console.log(e);
    

    Ini akan dicetak 5, 6, 5. Di dalam klausa tangkapan e bayangan variabel global dan lokal. Tetapi ruang lingkup khusus ini hanya untuk variabel yang tertangkap. Jika Anda menulis var f; di dalam klausa tangkapan, maka itu persis sama seperti jika Anda telah mendefinisikannya sebelum atau sesudah blok try-catch.


2262
2018-02-01 08:58



Javascript menggunakan rantai lingkup untuk menetapkan ruang lingkup untuk fungsi yang diberikan. Biasanya ada satu lingkup global, dan setiap fungsi yang didefinisikan memiliki ruang bersarang sendiri. Setiap fungsi yang didefinisikan dalam fungsi lain memiliki lingkup lokal yang terhubung ke fungsi luar. Selalu posisi di sumber yang menentukan ruang lingkup.

Unsur dalam rantai lingkup pada dasarnya adalah sebuah Peta dengan pointer ke ruang lingkup induknya.

Ketika menyelesaikan suatu variabel, javascript dimulai pada ruang lingkup paling dalam dan mencari keluar.


219
2018-02-01 08:35



Variabel yang dideklarasikan secara global memiliki cakupan global. Variabel yang dideklarasikan dalam fungsi dicakup ke fungsi itu, dan bayangan variabel global dengan nama yang sama.

(Saya yakin ada banyak kehebohan yang dapat dijumpai oleh pemrogram JavaScript nyata dalam jawaban lainnya. Khususnya saya temui halaman ini tentang apa sebenarnya this berarti kapan saja. Semoga tautan pengantar ini cukup untuk membantu Anda memulai.)


93
2018-02-01 08:31



JavaScript sekolah lama

Secara tradisional, JavaScript benar-benar hanya memiliki dua jenis cakupan:

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

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


JavaScript Modern

Itu spesifikasi JavaScript terbaru sekarang juga memungkinkan lingkup ketiga:

  1. Block Scope : Variabel dikenal di dalam blok itumereka dideklarasikan, dari saat mereka dinyatakan seterusnya (**)

Bagaimana cara membuat variabel cakupan blok?

Secara tradisional, Anda membuat variabel Anda seperti ini:

var myVariable = "Some text";

Variabel cakupan blok dibuat seperti ini:

let myVariable = "Some text";

Jadi apa perbedaan antara lingkup fungsional dan cakupan blok?

Untuk memahami perbedaan antara cakupan fungsional dan cakupan 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 loop pertama, tetapi tidak sebelum dan sesudah. Namun, variabel kami i dikenal di seluruh fungsi.

Juga, pertimbangkan bahwa blok variabel scoped tidak diketahui sebelum mereka dinyatakan karena mereka tidak dikibarkan. Anda juga tidak diizinkan untuk mengulang variabel scoping blok yang sama dalam blok yang sama. Ini membuat blok variabel scoped kurang rawan kesalahan daripada variabel scoped global atau fungsional, yang dikibarkan dan yang tidak menghasilkan kesalahan dalam kasus beberapa deklarasi.


Apakah aman untuk menggunakan variabel lingkup blok hari ini?

Apakah aman untuk digunakan hari ini, tergantung pada lingkungan Anda:

  • Jika Anda menulis kode JavaScript sisi server (Node.js), Anda dapat menggunakan aman let pernyataan.

  • Jika Anda menulis kode JavaScript sisi klien dan menggunakan transpiler (suka Traceur), Anda dapat menggunakan aman let pernyataan, namun kode Anda mungkin menjadi apa pun tetapi optimal sehubungan dengan kinerja.

  • Jika Anda menulis kode JavaScript sisi klien dan tidak menggunakan transpiler, Anda perlu mempertimbangkan dukungan browser.

    Hari ini, 23 Februari 2016, ini adalah beberapa browser yang tidak mendukung let atau hanya memiliki dukungan sebagian:

    • Penjelajah Internet 10 dan di bawah (tidak ada dukungan)
    • Firefox 43 dan di bawah (tidak ada dukungan)
    • Safari 9 dan di bawah (tidak ada dukungan)
    • Opera Mini 8 dan di bawah (tidak ada dukungan)
    • Browser Android 4 dan di bawah (tidak ada dukungan)
    • Opera 36 dan di bawah (dukungan parsial)
    • Chome 51 dan di bawah (dukungan parsial)

enter image description here


Bagaimana cara melacak dukungan browser

Untuk ikhtisar terbaru tentang browser mana yang mendukung let pernyataan pada saat Anda membaca jawaban ini, lihat ini Can I Use halaman.


(*) Variabel global dan fungsional scoped dapat diinisialisasi dan digunakan sebelum mereka dinyatakan karena variabel JavaScript mengangkat. Ini berarti deklarasi selalu jauh ke atas ruang lingkup.

(**) Blok variabel scoped tidak dikibarkan


55
2018-02-23 18:51



Inilah contohnya:

<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 cara menggunakannya untuk membuatnya anggota pribadi.


35
2018-02-01 08:48



Kuncinya, seperti yang saya pahami, adalah bahwa Javascript memiliki level fungsi dibandingkan dengan pencakupan blok C yang lebih umum.

Berikut ini artikel bagus tentang hal ini.


28
2018-05-15 17:38



Dalam "Javascript 1.7" (ekstensi Mozilla ke Javascript) seseorang juga dapat mendeklarasikan variabel blok-ruang dengan let pernyataan:

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4

23
2018-04-06 11:19



Ide pelingkupan dalam JavaScript saat awalnya dirancang oleh Brendan Eich berasal dari HyperCard bahasa scripting 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 bagian bawah. Konten apa pun di kartu dasar ini dibagikan dengan kartu yang ditempatkan di atasnya. Setiap kartu yang ditempatkan di bagian atas memiliki konten sendiri yang lebih diutamakan daripada kartu sebelumnya, tetapi masih memiliki akses ke kartu sebelumnya jika diinginkan.

Inilah tepatnya bagaimana sistem scoping JavaScript dirancang. Itu hanya memiliki nama yang berbeda. Kartu-kartu dalam JavaScript dikenal sebagai Konteks EksekusiECMA. Masing-masing dari konteks ini mengandung tiga bagian utama. Lingkungan variabel, lingkungan leksikal, dan ini mengikat. Kembali ke referensi kartu, lingkungan leksikal berisi semua konten dari kartu sebelumnya yang lebih rendah dalam tumpukan. Konteks saat ini berada di bagian atas tumpukan dan konten apa pun yang dinyatakan akan disimpan dalam lingkungan variabel. Lingkungan variabel akan diutamakan dalam kasus penamaan tabrakan.

Pengikatan ini akan mengarah ke objek yang mengandung. Terkadang lingkup atau konteks eksekusi berubah tanpa perubahan objek yang mengandung, seperti dalam fungsi yang dinyatakan di mana objek yang mengandung mungkin window atau fungsi konstruktor.

Konteks eksekusi ini dibuat setiap kali kontrol ditransfer. Kontrol ditransfer ketika kode mulai dijalankan, dan ini terutama dilakukan dari eksekusi fungsi.

Jadi itu adalah penjelasan teknisnya. Dalam prakteknya, penting untuk diingat bahwa dalam JavaScript

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

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 disebut oleh var enam, dan konteks dalam fungsi kembali dalam var enam segera dipanggil fungsi.

saya) Konteks luar. Ini memiliki lingkungan variabel a = 1
ii) Konteks IIFE, ia memiliki lingkungan leksikal a = 1, tetapi lingkungan variabel a = 6 yang diutamakan dalam tumpukan
aku aku aku) Konteks fungsi yang dikembalikan, ia memiliki lingkungan leksikal a = 6 dan itu adalah nilai yang direferensikan dalam tanda ketika dipanggil.

enter image description here


18
2017-09-14 20:29



1) Ada lingkup global, ruang lingkup fungsi, dan dengan dan lingkup tangkapan. Tidak ada tingkat cakupan 'blok' secara umum untuk variabel - dengan dan pernyataan menangkap menambahkan nama ke blok mereka.

2) Lingkup bersarang dengan fungsi sampai ke lingkup global.

3) Properti diselesaikan dengan melalui rantai prototipe. Pernyataan dengan membawa nama properti objek ke dalam lingkup leksikal yang ditentukan oleh blok dengan.

EDIT: ECMAAScript 6 (Harmony) adalah spec'ed untuk mendukung biarkan, dan saya tahu krom memungkinkan bendera 'harmoni', jadi mungkin itu mendukungnya ..

Membiarkan akan menjadi dukungan untuk pelingkupan tingkat blok, tetapi Anda harus menggunakan kata kunci untuk mewujudkannya.

EDIT: Berdasarkan pada Benjamin yang menunjukkan pernyataan dengan dan menangkap di komentar, saya telah mengedit posting, dan menambahkan lebih banyak. Baik dengan dan pernyataan menangkap memperkenalkan variabel ke dalam blok masing-masing, dan itu aku s lingkup blok. Variabel-variabel ini dialiri ke properti dari objek yang dilewatkan ke mereka.

 //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 di-scoped ke dengan blok, tetapi di-alias ke a.test1. 'Var test1' menciptakan test1 variabel baru dalam konteks leksikal atas (fungsi, atau global), kecuali itu adalah milik dari - yang itu.

Astaga! Hati-hati menggunakan 'dengan' - sama seperti var adalah noop jika variabel sudah didefinisikan dalam fungsi, juga merupakan noop sehubungan dengan nama yang diimpor dari objek! Sedikit kepala pada nama yang sudah ditentukan akan membuat ini jauh lebih aman. Saya pribadi tidak akan pernah menggunakannya karena ini.


16
2017-10-25 00:41