빠른 가이드: 폐쇄

안녕하세요 프로그래머입니다! 오늘은 자바스크립트 클로저에 대해 알아보겠습니다. 다들 들어보셨죠? 당신이 가지고 있든 없든, 나는 당신이 그것들을 사용했다고 확신합니다.

너무 많은 것을 포기하지 않고 클로저는 코드와 JavaScript를 전체적으로 이해하기 위해 부인할 수 없는 필수 개념입니다.

이유가 궁금하세요? 시작하자.


학습 목표



  • What is a Closure?
  • Lexical Scope
  • Functions as First-Class Citizens


  • The Benefits of using Closures
  • Encapsulation


  • Closure Examples
  • Example 1
  • Example 2

  • Summary + Recap



  • 폐쇄란 무엇인가

    A closure is the combination of a function and the environment in which it was declared.

    Considered one of the pillars of JavaScript, closures allow a function to access variables from an enclosing scope.

    In other words, a closure gives you access to an outer function's scope from an inner function.

    When I said that I was positive that you have used closures before, it is because every function in JavaScript forms a closure.

    어휘 범위

    You may have noticed I used the term "enclosing" in my description of closure -- let's unravel this by learning what lexical scope is.

    Simply, lexical scope is the accessibility of variables dependant on where the function is declared; NOT where the function is invoked (or called).

    For example:

    
    // declare function myFunc()
    function myFunc(){
        // declare and assign variable myName
        // myName is in the scope of myFunc()
        const myName = 'Adriana'
    
        // declare printName()
        function printName(){
          // log the value of variable myName to the console
          console.log(myName)
        }
        return printName()
    }
    
    
    // invoke myFunc()
    myFunc()
    

    In the above snippet, the function printName() is lexically scoped. printName() has access to the variable "myName" because we invoke and return printName() within the myFunc()'s scope.

    So, when we invoke myFunc(), the console outputs "Adriana".

    JavaScript is cool in the way that we can access a variable declared outside of a function within that function. A lot of languages actually do not allow this behavior.

    일류 시민으로서의 기능

    Want to know what else is cool about functions in JavaScript?

    Functions in JavaScript are First-Class Citizens. What does this mean? It is a fancy way to say that:

    • Functions can be passed as a parameter to another function.
    • Functions can be the return value of a function.

    Ultimately, functions are flexible and extremely worth utilizing!


    클로저 사용의 이점

    Now that we got the idea of what a closure is and how they work -- what are the benefits?

    Because of closures, the JavaScript Engine (V8) ensures that the function has access to all of the variables by keeping all the variables declared outside of the innermost function.

    JavaScript is lexically and statically scoped -- so when JavaScript compiles and looks through your code the first time, the JavaScript Engine (V8) catalogs what needs to be closured even before the code is executed or ran.

    So, the benefits?

    • Closures save memory space.
    • Closures allow for encapsulation.
    • Closures reduce bugs.

    캡슐화



    캡슐화는 "외부"세계 또는 전역 범위에 의해 조작되지 않도록 정보를 숨기는 것입니다.

    사용자에게 특정 기능에 대한 액세스 권한을 부여하거나 특정 변수(예: 상태를 저장하는 것)가 수정되는 것을 허용하지 않기 때문에 캡슐화를 사용합니다.

    위의 예와 같이 내부 함수를 다른 함수에 중첩하여 완전히 액세스할 수 없도록 합니다.

    기본적으로 캡슐화는 일부 데이터가 노출되지 않도록 합니다. 캡슐화는 데이터(또는 상태) 또는 해당 데이터에 대한 액세스 권한이 있는 기능에 대한 액세스 측면에서 권한 개념을 촉진합니다.


    폐쇄 예

    Now that we have acknowledged a textbook definition of closures, let's code this out (we are programmers, aren't we?).

    실시예 1

    First, let's declare a function "a" and within "a" declare a variable "cat" set to a string "Charlie":

    function a(){
        let cat = 'Charlie'
    }
    

    Since, we are not returning anything, if we invoked a() we would get undefined. However, our "cat" variable was declared within the function's scope and thus, it is in our memory heap (thanks V8 engine!).

    In order to be a closure, we must return ** and **declare a function within another function:

    function a(){
        let cat = 'Charlie'
        return function b(){
            let dog = 'Zoie'
        }
    }
    

    Let's declare AND return function "b" below our cat variable declaration. Within function "b" we declare another variable "dog" and set it to the string "Zoie". Function "b"'s scope now contains access to variable "dog" while also containing access to variable "cat".

    So, if we wanted to return the value of variables "cat" and "dog" within the scope of function "b", we could do this:

    function a(){
        let cat = 'Charlie'
        return function b(){
            let dog = 'Zoie'
            return `${cat} - ${dog}`
        }
    }
    

    In your console or sandbox, paste the above code snipped and then invoke/call the functions in this order:

    1. a()
    2. b()
    3. a()()

    What did your console output?

    • Invoking a() returns function b().
    • Invoking b() returns an error "b is not defined".
    • Invoking a()() returns our string literal.

    실시예 2

    Let's code out another example:

    
    function outer(){
       let state = 0
    
    }
    

    Here I have declared a function "outer" and declared and assigned a variable "state" to the value of 0.

    If we declare and return another function within outer(), can we access "state"?

    
    function outer(){
       let state = 0
       return function inner() {
          return `Our state is currently at: ${state}.`
       }
    }
    

    Yes! If we paste this code snippet into our sandbox and call outer() and inner(), what is our output?

    • Invoking outer() returns the function inner().
    • Invoking inner() returns an error "inner is not defined".
    • Invoking outer()() returns our string literal with the value of "state."

    In both examples, we are able to access the inner function by invoking the outer function. When we double-invoke the outer function, we are able to access the string literals. Why? By enclosing the inner function in the outer function's scope, we can only invoke it internally. So, we must use the outer scope as a bridge to receive the return value of the inner scope.

    So, how were we able to access the variables in the return statement? JavaScript's Engine (V8) reads through the code from outer function to inner function and shoves the variables into the closure (think of a box). The variables are stored for later use and are never removed because V8 sees that the variables are referenced in another function within the outer function's scope.


    요약 + 요약

    From this article, let's bundle and condense some of the takeaways:

    • JavaScript's Engine is V8.
    • V8 runs and compiles our code.
    • Functions in JavaScript are lexically scoped.
    • Lexical Scope: the accessibility of variables dependant on where the function is declared; NOT where the function is invoked (or called).
    • Functions in JavaScript are First-Class Citizens.
    • Variables declared in the global context OR within an enclosing scope are stored in the memory heap.
    • Closures allow a function to access variables from an enclosing scope even after it leaves the scope in which the function is declared.
    • Because of closures, the JavaScript Engine ensures that an inner function has access to all of the variables within its enclosing scope.
    • Encapsulation = privacy or reduced accessibility of data.

    Still not sure about closures? Here are some resources I used to help me further understand:

  • Encapsulation in JavaScript article




  • 저와 함께 읽고 코딩해주셔서 감사합니다 :)
    질문, 의견 또는 제안 사항이 있습니까? 아래에 두십시오.

    기억하십시오: 항상 학습에 가장 적합한 방식으로 코딩하십시오.

    좋은 웹페이지 즐겨찾기