어휘 범위는 무엇입니까?


682

어휘 범위 지정에 대한 간략한 소개는 무엇입니까?


89
팟 캐스트 58에서 Joel은 다른 장소에서 답변을 받았더라도 SO가 답변을위한 장소가되기를 원하므로 이러한 질문을 권장합니다. 조금 더 예의 바르게 말할 수 있지만 이것은 유효한 질문입니다.
Ralph M. Rickenbach

5
@rahul 나는 그것이 오래된 질문이라는 것을 이해합니다. 그러나 2009 년에도 확실하게 요청자는이를 해결하기 위해 기본적인 노력기울일 것으로 예상 했습니다. 약자로는 표시되지 않습니다 어떤 전혀 노력을. 아마도 그것이 많은 사람들에 의해 하향 조정 된 이유일까요?
PP

13
이 질문을 쓸 때 영어를 유창하게 구사하지 않았을 수도 있습니다
Martin

27
문제는 정중합니다. 그는 단지 그가 원하는 것을 말합니다. 당신은 대답 할 수 있습니다. 여기에 과민성 politness가 필요하지 않습니다.
Markus Siebeneicher

25
SO에 대한 내용을 작성하기 때문에 이와 같은 질문은 훌륭하다고 생각합니다. 질문에 노력이 없는지 걱정하는 IMO ... 답변에는 훌륭한 내용이 포함되어 있으며이 게시판에서 중요한 사항입니다.
Jwan622

답변:


686

예를 통해 이해합니다. :)

먼저 C와 같은 구문으로 어휘 범위 ( 정적 범위 라고도 함 ) :

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

모든 내부 레벨은 외부 레벨에 액세스 할 수 있습니다.

C와 유사한 구문 으로 Lisp 의 첫 번째 구현에서 사용되는 동적 범위 라는 또 다른 방법이 있습니다 .

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

여기에 fun액세스하거나 할 수 x있는 dummy1하거나 dummy2, 또는 x호출하는 것이 어떤 함수 funx그 안에 선언은.

dummy1();

5를 인쇄합니다

dummy2();

10을 인쇄합니다.

첫 번째는 컴파일 타임에 추론 할 수 있기 때문에 정적이라고하고, 두 번째는 동적이며 함수의 체인 호출에 의존하기 때문에 동적이라고합니다.

나는 눈에 대한 정적 범위 지정이 더 쉽다는 것을 알았습니다. 대부분의 언어는 결국 이런 식으로 갔다. 심지어 Lisp도 마찬가지이다. 동적 범위 지정은 모든 변수의 참조를 호출 된 함수에 전달하는 것과 같습니다.

컴파일러가 함수의 외부 동적 범위를 추론 할 수없는 이유의 예로 마지막 예제를 고려하십시오. 다음과 같이 작성하면 :

if(/* some condition */)
    dummy1();
else
    dummy2();

호출 체인은 런타임 조건에 따라 다릅니다. 맞다면 콜 체인은 다음과 같습니다.

dummy1 --> fun()

조건이 거짓 인 경우 :

dummy2 --> fun()

fun두 경우 모두 외부 범위 는 발신자 및 발신자의 발신자 등입니다 .

C 언어는 중첩 함수 나 동적 범위 지정을 허용하지 않습니다.


19
또한 방금 찾은 매우 이해하기 쉬운 자습서를 지적하고 싶습니다. Arak의 예는 훌륭하지만 더 많은 예를 필요로하는 사람 (실제로 다른 언어와 비교할 때)에는 너무 짧을 수 있습니다. 구경하다. 키워드가 어휘 범위를 이해하게하므로 이것을 이해하는 것이 중요합니다 . howtonode.org/what-is-this
CppLearner

9
이것은 좋은 대답입니다. 그러나 질문에는 태그가 붙어 있습니다 JavaScript. 따라서 이것이 허용되는 답변으로 표시되어서는 안된다고 생각합니다. JS에서 구체적으로 어휘 범위가 다릅니다
Boyang

6
매우 좋은 답변입니다. 감사합니다. @Boyang 동의하지 않습니다. 나는 Lisp 코더가 아니지만 Lisp 예제는 JS에서 얻지 못하는 동적 범위 지정의 예이므로 도움이됩니다.
dudewad

