Mengapa beberapa variabel yang dideklarasikan menggunakan membiarkan di dalam suatu fungsi menjadi tersedia di fungsi lain, sementara yang lain menghasilkan kesalahan referensi?

158

Saya tidak mengerti mengapa variabel bertingkah aneh ketika dideklarasikan di dalam suatu fungsi.

  1. Dalam firstfungsi saya mendeklarasikan dengan letvariabel bdan cdengan nilai 10 :

    b = c = 10;

    Dalam secondfungsi saya menunjukkan:

    b + ", " + c

    Dan ini menunjukkan:

    10, 10
  2. Juga dalam firstfungsi saya menyatakan adengan nilai 10 :

    let a = b = c = 10;

    Tetapi dalam secondfungsi itu menunjukkan kesalahan:

    Tidak dapat menemukan variabel: a

  3. Sekarang dalam firstfungsi saya menyatakan ddengan nilai 20 :

    var d = 20;

    Tetapi dalam secondfungsi itu menunjukkan kesalahan yang sama seperti sebelumnya, tetapi dengan variabel d:

    Tidak dapat menemukan variabel: d

Contoh:

function first() {
  let a = b = c = 10;
  var d = 20;
  second();
}

function second() {
  console.log(b + ", " + c); //shows "10, 10"

  try{ console.log(a); }  // Rreference error
  catch(e){ console.error(e.message) }

  try{ console.log(d); } // Reference error
  catch(e){ console.error(e.message) }
}
first()

interteiment yang buruk
sumber
31
Anda mendeklarasikan global, karena bdan ctidak diawali dengan varkata kunci. adan dbersifat lokal untuk first.
VLAZ
1
Komentar bukan untuk diskusi panjang; percakapan tangensial tentang apakah ini akan menjadi pertanyaan wawancara yang baik telah diarsipkan dalam obrolan .
Cody Gray
1
Ini mengingatkan saya pada situasi serupa di Visual Basic; Dim Apple, Banana, Pear As Fruitberarti Dim Apple / Dim Banana / Dim Pear As Fruit, dan tidak Dim Apple As Fruit / ....
Eric Lippert

Jawaban:

179

Itu karena Anda sebenarnya mengatakan:

c = 10;
b = c;
let a = b;

Dan bukan apa yang Anda pikir Anda katakan, yaitu:

let a = 10;
let b = 10;
let c = 10;

Anda akan melihat bahwa tidak peduli berapa banyak variabel yang Anda tambahkan ke rantai Anda, itu hanya akan menjadi yang pertama (a) yang menyebabkan kesalahan.

Ini karena "biarkan" lingkup variabel Anda ke blok (atau, "secara lokal", lebih atau kurang berarti "dalam tanda kurung") di mana Anda mendeklarasikannya.

Jika Anda mendeklarasikan variabel tanpa "biarkan", itu akan cakupan variabel secara global.

Jadi, dalam fungsi di mana Anda mengatur variabel Anda, semuanya mendapat nilai 10 (Anda bisa melihat ini di debugger jika Anda meletakkan breakpoint). Jika Anda meletakkan log konsol untuk a, b, c di fungsi pertama itu, semuanya baik-baik saja.

Tapi begitu Anda meninggalkan fungsi itu, yang pertama (a) - dan sekali lagi, ingatlah, secara teknis dalam urutan penugasan, itu adalah yang terakhir - "menghilang" (sekali lagi, Anda dapat melihat ini di debugger jika Anda menetapkan breakpoint pada fungsi kedua), tetapi dua lainnya (atau seberapa banyak yang Anda tambahkan) masih tersedia.

Ini karena, "biarkan" HANYA BERLAKU UNTUK (jadi hanya lingkup lokal) VARIABEL PERTAMA - sekali lagi, yang secara teknis merupakan yang terakhir dideklarasikan dan diberi nilai - dalam rantai. Sisanya secara teknis tidak memiliki "biarkan" di depan mereka. Jadi itu dinyatakan secara teknis secara global (yaitu, pada objek global), itulah sebabnya mereka muncul di fungsi kedua Anda.

Cobalah: hapus kata kunci "biarkan". Semua vars Anda sekarang akan tersedia.

"var" memiliki efek lingkup lokal yang serupa, tetapi berbeda dalam bagaimana variabel "diangkat", yang merupakan sesuatu yang harus Anda pahami, tetapi yang tidak terlibat langsung dengan pertanyaan Anda.

