Closure

WooSangWoock·2023년 5월 14일
0

Lexical Scope

function init() {
    var name = "yeoUl";
    // (1) init 내부에서 displayName() 함수를 선언
    // 내부에서만 이 함수를 호출 OK

    function displayName() {
        // (2) inner function, closure 안에서 
        // 밖의 함수인 init()의 변수 name을 호출 OK
        console.log(name); 
    }

    displayName();
  }

init();

// * lexical scoping
// : (2)에서와 같이 변수의 선언 위치를 고려하여 사용 가능을 판단

Closure

function makeFunc() {
    var name = "yeoUl";

    function displayName() {
      console.log(name);
    }

    return displayName;
  }
  
var myFunc = makeFunc();

myFunc();
// (3) 다른 점으로는 변수에 함수를 담아 이를 호출
// name 변수에 대한 참조가 역시 OK

// **Closure
// : 여기서 myFunc 변수가 Closure를 형성 => makeFunc()의 참조 + Lexical Enviroment(3)

// ES6 이후 let, const 의 추가로 {} 가 새로운 Scope로 작용 
// Module 의 도입으로 하나의 Scope가 추가
// ⇒ Closure는 이 모든 Scope의 변수에 접근 가능

function makeAdder(x) {
  var y = 1;

  return function(z) {
    y = 100;
    return x + y + z;
  };
}

// Closure에 x와 y의 환경이 저장됨
var add5 = makeAdder(5);
var add10 = makeAdder(10);

// add5, add10 모두 Closure로써 작용하지만
/// 서로 다른 Lexical 환경에서 x에 다른 값이 저장되었음

// 함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산
console.log(add5(2));  // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)

// *** 같은 함수를 이용하여 여러가지 변수를 생성해놓고, 이를 사용하는 식으로 활용이 가능함

Closure의 Scope

// Closure의 Scope들 세가지
// - local
// - outer funtions
// - global

// global scope
var e = 10;

function sum(a){
  return function(b){
    return function(c){
      // outer functions scope

      return function(d){
        // local scope
        return a + b + c + d + e;
      }
    }
  }
}

console.log(sum(1)(2)(3)(4)); // 20

Closure 대표적 사용 오류

<!DOCTYPE html>
<html>
    <body>
        <p id="help">Helpful notes will appear here</p>
        <p>E-mail: <input type="text" id="email" name="email"></p>
        <p>Name: <input type="text" id="name" name="name"></p>
        <p>Age: <input type="text" id="age" name="age"></p>

        <script type="text/javascript" src="./normal_mistake.js"></script>    
    </body>
</html>
// normal_mistake.js
function showHelp(help) {
        document.getElementById('help').innerHTML = help;
  }

/**
 * onfocus 상태가 되었을때, 해당 칸에 맞는 도움말로 변경하는 함수
 */
function setupHelp() {
        var helpText = [
                {'id': 'email', 'help': '이메일'},
                {'id': 'name', 'help': '이름'},
                {'id': 'age', 'help': '나이'}
            ];

        for (var i = 0; i < helpText.length; i++) {
            var item = helpText[i];

            // 여기서 onfocus에 연결되는 Closure가 모두 같게 됨
            // => 실행 시 문제가 발생
            document.getElementById(item.id).onfocus = function() {
                showHelp(item.help);
            }
        }
    }

setupHelp();

해결된 버전 1

function showHelp(help) {
    document.getElementById('help').innerHTML = help;
}

/**
* onfocus 상태가 되었을때, 해당 칸에 맞는 도움말로 변경하는 함수
*/
function setupHelp() {
    var helpText = [
            {'id': 'email', 'help': '이메일'},
            {'id': 'name', 'help': '이름'},
            {'id': 'age', 'help': '나이'}
        ];

    for (var i = 0; i < helpText.length; i++) {
        // let keyword가 사용되어서, for 구문 내의 3개의 scope가 서로 구분됨
        let item = helpText[i];

        document.getElementById(item.id).onfocus = function() {
            showHelp(item.help);
        }
    }
}

setupHelp();

해결된 버전 2

function showHelp(help) {
    document.getElementById('help').innerHTML = help;
}

/**
* onfocus 상태가 되었을때, 해당 칸에 맞는 도움말로 변경하는 함수
*/
function setupHelp() {
    var helpText = [
            {'id': 'email', 'help': '이메일'},
            {'id': 'name', 'help': '이름'},
            {'id': 'age', 'help': '나이'}
        ];

    helpText.forEach(function(text) {
        // forEach 사용시 각각의 원소마다 다른 익명함수가 호출되기 때문에 다른 Closure를 가짐
        document.getElementById(text.id).onfocus = function() {
            showHelp(text.help);
        }
    })
}

setupHelp();
profile
이것저것

0개의 댓글