4
처음에는 예제가 유효한 C 코드라고 생각하고 C에 동적 범위가 있는지 혼란 스럽습니다. 마지막으로 고지 사항이 코드 예제 이전으로 바뀔 수 있습니까?
Yangshun Tay

2
이것은 여전히 ​​유용한 답변이지만 @Boyang이 맞다고 생각합니다. 이 답변은 '레벨'을 의미하며, 이는 C가 가지고있는 블록 범위의 라인에 더 가깝습니다. 기본적으로 JavaScript에는 블록 레벨 범위가 없으므로 for루프 내부 가 일반적인 문제입니다. 자바 스크립트에 대한 어휘 범위 만 ES6 않는 기능 수준에 let또는 const사용됩니다.
icc97 April

275

가장 짧은 정의를 시도해 보겠습니다.

어휘 범위 지정 은 중첩 함수에서 변수 이름을 확인하는 방법을 정의합니다. 내부 함수에는 상위 함수가 반환 된 경우에도 상위 함수의 범위가 포함 됩니다.

그것이 전부입니다!


21
마지막 부분 : "부모 함수가 반환 된 경우에도"를 Closure라고합니다.
Juanma Menendez

1
단 한 문장으로 Lexical Scoping & Closure를 이해했습니다. 감사!!
던전

63
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

위의 코드는 "나는 단지 로컬입니다"를 반환합니다. "나는 글로벌입니다"를 반환하지 않습니다. func () 함수는 whatismyscope 함수의 범위에 속하는 원래 정의 된 위치를 계산하기 때문입니다.

그것이 호출되는 것이 무엇이든 (글로벌 범위 / 다른 함수 내에서도) 귀찮게하지 않을 것입니다. 그래서 내가 글로벌 인 글로벌 범위 값이 인쇄되지 않습니다.

이를 "어휘 범위 지정"이라고합니다. 여기서 JavaScript 정의 안내서에 따르면 " 함수를 정의 할 때 적용되었던 스코프 체인을 사용하여 함수가 실행됩니다 ".

어휘 범위는 매우 강력한 개념입니다.

도움이 되었기를 바랍니다..:)


3
함수 func () {return this.scope;}를 작성하면 하나 더 추가하고 싶습니다. "re am this"를 반환하고이 키워드를 사용하면 범위가 변경됩니다
Rajesh Kumar Bhawsar

41

어휘 (AKA 정적) 범위 지정은 텍스트 코드 모음 내 위치 만 기준으로 변수 범위를 결정하는 것을 말합니다. 변수는 항상 최상위 환경을 나타냅니다. 동적 범위관련하여 이해하는 것이 좋습니다 .


41

범위는 기능, 변수 등을 사용할 수있는 영역을 정의합니다. 예를 들어 변수의 가용성은 컨텍스트 내에서 정의됩니다. 함수, 파일 또는 객체가 정의되어 있다고합시다. 일반적으로 이러한 로컬 변수를 호출합니다.

어휘 부분은 소스 코드를 읽지 않고 범위를 파생시킬 수 있음을 의미합니다.

어휘 범위는 정적 범위라고도합니다.

동적 범위는 정의 후 어디서나 호출하거나 참조 할 수있는 전역 변수를 정의합니다. 대부분의 프로그램 언어의 전역 변수가 어휘 범위에 있더라도 전역 변수라고도합니다. 이는 변수가이 컨텍스트에서 사용 가능하다는 코드를 읽음으로써 파생 될 수 있음을 의미합니다. 아마도 instatiation 또는 정의를 찾기 위해 uses 또는 contains 절을 따라야 할 수도 있지만 코드 / 컴파일러는이 위치의 변수에 대해 알고 있습니다.

반면에 동적 범위 지정에서는 먼저 로컬 함수를 검색 한 다음 로컬 함수를 호출 한 함수를 검색 한 다음 해당 함수를 호출 한 함수 등을 호출 스택에서 검색합니다. "동적"은 주어진 함수가 호출 될 때마다 호출 스택이 다를 수 있으므로 함수가 호출되는 위치에 따라 다른 변수에 부딪 칠 수 있다는 점에서 변경을 나타냅니다. ( 여기 참조 )