(BTW, pertanyaan ini akan membuat cukup banyak pro JS devs untuk menjadikannya bagus).

Sangat menyarankan Anda menghabiskan waktu dengan perbedaan dalam bagaimana variabel dapat dideklarasikan di JS: tanpa kata kunci, dengan "let", dan dengan "var".

Tim Consolazio
sumber
4
Secara bersamaan, ini adalah hal terbaik dan terburuk tentang pemrograman: komputer akan melakukan persis apa yang Anda perintahkan . Belum tentu apa yang Anda maksudkan untuk dilakukan. Programnya sempurna. Kami menciptakan masalah.
Niet the Dark Absol
8
@Thevs Mengapa Anda merekomendasikan varlebih letdalam konteks jawaban ini? Saya tidak mengerti.
Klaycon
4
@Thevs Saya sangat tidak setuju dengan Anda. vardapat rentan terhadap bug jika digunakan dengan sembarangan. Periksa biola
Cid
2
@Thevs dalam apa hal yang varharus setiap keuntungan lebih let? Izinkan saya mengklarifikasi: konteks modern ketika keduanya opsi dan saya meminta kode yang harus ditulis. Ketika saya menanyakan hal ini sebelumnya, saya telah menerima jawaban tentang "Anda dapat mendeklarasikan ulang variabel dengan var" dalam hal ini saya harus mengingatkan orang bahwa Anda tidak boleh mendeklarasikan ulang variabel . Entah itu bug atau kesalahan dalam logika kode - jadi manfaat dari deklarasi ulang adalah ... bahwa itu memungkinkan Anda untuk menulis kode yang salah. Saya belum melihat alasan masuk akal yang mendukung varketika letjuga merupakan pilihan.
VLAZ
2
Menorehkan tanda lain terhadap javascript. Semua variabel bersifat global kecuali dinyatakan lokal. :(
JRE
68

Dalam fungsi first(), variabel bdan cdibuat dengan cepat, tanpa menggunakan varatau let.

let a = b = c = 10; // b and c are created on the fly

Berbeda dari

let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)

Mereka menjadi tersirat global. Itu sebabnya mereka tersedia disecond()

Dari dokumentasi

Menetapkan nilai ke variabel yang tidak dideklarasikan secara implisit menciptakannya sebagai variabel global (itu menjadi properti dari objek global) ketika tugas dijalankan.

Untuk menghindari ini, Anda bisa menggunakan "use strict"yang akan memberikan kesalahan ketika seseorang menggunakan variabel yang tidak dideklarasikan

"use strict"; // <-------------- check this

function first() {
   /*
    * With "use strict" c is not defined.
    * (Neither is b, but since the line will be executed from right to left,
    * the variable c will cause the error and the script will stop)
    * Without, b and c become globals, and then are accessible in other functions
    */
   let a = b = c = 10;
   var d = 20;
   second();
}

function second() {
   console.log(b + ", " + c); //reference error
   console.log(a); //reference error
   console.log(d); //reference error
}

first();

Cid
sumber
15
Selain itu: let a = 10, b = 10, c = 10;atau let a, b, c; a = b = c = 10;cara yang benar untuk mendeklarasikan variabel.
Rickard Elimää
Jadi dengan mode ketat, bagaimana dengan variabel b?
Centang 20
2
@ Tick20 variabel btidak akan dievaluasi / tercapai, kesalahan akan terjadi pada baris let a = b = c = 10;, baca dari kanan ke kiri . cmenjadi variabel pertama yang menyebabkan ReferenceError, sisa baris tidak akan dieksekusi (skrip telah berhenti)
Cid
2
sesuatu seperti let a = 10, b = a, c = b;itu juga berlaku
Kaddath
8
terutama untuk "gunakan ketat". Dalam konteks pertanyaan wawancara, itu juga akan menjadi awal dari komentar saya pada kode ini.
Pac0
23

Sebelum memanggil hal-hal aneh, mari kita ketahui beberapa dasar-dasarnya terlebih dahulu:

var dan let keduanya digunakan untuk deklarasi variabel dalam JavaScript. Sebagai contoh,

var one = 1;
let two = 2;

Variabel juga dapat dideklarasikan tanpa menggunakan varatau let. Sebagai contoh,

three = 3;

Sekarang perbedaan antara pendekatan di atas adalah:

var adalah fungsi tercakup

dan

let adalah scoped blok.

