Pertanyaan Apa perbedaan antara menggunakan "biarkan" dan "var" untuk mendeklarasikan variabel dalam JavaScript?


ECMAScript 6 diperkenalkan itu let pernyataan. Saya pernah mendengarnya digambarkan sebagai variabel "lokal", tapi saya masih tidak yakin bagaimana ia berperilaku berbeda dari var kata kunci.

Apa perbedaannya? Kapan seharusnya let digunakan lebih var?


3238
2018-04-17 20:09


asal


Jawaban:


Perbedaannya adalah scoping. var dicakup ke blok fungsi terdekat dan let dirangkak ke yang terdekat melampirkan blok, yang bisa lebih kecil dari blok fungsi. Keduanya bersifat global jika di luar blok apa pun.

Juga, variabel dideklarasikan dengan let tidak dapat diakses sebelum mereka dinyatakan dalam blok melampirkan mereka. Seperti yang terlihat di demo, ini akan melemparkan pengecualian ReferenceError.

Demo: 

var html = '';

write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible

try {
  write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
  write('globalLet: exception');
}

write('\nset variables');

var globalVar = 'globalVar';
let globalLet = 'globalLet';

write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);

function functionScoped() {
  write('\n#### function ####');
  write('\nfunctionVar: ' + functionVar); //undefined, but visible

  try {
    write('functionLet: ' + functionLet); //undefined, *not* visible
  } catch (exception) {
    write('functionLet: exception');
  }

  write('\nset variables');

  var functionVar = 'functionVar';
  let functionLet = 'functionLet';

  write('\nfunctionVar: ' + functionVar);
  write('functionLet: ' + functionLet);
}

function blockScoped() {
  write('\n#### block ####');
  write('\nblockVar: ' + blockVar); //undefined, but visible

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }

  for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
    write('\nblockVar: ' + blockVar); // visible here and whole function
  };

  for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
    write('blockLet: ' + blockLet); // visible only here
  };

  write('\nblockVar: ' + blockVar);

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }
}