동적 범위에 대한 흥미로운 예를 보려면 여기를 참조 하십시오 .

자세한 내용은 여기여기를 참조 하십시오 .

델파이 / 오브젝트 파스칼의 예제

델파이는 어휘 범위를 가지고 있습니다.

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

델파이가 동적 범위에 가장 가까운 것은 RegisterClass () / GetClass () 함수 쌍입니다. 사용 방법은 여기를 참조 하십시오 .

RegisterClass ([TmyClass])가 특정 클래스를 등록하기 위해 호출 된 시간은 코드를 읽음으로써 예측할 수 없습니다 (사용자가 호출 한 버튼 클릭 메소드에서 호출 됨). GetClass ( 'TmyClass')를 호출하는 코드는 결과 또는 아닙니다. RegisterClass () 호출은 GetClass ()를 사용하여 어휘 범위 내에있을 필요는 없습니다.

동적 범위의 또 다른 가능성 은 델파이 2009의 익명 메소드 (클로저)입니다. 호출 함수의 변수를 알고 있기 때문입니다. 재귀 적으로 호출 경로를 따르지 않으므로 완전히 동적이지 않습니다.


2
실제로 개인은 클래스가 정의 된 전체 유닛에서 액세스 할 수 있습니다. 이것이 바로 "Strict private"이 D2006에 도입 된 이유입니다.
Marco van de Voort

2
일반 언어의 경우 +1 (복잡한 언어와 많은 설명이없는 예제와 반대)
Pops

36

@Arak과 같은 사람들의 모든 기능을 갖춘 언어에 구애받지 않는 답변을 좋아합니다. 이 질문은 JavaScript 로 태그 되었으므로이 언어에 매우 특정한 메모를 작성하고 싶습니다.

JavaScript에서 범위를 지정하기위한 선택은 다음과 같습니다.

  • 있는 그대로 (범위 조정 없음)
  • 어휘 var _this = this; function callback(){ console.log(_this); }
  • 경계 callback.bind(this)

JavaScript 에는 실제로 동적 범위 가 없다는 점은 주목할 가치가 있습니다. .bind조정this키워드를 가깝지만 기술적으로는 다릅니다.

다음은 두 가지 방법을 모두 보여주는 예입니다. 콜백 범위 지정 방법에 대한 결정을 할 때마다 약속, 이벤트 핸들러 등에 적용됩니다.

어휘

다음은 Lexical ScopingJavaScript에서 콜백 이라는 용어 입니다.

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

경계

범위를 정하는 또 다른 방법은 다음을 사용하는 것입니다 Function.prototype.bind.

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

이 방법들은 내가 아는 한 행동 상 동일합니다.


사용 bind은 범위에 영향을 미치지 않습니다.
벤 애스턴

12

어휘 범위 : 함수 외부에서 선언 된 변수는 전역 변수이며 JavaScript 프로그램의 모든 곳에서 볼 수 있습니다. 함수 안에 선언 된 변수는 함수 범위를 가지며 해당 함수 안에 나타나는 코드에만 표시됩니다.


12

IBM 은이를 다음과 같이 정의합니다.

선언이 적용되는 프로그램 또는 세그먼트 단위의 부분. 루틴에 선언 된 식별자는 해당 루틴과 모든 중첩 루틴 내에 알려져 있습니다. 중첩 루틴이 동일한 이름의 항목을 선언하면 중첩 루틴에서 외부 항목을 사용할 수 없습니다.

예 1 :

function x() {
    /*
    Variable 'a' is only available to function 'x' and function 'y'.
    In other words the area defined by 'x' is the lexical scope of
    variable 'a'
    */
    var a = "I am a";

    function y() {
        console.log( a )
    }
    y();

}
// outputs 'I am a'
x();

예 2 :

function x() {

    var a = "I am a";

    function y() {
         /*
         If a nested routine declares an item with the same name,
         the outer item is not available in the nested routine.
         */
        var a = 'I am inner a';
        console.log( a )
    }
    y();

}
// outputs 'I am inner a'
x();

8