sedangkan ruang lingkup variabel yang dideklarasikan tanpa var/ letkata kunci menjadi global terlepas dari di mana ia dinyatakan.

Variabel global dapat diakses dari mana saja di halaman web (tidak disarankan karena global dapat dimodifikasi secara tidak sengaja).

Sekarang menurut konsep-konsep ini mari kita lihat kode yang dimaksud:

 function first() {
   let a = b = c = 10;
   /* The above line means:
    let a=10; // Block scope
    b=10; // Global scope
    c=10; // Global scope
    */

   var d = 20; // Function scope
   second();
}

function second() {
   alert(b + ", " + c); // Shows "10, 10" //accessible because of global scope
   alert(a); // Error not accessible because block scope has ended
   alert(d); // Error not accessible because function scope has ended
}
fatimasajjad
sumber
1
Anda menjiplak bagian dari jawaban JonoJames . Mengapa?
Peter Mortensen
2
Maaf, tetapi saya tidak punya niat seperti itu, sesuatu yang serupa mungkin ada di sana karena kami mungkin telah mengumpulkan informasi dari sumber yang sama.
fatimasajjad
2
Bisa jadi kedua jawaban berisi konten yang disalin dari sumber asli yang sama tanpa kutipan yang jelas - mungkin tutorialsteacher.com/javascript/javascript-variable . Kehadiran plagiarisme jelas, karena kesalahan gramatikal direproduksi dari yang asli - "ruang lingkup variabel yang dideklarasikan tanpa varkata kunci menjadi global terlepas dari di mana ia dinyatakan" harus berupa "ruang lingkup ... menjadi" atau " cakupan ... menjadi " . Menggunakan kata-kata persis orang lain membutuhkan kutipan, baik dari sini atau di tempat lain. meta.stackexchange.com/q/160071/211183
Michael - sqlbot
Terima kasih teman-teman, saya telah menambahkan tautan referensi untuk sumbernya.
fatimasajjad
6

Variabel yang menggunakan letkata kunci seharusnya hanya tersedia dalam lingkup blok dan tidak tersedia dalam fungsi luar ...

Setiap variabel yang Anda nyatakan dengan cara itu tidak menggunakan letatau var. Anda kehilangan koma di deklarasi variabel.

Tidak disarankan untuk mendeklarasikan variabel tanpa varkata kunci. Secara tidak sengaja dapat menimpa variabel global yang ada. Cakupan variabel yang dideklarasikan tanpa varkata kunci menjadi global terlepas dari di mana ia dinyatakan. Variabel global dapat diakses dari mana saja di halaman web.

function first() {
   let a = 10;
   let b = 10;
   let c = 10;
   var d = 20;
   second();
}

function second() {
   console.log(b + ", " + c); //shows "10, 10"
   console.log(a); //reference error
   console.log(d); //reference error
}

first();

JonoJames
sumber
3

Itu karena ketika Anda tidak menggunakan letatau varkemudian variabel dinyatakan dengan cepat, lebih baik Anda menyatakan seperti berikut.

let a = 10;
let b = 10;
let c = 10;
Mac Rathod
sumber
2

Masalah aneh ini disebabkan oleh aturan pelingkupan dalam JavaScript

function first() {
   let a = b = c = 10; // a is in local scope, b and c are in global scope
   var d = 20; // d is in local scope
   second(); // will have access to b and c from the global scope
}

Dengan asumsi bahwa Anda ingin mendeklarasikan 3 variabel lokal yang diinisialisasi dengan nilai yang sama (100). Pertama Anda () akan terlihat seperti di bawah ini. Dalam hal ini, second () tidak akan memiliki akses ke salah satu variabel karena mereka lokal ke yang pertama ()

function first() {
   let a = 100; // a is in local scope init to 100
   let b = a; // b is in local scope init to a
   let c = b // c is in local scope init to b

   var d = 20; // d is in local scope
   second(); // will not have access a, b, c, or d
}

Namun, jika Anda ingin variabel global maka yang pertama () Anda akan terlihat seperti di bawah ini. Dalam hal ini, yang kedua akan memiliki akses ke semua variabel karena mereka berada dalam lingkup global

function first() {
   a = 100; // a is in global scope
   b = a; // b is in global scope
   c = b // c is in global scope

   d = 20; // d is in global scope
   second(); // will have access to a, b, c, and d from the global scope
}

