함수 내부에서 let을 사용하여 선언 된 일부 변수가 다른 함수에서 사용 가능한 반면 다른 변수가 참조 오류를 발생시키는 이유는 무엇입니까?


158

함수 내에서 선언 할 때 변수가 왜 그렇게 이상하게 작용하는지 이해할 수 없습니다.

  1. 에서 first함수는 I로 선언 let변수 bc값으로 10 :

    b = c = 10;

    에서 second기능을 내가 보여

    b + ", " + c

    그리고 이것은 보여줍니다 :

    10, 10
  2. 또한 first함수 에서 a10으로 선언 합니다 .

    let a = b = c = 10;

    그러나 second함수에서 오류가 표시됩니다.

    변수를 찾을 수 없습니다 : a

  3. 이제 first함수 에서 d20으로 선언 합니다 .

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


31
키워드를 접두사로 사용하지 않기 때문에 전역을 선언 b하고 c있습니다 var. ad로컬입니다 first.
VLAZ

1
의견은 긴 토론을위한 것이 아닙니다. 이것이 좋은 면접 질문이 될 것인지에 대한 탄젠트 대화가 대화에 보관되었습니다 .
코디 그레이

1
이것은 Visual Basic에서도 비슷한 상황을 상기시킵니다. Dim Apple, Banana, Pear As Fruit수단 Dim Apple / Dim Banana / Dim Pear As Fruit, 그리고 Dim Apple As Fruit / ....
Eric Lippert

답변:


179

실제로 말하고 있기 때문입니다.

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"은 로컬 범위 효과가 비슷하지만 변수가 "호이스트"되는 방식이 다릅니다. 이는 확실히 이해해야하지만 질문과 직접 ​​관련이 없습니다.

(BTW,이 질문은 프로 JS 개발자가 그것을 좋은 것으로 만들 정도로 충분할 것입니다).

키워드, "let"및 "var"을 사용하여 JS에서 변수를 선언하는 방법의 차이점에 대해 시간을 보내십시오.


4
그것은 프로그래밍에있어서 가장 좋고 최악의 일입니다 : 컴퓨터는 당신이시키는 대로 정확하게 행동 할 것입니다. 당신이 의도 한 것은 아닙니다. 프로그램은 완벽합니다. 우리는 문제를 만듭니다.
어두운 압솔 니엣

8
@Thevs 왜 추천 할 var이상 let이 답변의 맥락에서? 이해가 안 돼요
Klaycon

4
@Thevs 나는 당신에 강력히 동의하지 않습니다. var부주의하게 사용하면 버그가 발생하기 쉽습니다. 이 바이올린을
Cid

2
어떤 경우에 @Thevs var어떤 장점이 let있습니까? 두 가지 모두 옵션 일 때 작성 해야하는 코드를 요구하는 현대적인 맥락을 명확히하겠습니다 . 전에이 질문을 받았을 때 "변수를 다시 선언 할 수 있습니다"라는 대답을 받았습니다 var.이 경우 변수를 다시 선언해서는 안된다는 것을 사람들에게 상기시켜야 합니다 . 그것은 코드 논리의 버그 또는 오류입니다. 따라서 재 선언의 이점은 잘못된 코드를 작성할 수 있다는 것입니다. 나는 또한 옵션이 var언제 인지에 대한 합리적인 이유를 아직 보지 못했다 let.
VLAZ

2
자바 스크립트에 대한 또 다른 마크를 작성하십시오. 로컬로 선언하지 않는 한 모든 변수는 전역 변수입니다. :(
JRE

68

함수에서 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();


15
또한 : let a = 10, b = 10, c = 10;또는 let a, b, c; a = b = c = 10;다른 변수를 선언하는 올바른 방법 일 것이다.
Rickard Elimää

엄격 모드에서 변수 b는 어떻습니까?
Tick20

2
@ Tick20 변수 b가 평가 / 도달되지 않으며 let a = b = c = 10;, 오른쪽에서 왼쪽으로 읽는 줄에 오류가 발생합니다 . c을 일으키는 첫 번째 변수 ReferenceError이므로 나머지 행은 실행되지 않습니다 (스크립트가 중지됨)
Cid

2
같은 뭔가 let a = 10, b = a, c = b;너무 유효
Kaddath

8
주로 "엄격한 사용"을 위해 찬성했습니다. 인터뷰 질문의 맥락에서, 그것은 또한이 코드에 대한 나의 의견의 시작일 것입니다.
Pac0

23

이상하다고 부르기 전에 먼저 몇 가지 기본 사항을 알아 두십시오.

varlet 은 모두 JavaScript에서 변수 선언에 사용됩니다. 예를 들어

var one = 1;
let two = 2;

var또는 을 사용하지 않고 변수를 선언 할 수도 있습니다 let. 예를 들어

three = 3;

이제 위의 접근 방식의 차이가 있다는 것입니다 :

var 기능 범위입니다

let 블록 범위입니다.

var/ let키워드 없이 선언 된 변수의 범위 는 선언 된 위치에 관계없이 전역 이됩니다.

글로벌 변수 는 웹 페이지의 어느 곳에서나 액세스 할 수 있습니다 (글로벌은 실수로 수정 ​​될 수 있으므로 권장되지 않음).

이제 이러한 개념에 따라 문제의 코드를 살펴 보겠습니다.

 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
}