어휘 범위 는 중첩 된 함수 그룹 에서 내부 함수가 상위 범위의 변수 및 기타 자원에 액세스 할 수 있음을 의미합니다 . 이것은 자식 함수가 부모의 실행 컨텍스트에 어휘 적으로 묶여 있음을 의미합니다. 어휘 범위는 때로는 정적 범위 라고도합니다 .

function grandfather() {
    var name = 'Hammad';
    // 'likes' is not accessible here
    function parent() {
        // 'name' is accessible here
        // 'likes' is not accessible here
        function child() {
            // Innermost level of the scope chain
            // 'name' is also accessible here
            var likes = 'Coding';
        }
    }
}

어휘 범위에 대해 알 수있는 것은 앞으로 작동한다는 것입니다. 즉, 하위 실행 컨텍스트에서 이름에 액세스 할 수 있습니다. 그러나 부모에게 뒤로 작동하지 않으므로 부모가 변수에 likes액세스 할 수 없습니다.

이것은 또한 다른 실행 컨텍스트에서 동일한 이름을 가진 변수가 실행 스택의 맨 위에서 아래로 우선한다는 것을 알려줍니다. 가장 안쪽의 함수 (실행 스택의 최상위 컨텍스트)에서 다른 변수와 유사한 이름을 가진 변수가 우선 순위가 높습니다.

여기 에서 가져옵니다 .


8

간단한 언어에서 어휘 범위는 스코프 외부에서 정의 된 변수이거나 스코프 내에서 스코프를 자동으로 사용할 수 있으므로이를 전달할 필요가 없습니다.

예:

let str="JavaScript";

const myFun = () => {
    console.log(str);
}

myFun();

// 출력 : JavaScript


2
예를 들어 가장 짧고 가장 좋은 대답. ES6 '화살표 기능이 문제를 해결한다고 덧붙일 수 있습니다 bind. 그들과 함께, bind더 이상 필요하지 않습니다. 이 변경 확인에 대한 자세한 내용은 stackoverflow.com/a/34361380/11127383
Daniel Danielecki

4

어휘동적 범위 지정 을 둘러싼 대화에는 중요한 부분이 있습니다. 범위 가 지정된 변수 의 수명 에 대한 명확한 설명 또는 변수에 액세스 할 수있는 경우 .

동적 범위 지정은 전통적으로 우리가 생각하는 방식으로 "전역"범위 지정에 매우 느슨하게 대응합니다 (두 가지를 비교 한 이유는 이미 언급 되었기 때문입니다. 특히 링크 된 기사의 설명이 마음에 들지 않습니다. ); 링크 된 기사에 따르면 "... [it]는 전역 범위 변수를 대체하는 데 유용합니다."

그래서 일반 영어로 두 범위 지정 메커니즘 사이의 중요한 차이점은 무엇입니까?

어휘 범위 지정은 위의 답변 전반에 걸쳐 매우 잘 정의되어 있습니다. 어휘 범위 변수는 정의 된 함수의 로컬 수준에서 사용 가능하거나 액세스 가능합니다.

그러나 OP의 초점이 아니기 때문에 동적 범위 지정은 많은 관심을받지 못했으며 수신 된 관심은 아마도 조금 더 필요할 것입니다 (다른 답변에 대한 비판이 아니라 오히려 "오, 그 대답은 우리가 조금 더 있기를 바랐다 "). 여기 조금 더 있습니다 :

동적 범위 지정은 함수 호출 기간 동안 또는 함수가 실행되는 동안 큰 프로그램에서 변수에 액세스 할 수 있음을 의미합니다. 실제로 Wikipedia는 실제로 두 가지 의 차이점에 대한 설명으로 훌륭하게 작동합니다 . 난독 화하지 않도록 동적 범위 지정을 설명하는 텍스트는 다음과 같습니다.

... [I] n 동적 범위 지정 (또는 동적 범위) 변수 이름의 범위가 특정 함수이면 해당 범위는 함수가 실행되는 시간입니다. 함수가 실행되는 동안 변수 이름이 존재합니다. 변수에 바인딩되어 있지만 함수가 반환 된 후 변수 이름이 존재하지 않습니다.


3

