Почему некоторые переменные, объявленные с использованием параметра let inside, становятся доступными в другой функции, в то время как другие приводят к ошибке ссылки? - PullRequest
158 голосов
/ 27 января 2020

Я не могу понять, почему переменные ведут себя так странно, когда объявляются внутри функции.

  1. В функции first я объявляю let переменные b и c со значением 10 :

    b = c = 10;
    

    В функции second я показываю:

    b + ", " + c
    

    И это показывает:

    10, 10
    
  2. Также в функции first я объявляю a со значением 10 :

    let a = b = c = 10;
    

    Но в функции second выдает ошибку :

    Не могу найти переменную: a

  3. Теперь в функции first я объявляю d со значением 20 :

    var d = 20;
    

    Но в функции second отображается та же ошибка, что и раньше, но с переменной d:

    Не могу найти переменную: d

Пример:

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()

Ответы [ 8 ]

179 голосов
/ 27 января 2020

Это потому, что вы на самом деле говорите:

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

А не то, что вы думаете, что говорите, а именно:

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

Вы заметите, что независимо от того, сколько переменные, которые вы добавляете в свою цепочку, это будет только первая (а), которая вызывает ошибку.

Это потому, что «let» определяет вашу переменную в блоке (или «локально», более или менее означая «в скобках»), в котором вы ее объявляете.

Если вы объявляете переменную без «let», она охватывает область глобально.

Итак, в функции, в которой вы устанавливаете переменные, все получает значение 10 (вы можете увидеть это в отладчике, если вы установите точку останова). Если вы поместите консольный журнал для a, b, c в этой первой функции, все будет хорошо.

Но как только вы покидаете эту функцию, первая (а) - и снова, имейте в виду, технически в порядке назначения, это последняя - «исчезает» (опять же, Вы можете увидеть это в отладчике, если вы установили точку останова во второй функции), но две другие (или сколько бы вы ни добавили) все еще доступны.

Это потому, что «let» ТОЛЬКО ПРИМЕНЯЕТСЯ ( так что только локально ограничивает) ПЕРВАЯ ПЕРЕМЕННАЯ - опять же, которая технически является последней, которая будет объявлена ​​и которой присвоено значение - в цепочке. У остальных технически нет «пускай» перед ними. Так что они технически объявлены глобально (то есть в глобальном объекте), поэтому они появляются в вашей второй функции.

Попробуйте: удалите ключевое слово let. Все ваши варианты теперь будут доступны.

«var» имеет аналогичный эффект локальной области видимости, но отличается тем, как переменная «поднимается», что вам определенно нужно понять, но которое напрямую не связано с вашим вопросом.

(Кстати, этот вопрос может поставить в тупик достаточно JS разработчиков, чтобы сделать его хорошим).

Настоятельно советуем вам потратить время на различия в том, как переменные могут быть объявлены в JS: без ключевого слова, с «let» и с «var».

68 голосов
/ 27 января 2020

В функции first() переменные b и c создаются на лету, без использования var или let.

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

Отличается от

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

Они становятся неявными глобальными. Вот почему они доступны в second()

Из документации

При назначении значения необъявленной переменной неявно создается ее как глобальная переменная (она становится свойство глобального объекта) при выполнении присваивания.

Чтобы избежать этого, вы можете использовать "use strict", что приведет к ошибкам при использовании необъявленной переменной

"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();
23 голосов
/ 27 января 2020

Прежде чем называть вещи странными, давайте сначала узнаем некоторые основы:

var и let оба используются для объявления переменных в JavaScript. Например,

var one = 1;
let two = 2;

Переменные также могут быть объявлены без использования var или let. Например,

three = 3;

Теперь разница между вышеупомянутыми подходами заключается в том, что:

var - это область действия функции

и

let ограничены областью действия блока.

, а область действия переменных, объявленных без ключевого слова var / let, становится global независимо от того, где оно объявлено.

Глобальные переменные доступны из любой точки веб-страницы (не рекомендуется, поскольку глобальные переменные могут быть случайно изменены).

Теперь в соответствии с этими понятиями, давайте посмотрим на код:

 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
}
6 голосов
/ 27 января 2020

Переменные, использующие ключевое слово let, должны быть доступны только в рамках блока и недоступны во внешней функции ...