1
JonoJames의 답변 일부를 표절했습니다 . 왜?
Peter Mortensen

2
죄송하지만 같은 의도가 없었습니다. 같은 출처에서 정보를 수집했기 때문에 비슷한 것이있을 수 있습니다.
fatimasajjad

2
두 답변 모두 명백한 인용없이 동일한 원본 소스에서 복사 한 내용을 포함 할 수 있습니다 (가능한 경우 tutorialsteacher.com/javascript/javascript-variable) . - 표절의 존재는 문법 오류가 원본과 복제되기 때문에, 명백하다 "는없이 변수의 범위는 선언 var이 선언 된 곳의 세계에 상관없이이 될 키워드" 이어야한다 "... 범위가된다" 또는 은 " 범위 ...가됩니다 " . 다른 사람의 정확한 단어를 사용하려면 여기 또는 다른 곳에서 인용이 필요합니다. meta.stackexchange.com/q/160071/211183
마이클 - sqlbot

고마워, 소스에 대한 참조 링크를 추가했습니다.
fatimasajjad

6

를 사용하는 변수 let키워드를 는 블록 범위 내에서만 사용할 수 있어야하며 외부 함수에서는 사용할 수 없습니다 ...

그런 식으로 선언하는 각 변수는 사용하지 않습니다 letvar. 변수 선언에 쉼표가 없습니다.

되는 하지 않는 것이 좋습니다 를 빼고 변수를 선언하는 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

이 때문에 사용하지 않는 경우의이다 let또는 var다음 변수는 즉시 선언을 받고, 더 나은 당신은 다음과 같이 선언합니다.

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

2

이상한 문제는 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
}

동일한 값 (100)으로 초기화 된 3 개의 로컬 변수 를 선언한다고 가정합니다 . 첫 번째 ()는 다음과 같습니다. 이 경우 second ()는 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 ()는 다음과 같습니다. 이 경우 두 번째는 모든 변수가 전역 범위 에 있기 때문에 모든 변수에 액세스 할 수 있습니다.

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 () {여기에서 const는 전체 함수에 액세스 할 수 있습니다},
  • for () {여기의 var는 외부 범위에 액세스 할 수 있습니다.
  • 기타

전역 변수 (일명 전역 범위에서 액세스 가능).
이 변수는 전역 객체에 첨부됩니다. 전역 객체는 환경에 따라 다릅니다. 브라우저의 창 개체입니다.

특별 참고 사항 : var, let, const 키워드를 사용하지 않고 JavaScript로 변수를 선언 할 수 있습니다. 이 방법으로 선언 된 변수는 전역 개체에 연결되므로 전역 범위에서 액세스 할 수 있습니다.
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 / unknown-variables-scope-hoisting-in-javascript


0

주요 차이점은 범위 지정 규칙입니다. var 키워드로 선언 된 변수는 직접 함수 본문 (따라서 함수 범위)에 범위가 지정되는 반면, 변수는 {} (블록 범위)로 표시되는 즉시 둘러싸는 블록에 범위가 지정됩니다. 그리고 당신이 말할 때

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

c와 b의 수명은 재미 있지만 a는 블록 스팬 뿐이며 참조하여 a에 액세스하려고하면 항상 오류가 표시되지만 c와 b는 전역 적으로 표시되므로 그렇지 않습니다. 체인에 추가하는 변수는 오류를 일으키는 첫 번째 (a) 일뿐입니다. "let"은 변수를 블록의 범위 (또는 "로컬", "괄호 안에"는 다소 의미가 있기 때문입니다) 때문입니다. "let"없이 변수를 선언하면 전역으로 변수의 범위를 지정합니다. 따라서 변수를 설정하는 함수에서 모든 값은 10이됩니다 (디버거에서이 값을 중단 점). 첫 번째 기능에 a, b, c에 대한 콘솔 로그를 넣으면 모든 것이 잘됩니다. 그러나 해당 기능을 떠나 자마자 첫 번째 기능은 (a) 다시 한 번 명심하십시오.


0

JavaScript에서 변수 선언의 3 가지 흥미로운 측면은 다음과 같습니다.

  1. var 는 변수의 범위를 변수가 정의 된 블록으로 제한합니다. ( 'var' 로컬 범위 입니다.)

  2. 임시 재정의를 허용 하자블록 내에서 외부 변수의 값을 .

  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

설명:

변수 ab 는 ' first () var 또는 let 키워드없이 ' .

따라서 ab 는 전역 적이므로 프로그램 전체에서 액세스 할 수 있습니다.

'second' 라는 함수에서 'let a = 5' 일시적으로 ' a ' 값 을 ' 5 '에만 함수의 범위 내.

IE의 전역 범위에서 ' second () ' 범위를 벗어나면 ' a ' 값은 이전에 정의 된대로입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.