어휘 범위는 함수가 함수가 정의 된 컨텍스트에서 변수를 찾고 해당 범위의 바로 범위에서 변수를 찾지 않음을 의미합니다.

자세한 내용을 원한다면 Lisp 에서 어휘 범위가 어떻게 작동하는지 살펴보십시오 . Kyle Linin이 Common Lisp의 Dynamic 및 Lexical 변수에서 선택한 답변 은 여기의 답변보다 훨씬 명확합니다.

우연히도 나는 이것에 대해 Lisp 클래스에서만 배웠으며 JavaScript에도 적용됩니다.

Chrome 콘솔 에서이 코드를 실행했습니다.

// JavaScript               Equivalent Lisp
var x = 5;                //(setf x 5)
console.debug(x);         //(print x)
function print_x(){       //(defun print-x ()
    console.debug(x);     //    (print x)
}                         //)
(function(){              //(let
    var x = 10;           //    ((x 10))
    console.debug(x);     //    (print x)
    print_x();            //    (print-x)
})();                     //)

산출:

5
10
5

3

JavaScript의 어휘 범위는 함수 외부에 정의 된 변수가 변수 선언 후 정의 된 다른 함수 내에서 액세스 할 수 있음을 의미합니다. 그러나 그 반대는 사실이 아닙니다. 함수 내부에 정의 된 변수는 해당 함수 외부에서 액세스 할 수 없습니다.

이 개념은 JavaScript에서 클로저에 많이 사용됩니다.

아래 코드가 있다고 가정 해 봅시다.

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

이제 add ()->를 호출하면 3이 인쇄됩니다.

따라서 add () 함수는 x메소드 함수 add 전에 정의 된 전역 변수에 액세스합니다 . 이것은 JavaScript의 어휘 범위로 인해 호출됩니다.


코드 스 니펫은 동적 범위 언어 용임을 고려하십시오. add()주어진 코드 스 니펫 바로 다음에 호출 된 함수는 3을 인쇄합니다. 어휘 범위 지정은 단순히 함수가 로컬 컨텍스트 외부의 전역 변수에 액세스 할 수 있음을 의미하지는 않습니다. 따라서 예제 코드는 어휘 범위 지정의 의미를 보여주는 데 실제로 도움이되지 않습니다. 코드에서 어휘 범위를 표시하려면 카운터 예제 또는 코드의 다른 가능한 해석에 대한 설명이 필요합니다.
C 퍼킨스

2

어휘 범위는 실행 스택의 현재 위치에서 볼 수있는 식별자 (예 : 변수, 함수 등)의 어휘를 나타냅니다.

- global execution context
    - foo
    - bar
    - function1 execution context
        - foo2
        - bar2
        - function2 execution context
            - foo3
            - bar3

foobar 그들은 세계이기 때문에 가능한 식별자의 사전 내에서 항상.

function1실행되는, 그것의 사전에 액세스 할 수있다 foo2, bar2, foo,와 bar.

언제 function2 실행되고, 그것의 사전에 액세스 할 수있는 foo3, bar3, foo2, bar2, foo, 및 bar.

글로벌 및 / 또는 외부 함수가 내부 함수 식별자에 액세스 할 수없는 이유는 해당 함수의 실행이 아직 발생하지 않았으므로 해당 식별자가 메모리에 할당되지 않았기 때문입니다. 또한 내부 컨텍스트가 실행되면 실행 스택에서 제거되어 모든 식별자가 가비지 수집되어 더 이상 사용할 수 없음을 의미합니다.

마지막으로, 중첩 된 실행 컨텍스트가 항상 상위 실행 컨텍스트에 액세스 할 수 있고 따라서 더 큰 식별자 사전에 액세스 할 수있는 이유입니다.

보다:

위의 정의를 단순화하는 데 도움을 주신 @ robr3rd 에게 특별한 감사를드립니다 .


1

이 질문에 대해 한 걸음 물러나 더 큰 해석 프레임 워크 (프로그램 실행)에서 범위 지정 역할을 살펴봄으로써 얻을 수있는 다른 각도가 있습니다. 다시 말해, 언어에 대한 인터프리터 (또는 컴파일러)를 구축 중이고 프로그램 및 일부 입력에 따라 출력 계산을 담당했다고 가정하십시오.