Каждая переменная, которую вы объявляете таким образом, не использует let или var. В объявлении переменных отсутствует запятая.

*1009* не рекомендуется объявлять переменную без ключевого слова var. Он может случайно перезаписать существующую глобальную переменную. Область действия переменных, объявленных без ключевого слова var, становится глобальной независимо от того, где оно объявлено. Глобальные переменные доступны из любой точки веб-страницы.

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();
3 голосов
/ 29 января 2020

Это из-за того, что когда вы не используете let или var, тогда переменная становится объявленной на лету, лучше объявить, как показано ниже.

let a = 10;
let b = 10;
let c = 10;
2 голосов
/ 15 февраля 2020

Странная проблема вызвана правилами области действия в 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
}

При условии, что вы хотите объявить 3 локальные переменные , инициализированные одним и тем же значением (100). Ваша первая () будет выглядеть ниже. В этом случае second () не будет иметь доступа ни к одной из переменных, потому что они локальные to first ()

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
}

Однако, если вы хотите глобальные переменные тогда ваш first () будет выглядеть ниже. В этом случае секунда будет иметь доступ ко всем переменным, потому что они находятся в global scope

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
}

Локальные переменные (он же доступен в блоке кода, где они объявлены).
Блок кода - это любой {} со строкой кода между.

  • function () {var, let, const здесь доступна для всей функции},
  • for () {var in здесь доступна для внешней области видимости, let, const available только здесь},
  • et c.

Глобальные переменные (он же доступен в глобальной области видимости).
Эти переменные прикреплены к глобальному объекту. Глобальный объект зависит от окружающей среды. Это объект окна в браузерах.

Специальное примечание: Вы можете объявить переменные в JavaScript без использования ключевых слов var, let, const. Объявленная таким образом переменная присоединяется к глобальному объекту, поэтому доступна в глобальной области видимости.
a = 100 // is valid and is in global scope

Некоторые статьи для дальнейшего чтения: https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/ https://scotch.io/tutorials/understanding-scope-in-javascript https://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript

0 голосов
/ 02 февраля 2020

Вот три интересных аспекта объявления переменных в JavaScript:

  1. var ограничивает область видимости переменной для блока, в котором она определена. ( 'var' для локальный охват .)

  2. let позволяет временное переопределение значения внешней переменной внутри блока.

  3. Простое объявление переменной без var или let сделает переменную глобальной, независимо от того, где она объявлена.

Вот демонстрационная версия let , что является последним дополнением к языку:

// 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))

Вывод:

$ 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

Объяснение:

Переменные a и b были разделены внутри ' first () ', без var или let ключевые слова.

Следовательно, a и b являются глобальными и, следовательно, доступны во всей программе.

В функции с именем 'second' , оператор 'let a = 5' temporari ly устанавливает значение ' a ' на ' 5 ', только в рамках функции.

Вне области действия ' second () ', IE, в глобальной области видимости значение a будет таким, как определено ранее.

0 голосов
/ 30 января 2020

Основным отличием являются правила определения объема. Переменные, объявленные ключевым словом var, попадают в область непосредственного тела функции (отсюда область действия функции), а переменные let - в область непосредственного включения, обозначенную {} (отсюда область действия блока). И когда вы говорите, что

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

c и b имеют жизненный цикл как забавный, но имеют только блочный промежуток, и если вы пытаетесь получить доступ к a, ссылаясь на него, всегда показывает ошибку, но c и b глобально, поэтому они этого не делают. Вы заметите, что независимо от того, сколько переменных вы добавляете в свою цепочку, это будет только первый (а), который вызывает ошибку. Это потому, что «пусть» определяет вашу переменную в блоке (или, «локально», более или менее означающее «в скобках»), в котором вы объявляете это. Если вы объявляете переменную без «let», она определяет область глобально. Таким образом, в функции, где вы устанавливаете свои переменные, все получает значение 10 (вы можете увидеть это в отладчике, если поставить точку останова). Если вы поместите консольный журнал для a, b, c в этой первой функции, все будет хорошо. Но как только вы выйдете из этой функции, первая (a) - и снова, имейте в виду, технически в порядок назначения, он последний - «исчезает» (опять же, вы можете увидеть это в отладчике, если вы установите точку останова во второй функции), но другие два (или сколько вы добавляете) по-прежнему имеется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...