function write(line) {
  html += (line ? line : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

Global:

Mereka sangat mirip ketika digunakan seperti ini di luar blok fungsi.

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

Namun, variabel global didefinisikan dengan let tidak akan ditambahkan sebagai properti di global window objek seperti yang didefinisikan dengan var.

console.log(window.me); // undefined
console.log(window.i); // 'able'

Fungsi:

Mereka identik ketika digunakan seperti ini di blok fungsi.

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

Blok:

Inilah perbedaannya. let hanya terlihat di for() loop dan var terlihat oleh seluruh fungsi.

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

Redeclaration:

Dengan asumsi mode ketat, var akan membiarkan Anda mendeklarasikan ulang variabel yang sama dalam cakupan yang sama. Di samping itu, let tidak akan:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.

4549
2018-05-27 10:16



let juga dapat digunakan untuk menghindari masalah dengan penutupan. Ini mengikat nilai segar daripada menyimpan referensi lama seperti yang ditunjukkan pada contoh di bawah ini.

DEMO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

Kode di atas menunjukkan masalah penutupan JavaScript klasik. Referensi ke i variabel disimpan dalam penutupan handler klik, bukan nilai sebenarnya dari i.

Setiap penangan klik tunggal akan merujuk ke objek yang sama karena hanya ada satu objek penghitung yang menampung 6 sehingga Anda mendapatkan enam pada setiap klik.

Solusi umum adalah untuk membungkus ini dalam fungsi anonim dan lulus i sebagai argumen. Masalah-masalah seperti itu juga dapat dihindari sekarang dengan menggunakan let sebagai gantinya var seperti yang ditunjukkan pada kode di bawah ini.

DEMO (Diuji di Chrome dan Firefox 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

450
2018-04-17 20:11



Ini sebuah penjelasan tentang let kata kunci dengan beberapa contoh.

biarkan bekerja sangat mirip var. Perbedaan utama adalah bahwa ruang lingkup variabel var adalah seluruh fungsi melampirkan

Meja ini di Wikipedia menunjukkan browser mana yang mendukung Javascript 1.7.

Perhatikan bahwa hanya Mozilla dan browser Chrome yang mendukungnya. IE, Safari, dan potensi lainnya tidak.


129
2018-02-23 18:35



Apa perbedaannya let dan var?

  • Variabel yang didefinisikan menggunakan var Pernyataan ini dikenal di seluruh fungsi itu itu didefinisikan dalam, dari awal fungsi. (*)
  • Variabel yang didefinisikan menggunakan let Pernyataan hanya dikenal di blok itu itu didefinisikan dalam, dari saat itu didefinisikan seterusnya. (**)

Untuk memahami perbedaannya, perhatikan 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 ini aman untuk digunakan let hari ini?

Beberapa orang akan berpendapat bahwa di masa depan kita HANYA akan menggunakan pernyataan let dan pernyataan var akan menjadi usang. Guru JavaScript Kyle Simpson menulis artikel yang sangat rumit tentang mengapa itu tidak terjadi.

Hari ini, bagaimanapun, itu jelas tidak terjadi. Sebenarnya, kita perlu bertanya pada diri sendiri apakah aman untuk menggunakan let pernyataan. Jawaban atas pertanyaan itu 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, Jun 8 2018, masih ada beberapa browser yang tidak mendukung let!

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


115
2018-06-02 20:59



Jawaban yang diterima tidak ada artinya:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined

98
2018-04-17 21:38



Ada beberapa perbedaan halus - let scoping berperilaku lebih seperti pengelompokan variabel dalam bahasa-bahasa lain.

misalnya Ini mencakup ke blok terlampir, Mereka tidak ada sebelum mereka dinyatakan, dll.

Namun perlu diperhatikan let hanya bagian dari implementasi Javascript yang lebih baru dan memiliki berbagai tingkat dukungan browser.


40
2018-03-06 10:41



Berikut ini contoh perbedaan antara keduanya (dukungan baru saja dimulai untuk chrome): enter image description here

Seperti yang Anda lihat var j variabel masih memiliki nilai di luar untuk lingkup loop (Block Scope), tetapi let i variabel tidak terdefinisi di luar untuk lingkup loop.

"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
  console.log(j);
}

console.log(j);

console.log("let:");
for (let i = 0; i < 2; i++) {
  console.log(i);
}

console.log(i);


39
2017-11-23 22:52



let

Blok ruang lingkup

Variabel yang dideklarasikan menggunakan let kata kunci berskala blok, yang berarti bahwa mereka hanya tersedia di blok di mana mereka diumumkan.

Di tingkat atas (di luar fungsi)

Di tingkat atas, variabel dideklarasikan menggunakan let jangan membuat properti pada objek global.

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

Di dalam suatu fungsi

Di dalam funciton (tetapi di luar blok), let memiliki ruang lingkup yang sama var.

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Di dalam blok

Variabel yang dideklarasikan menggunakan let di dalam blok tidak dapat diakses di luar blok itu.

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Di dalam satu lingkaran

Variabel yang dideklarasikan dengan let dalam loop dapat direferensikan hanya di dalam lingkaran itu.

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

Loops dengan penutup

Jika Anda menggunakan let dari pada var dalam satu lingkaran, dengan setiap iterasi Anda mendapatkan variabel baru. Itu berarti Anda dapat dengan aman menggunakan penutupan di dalam satu lingkaran.

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

Zona mati temporal

Karena zona mati temporal, variabel yang dideklarasikan menggunakan let tidak dapat diakses sebelum mereka dinyatakan. Mencoba melakukan hal itu melempar kesalahan.

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

Tidak ada pernyataan ulang

Anda tidak dapat mendeklarasikan variabel yang sama beberapa kali menggunakan let. Anda juga tidak dapat mendeklarasikan variabel menggunakan let dengan identifier yang sama dengan variabel lain yang dideklarasikan menggunakan var.

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

const sangat mirip dengan let—itu terlindung blok dan memiliki TDZ. Namun ada dua hal yang berbeda.

Tidak ada penetapan ulang

Variabel dideklarasikan menggunakan const tidak dapat ditugaskan kembali.

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

Perhatikan bahwa itu tidak berarti bahwa nilainya tidak berubah. Sifatnya masih bisa diubah.

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

Jika Anda ingin memiliki objek yang tidak dapat diubah, Anda harus menggunakannya Object.freeze().

Initializer diperlukan

Anda selalu harus menentukan nilai saat mendeklarasikan variabel menggunakan const.

const a; // SyntaxError: Missing initializer in const declaration

37
2018-01-17 15:11



  • Variabel Tidak Mengangkat

    let akan tidak hoist ke seluruh ruang lingkup blok mereka muncul. Sebaliknya, var bisa mengerek seperti di bawah ini.

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }
    

    Sebenarnya, Per @Bergi, Kedua var dan let dikibarkan.

  • Koleksi Sampah

    Blok ruang lingkup let berguna terkait dengan penutupan dan pengumpulan sampah untuk merebut kembali memori. Mempertimbangkan,

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    

    Itu click panggilan handler tidak membutuhkan hugeData variabel sama sekali. Secara teoritis, setelah process(..) berjalan, struktur data yang sangat besar hugeData bisa menjadi sampah yang dikumpulkan. Namun, ada kemungkinan bahwa beberapa mesin JS masih harus menjaga struktur besar ini, karena click fungsi memiliki penutupan atas seluruh ruang lingkup.

    Namun, ruang lingkup blok dapat membuat struktur data yang sangat besar ini menjadi sampah yang dikumpulkan.

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    
  • let loop

    let dalam lingkaran bisa mengikat kembali untuk setiap iterasi loop, pastikan untuk menetapkan kembali nilai dari akhir iterasi loop sebelumnya. Mempertimbangkan,

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    Namun, ganti var dengan let

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    Karena let membuat lingkungan leksikal baru dengan nama-nama tersebut untuk a) ekspresi initialiserer b) setiap iterasi (sebelumnya untuk mengevaluasi ekspresi kenaikan), lebih rinci adalah sini.


20
2018-03-22 14:39