해석에는 다음 세 가지를 추적해야합니다.

  1. 상태-즉 힙 및 스택의 변수 및 참조 메모리 위치

  2. 해당 상태에서의 작업, 즉 프로그램의 모든 코드 줄

  3. 환경 특정되는 동작이 실행 - 즉, 투영 상태로 동작합니다.

인터프리터는 프로그램의 첫 번째 코드 라인에서 시작하여 환경을 계산하고 해당 환경에서 라인을 실행하며 프로그램 상태에 미치는 영향을 캡처합니다. 그런 다음 프로그램의 제어 흐름에 따라 다음 코드 줄을 실행하고 프로그램이 끝날 때까지 프로세스를 반복합니다.

모든 작업에 대한 환경을 계산하는 방법은 프로그래밍 언어로 정의 된 공식 규칙 집합을 통하는 것입니다. "바인딩"이라는 용어는 프로그램의 전체 상태를 환경의 값에 매핑하는 것을 설명하는 데 자주 사용됩니다. "전체 상태"는 전역 상태를 의미하는 것이 아니라 실행의 모든 ​​시점에서 도달 가능한 모든 정의의 합계를 의미합니다.

이것은 범위 지정 문제가 정의되는 프레임 워크입니다. 이제 옵션의 다음 부분으로 넘어갑니다.

  • 인터프리터의 구현자는 가능한 한 환경을 프로그램 상태에 최대한 가깝게하여 작업을 단순화 할 수 있습니다. 따라서, 코드 라인의 환경은 이전 라인이 할당인지, 함수 호출인지, 함수로부터의 리턴인지, 또는 while 루프와 같은 제어 구조.

이것은 동적 범위 지정 의 요지이며 , 코드가 실행되는 환경은 실행 컨텍스트에 의해 정의 된 프로그램의 상태에 바인딩됩니다.

  • 또는 언어를 사용하는 프로그래머를 생각하고 변수가 취할 수있는 값을 추적하는 작업을 단순화 할 수 있습니다. 과거 실행의 전체 결과에 대한 추론과 관련하여 너무 많은 경로와 너무 많은 복잡성이 있습니다. Lexical Scoping 은 현재 환경을 현재 블록, 기능 또는 기타 범위 단위 및 상위 (예 : 현재 시계를 둘러싸는 블록 또는 현재 기능을 호출 한 기능)에 정의 된 상태 부분으로 제한하여 이를 수행합니다.

즉, 어휘 범위 를 사용하면 코드에서 보는 환경이 블록 또는 함수와 같이 언어로 명시 적으로 정의 된 범위와 연관된 상태에 바인딩됩니다.


0

고대의 질문이지만 여기에 내가 가지고 있습니다.

어휘 (정적) 범위는 소스 코드 에서 변수의 범위를 나타냅니다 .

JavaScript와 같은 언어에서 함수를 전달하고 기타 객체에 첨부하고 다시 첨부 할 수있는 언어에서는 해당 범위가 당시 함수를 호출하는 사람에 따라 다르지만 그렇지 않습니다. 그런 식으로 범위를 변경하면 동적 범위가되고 JavaScript는 this객체 참조를 제외하고는 그렇게하지 않습니다 .

요점을 설명하려면 :

var a='apple';

function doit() {
    var a='aardvark';
    return function() {
        alert(a);
    }
}

var test=doit();
test();

이 예에서 변수 a는 전역 적으로 정의되었지만 doit()함수 에는 음영 처리되어 있습니다. 이 함수는 다른 함수를 반환합니다.이 함수는 a자체 범위를 벗어난 변수에 의존합니다 .

당신이 실행하는 경우 사용되는 값입니다 찾기 것 aardvark,하지 apple가의 범위에 있지만, 이는 test()기능, 원래의 함수의 어휘 범위에 있지 않습니다. 즉, 사용 된 범위는 함수가 실제로 사용되는 범위가 아니라 소스 코드에 나타나는 범위입니다.