Variabel lokal (alias. Dapat diakses di blok kode tempat mereka dideklarasikan).
Blok Kode adalah setiap {} dengan baris kode di antaranya.

  • function () {var, let, const di sini dapat diakses oleh seluruh fungsi},
  • for () {var di sini dapat diakses oleh lingkup luar, biarkan, const hanya dapat diakses di sini},
  • dll.

Variabel global (alias dapat diakses di lingkup global).
Variabel-variabel ini melekat pada objek global. Objek global bergantung pada lingkungan. Ini adalah objek jendela di browser.

Catatan khusus: Anda dapat mendeklarasikan variabel dalam JavaScript tanpa menggunakan kata kunci var, let, const. Variabel yang dideklarasikan dengan cara ini dilampirkan ke objek global, oleh karena itu dapat diakses dalam lingkup global.
a = 100 // is valid and is in global scope

Beberapa artikel untuk dibaca lebih lanjut: https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/ https://scotch.io/tutorials/understanding-scope-in-javascript https: //www.digitalocean .com / komunitas / tutorial / pemahaman-variabel-lingkup-mengangkat-di-javascript

Funwie
sumber
0

Perbedaan utama adalah aturan pelingkupan. Variabel yang dideklarasikan dengan kata kunci var dicakupkan ke badan fungsi langsung (maka lingkup fungsi) sementara variabel biarkan dilingkupi ke blok penutup langsung yang dilambangkan dengan {} (karenanya ruang lingkup blok). Dan ketika Anda mengatakannya

c = 10;
b = c;
let a = b;

c dan b memiliki rentang hidup sama seperti bersenang-senang tetapi hanya memiliki rentang blok dan jika Anda mencoba mengakses dengan merujuknya selalu menunjukkan kesalahan tetapi c dan b adalah global sehingga mereka tidak. Anda akan melihat bahwa tidak peduli berapa banyak variabel yang Anda tambahkan ke rantai Anda, itu hanya akan menjadi yang pertama (a) yang menyebabkan kesalahan. Ini karena "biarkan" lingkup variabel Anda ke blok (atau, "secara lokal", kurang lebih berarti "di dalam tanda kurung") di mana Anda mendeklarasikannya. Jika Anda mendeklarasikan variabel tanpa "biarkan", itu akan cakupan variabel secara global. Jadi, dalam fungsi di mana Anda mengatur variabel Anda, semuanya mendapatkan nilai 10 (Anda dapat melihat ini di debugger jika Anda meletakkan break-point). Jika Anda meletakkan log konsol untuk a, b, c di fungsi pertama itu, semuanya baik-baik saja. Tapi begitu Anda meninggalkan fungsi itu, yang pertama (a) - dan sekali lagi, perlu diingat,

Muhammad Fahad
sumber
0

Berikut adalah 3 aspek menarik dari deklarasi variabel dalam JavaScript:

  1. var membatasi ruang lingkup variabel ke blok di mana ia didefinisikan. ( 'var' untuk lingkup lokal .)

  2. biarkan memungkinkan penimpaan sementara nilai variabel eksternal di dalam blok.

  3. Cukup mendeklarasikan variabel tanpa var atau biarkan akan membuat variabel global, terlepas dari mana itu dinyatakan.

Berikut ini adalah demo dari let , yang merupakan tambahan terbaru untuk bahasa ini:

// File name:  let_demo.js

function first() {
   a = b = 10
   console.log("First function:    a = " + a)
   console.log("First function:    a + b = " + (a + b))
}

function second() {
    let a = 5
    console.log("Second function:    a = " + a)
    console.log("Second function:    a + b = " + (a + b))
}

first()   

second()

console.log("Global:    a = " + a)
console.log("Global:    a + b = " + (a + b))

Keluaran:

$ node let_demo.js 

First function:    a = 10
First function:    a + b = 20

Second function:    a = 5
Second function:    a + b = 15

Global:    a = 10
Global:    a + b = 20

Penjelasan:

Variabel a dan b dijelaskan di dalam ' first () ', tanpa kata kunci var atau let.

Karena itu, a dan b bersifat global, dan karenanya, dapat diakses di seluruh program.

Dalam fungsi bernama 'kedua' , pernyataan 'let a = 5' untuk sementara menetapkan nilai ' a ' hingga ' 5 ', dalam lingkup fungsi saja.

Di luar lingkup ' second () ', IE, dalam lingkup global, nilai ' a ' akan seperti yang didefinisikan sebelumnya.

Gopinath
sumber