이 사실은 성가신 결과를 초래할 수 있습니다. 예를 들어, 함수를 개별적으로 구성하는 것이 더 쉬운 것으로 결정한 다음 이벤트 핸들러와 같이 시간이 오면이를 사용할 수 있습니다.

var a='apple',b='banana';

function init() {
  var a='aardvark',b='bandicoot';
  document.querySelector('button#a').onclick=function(event) {
    alert(a);
  }
  document.querySelector('button#b').onclick=doB;
}

function doB(event) {
  alert(b);
}

init();
<button id="a">A</button>
<button id="b">B</button>

이 코드 샘플은 각각 하나를 수행합니다. 어휘 범위로 인해 button A은 내부 변수를 사용하지만 button B은 그렇지 않습니다. 당신이 원했던 것보다 더 많이 중첩 함수를 만들 수 있습니다.

그런데 두 예제 모두에서 포함 함수 함수가 과정을 실행하더라도 내부 어휘 범위 변수는 지속됨을 알 수 있습니다. 이것을 closure 라고 하며 외부 함수가 완료된 경우에도 중첩 함수가 외부 변수에 액세스하는 것을 나타냅니다. JavaScript는 이러한 변수가 더 이상 필요하지 않은지 여부를 판단 할 수있을 정도로 똑똑해야하며 그렇지 않은 경우 가비지 수집 할 수 있습니다.


-1

나는 보통 예를 들어 배우고 여기 약간의 것이 있습니다.

const lives = 0;

function catCircus () {
    this.lives = 1;
    const lives = 2;

    const cat1 = {
        lives: 5,
        jumps: () => {
            console.log(this.lives);
        }
    };
    cat1.jumps(); // 1
    console.log(cat1); // { lives: 5, jumps: [Function: jumps] }

    const cat2 = {
        lives: 5,
        jumps: () => {
            console.log(lives);
        }
    };
    cat2.jumps(); // 2
    console.log(cat2); // { lives: 5, jumps: [Function: jumps] }

    const cat3 = {
        lives: 5,
        jumps: () => {
            const lives = 3;
            console.log(lives);
        }
    };
    cat3.jumps(); // 3
    console.log(cat3); // { lives: 5, jumps: [Function: jumps] }

    const cat4 = {
        lives: 5,
        jumps: function () {
            console.log(lives);
        }
    };
    cat4.jumps(); // 2
    console.log(cat4); // { lives: 5, jumps: [Function: jumps] }

    const cat5 = {
        lives: 5,
        jumps: function () {
            var lives = 4;
            console.log(lives);
        }
    };
    cat5.jumps(); // 4
    console.log(cat5); // { lives: 5, jumps: [Function: jumps] }

    const cat6 = {
        lives: 5,
        jumps: function () {
            console.log(this.lives);
        }
    };
    cat6.jumps(); // 5
    console.log(cat6); // { lives: 5, jumps: [Function: jumps] }

    const cat7 = {
        lives: 5,
        jumps: function thrownOutOfWindow () {
            console.log(this.lives);
        }
    };
    cat7.jumps(); // 5
    console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}

catCircus();

-1

이 주제는 내장 bind함수와 밀접한 관련이 있으며 ECMAScript 6 화살표 함수 에서 소개되었습니다 . 우리가 사용하고 싶었던 모든 새로운 "클래스"(실제로 함수) 메소드 bind에 대해 스코프에 액세스하려면이 작업을 수행해야 했기 때문에 정말 성가신 일이었습니다 .

기본적으로 JavaScript는 thison 함수 의 범위를 설정하지 않습니다 ( 컨텍스트를 on으로 설정하지 않음 this). 기본적으로 원하는 컨텍스트 를 명시 적으로 말해야 합니다.

화살표 기능 자동 소위 도착 어휘 범위 (그것의 함유 블록의 변수의 정의에 액세스 할 수있는). 사용시 화살표 기능을 자동으로 결합 this화살표 기능은 처음에 정의 된 장소, 및 문맥 이러한 화살표 함수는 그 블록이 포함된다.

아래의 가장 간단한 예에서 실제로 어떻게 작동하는지 확인하십시오.

화살표 이전 함수 (기본적으로 어휘 범위 없음) :

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

화살표 기능 사용 (기본적으로 어휘 범위) :

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

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