Home

[JS] 함수형 자바스크립트 [Part.1] 함수형으로 사고하기

functional-javascript

함수형 자바스크립트 - 모던 웹 개발에 충실한 실전 함수형 프로그래밍 안내서

루이스 아텐시오 지음

한빛 미디어

한빛 미디어에서 나온 루이스 아텐시오의 ‘함수형 자바스크립트’ 중 [ Part.1 ] 함수형으로 사고하기를 읽고 정리한 페이지이다.


Part_1. 함수형으로 사고하기

목차

  1. 함수형 길들이기
  2. 고계 자바스크립트

함수형 길들이기

  • 자바스크립트는 언어 내부에 상태를 적절히 관리할 장치가 마땅치 않다. ( 자바스크립트 동적 언어이다 보니 상태가 계속 변경 될 수 있음을 말하는 것인지 헷갈린다? )

  • 함수형 프로그래밍(FP: Functional Programming)은 애플리케이션을 작성할 때 확장성, 모듈화, 재사용성, 테스트 용이성 등 많은 도움을 줄 수 있다.

  • FP는 프레임워크나 도구가 아니다. 지금까지 객체지향으로 개발해왔던 사고와 근본적으로 다르며 FP를 사용하기 위해서는 사고를 전환해야 한다.

  • FP의 진정한 목적은 어떤 결과를 만드는 함수를 적용하는 그런 단순한 차원이 아니다. 진짜 목표는 애플리케이션의 부수효과(side effect)를 방지하고 상태 변이(mutation of state)를 감소하기 위해 데이터의 제어 흐름과 연산을 추상(abstract)하는 것이다.

  • 함수형 프로그램을 이해하려면, 다음 기본 개념을 이해해야 한다

    • 선언적 프로그래밍

      • FP는 큰 틀에서 선언적 프로그래밍 패러다임에 속한다
      • 명령형 프로그램은 어떤 결과를 내기 위해 시스템의 상태를 변경하는 구문을 위에서 아래로 죽 늘어놓은 순차 열에 불과하다. 이와 달리 선언적 프로그래밍은 서술부와 평가부를 분리하여, 제어 흐름이나 상태 변화를 특정하지 않고도 프로그램 로직이 무엇인지를 표현식으로 나타낸다
      • FP를 하기 위한 첫 번째 작업은 명령형으로 작성된 코드를 함수로 추상화하는 것이다
      • FP는 무상태성불변성은 지향한다
      • FP는 부수효과와 상태 변이를 일으키지 않는 순수함수를 써야 한다.
    • 순수 함수

      • 기본적으로 FP는 순수함수로 구성된 불변 프로그램을 구축을 전제로 한다. 그럼 순수 함수는 무엇일까?

        • 주어진 입력에만 의존할 뿐, 평가 도중 또는 호출 간 변경될 수 있는 숨겨진 값이나 외부 상태와 무관하게 동작하는 함수
        • 전역 객체나 레퍼런스로 전달된 매개변수를 수정하는 등 함수 스코프 밖에서 어떠한 변경도 일으키지 않는 함수
      // 아래 함수는 함수 밖에 있는 외부 스코프의 변수를 읽고 수정한다.
      // 이 함수는 부수효과를 동반하기 때문에 순수함수가 아니다.
      var counter = 0
      function increment() {
        return ++counter;
      }
      
      // 아래 함수는 호출 될때마다 값이 달라진다.
      // 이는 순수함수가 아니다
      function getDate() {
        return new Date();
      }
      
      // 억지로 만들어낸 예제이다. 말이 안되긴 한다;;
      // 아래는 매개변수로 들어온 값을 변경해버린다. 이것도 순수함수가 아니다.
      function add(x, y) {
        x += y
        return x;
      }
      • FP는 모든 상태 변이를 근절을 주장하는 것은 아니다. 상태 변이를 줄이고 관리할 수 있는 프레임워크를 제공하여 순수/불순 함수를 구분하자는 것이다
      • 함수가 일관된 반환 값을 보장하도록 해서 전체 함수 결과를 예측 가능한 방향으로 유도하는 것이 목표이다.
    • 참조 투명성

      • 어떤 함수가 동일한 입력을 받았을 때 동일한 결과를 내면 이를 참조 투명한 함수라 한다.
      • 참조 투명함 함수 사용 시 이점

        • 테스트가 쉬워진다
        • 전체 로직을 파악하는 것도 쉬워진다.
        • 리팩토링/치환 등의 작업을 쉽게 할 수 있다.
      • 참조 투명한 함수를 작성할 때는 객체를 변이하지 않는 것이 중요하다.
    • 불변성

      • 불변 데이터는 한번 생성된 후 바뀌지 않는다. 하지만 array나 Object 등의 객체는 불변이 아니어서 함수 인수로 전달해도 원래 내용이 변경되어 부수효과가 발생할 수 있다.
  • 결국 FP외부에서 관찰 가능한 부수효과가 제거된 불변 프로그램을 작성하기 위해 순수함수를 선언적으로 평가하는 것을 말한다.

  • 함수를 순수 연산의 관점에서 데이터를 절대 변경하지 않는 고정된 작업 단위로 바라본다면 버그는 줄어들게 돼있다

  • FP로 개발을 하면 무엇이 좋아질까? 일반적으로 FP로 개발을 하게 된다면 다음처럼 작업하게 될 것이다.

    • 간단한 함수로 작업을 분해한다.

      • 함수를 작게 분해할 경우 작업 단위는 바로 함수 자신이 된다.

      • FP에서 모듈화는 단일성의 원리와 밀접한 관련이 있다. 함수는 저마다 한 가지 목표만 바라봐야 한다는 것이다

      • 이런 작은 함수 여러 개를 실행해서 하나의 큰 작업을 진행하는 것이다. 이때 합성 기법 개념이 나온다.

        • 설명
        두 함수 f, g가 있을때 이 두개를 함성하면 수학적으로 다음과 같아진다. 'f 합성 g' 라고 있는다.
        f * g = f(g(x))
        • 예시
        // 위에 함성을 함수로 구현한 것이 합성 함수이다.
        var run = function(f, g) {
          return function(x) {
            return f(g(x));
          };
        };
        
        const multiplier = (x) => {
          return x * x;
        };
        
        const plus1 = (x) => {
          return x + 1;
        }
        
        // run에 함수 2개를 넣으면 함수가 리턴된다. 이 함수를 실행시켜야 합성 되는 것이다.
        const test = run(multiplier, plus1);
        // 위 코드는 결국 multiplier(plus1(x))가 된다.
        console.log(test(10));  // 121
        • 위 코드의 run처럼 다른 함수를 인수로 받는 함수를 고계함수라 한다.
        • lodash에도 위 run과 같은 동작을 하는 코드가 있다. 바로 _.flow, _.flowRight라는 코드인데 나중에 살펴보자.
    • 흐름 체인으로 데이터를 처리한다.

      • 체인은 같은 객체를 반환하는 순차적인 함수 호출이다.
      • 체인도 합성처럼 코드를 간결 명료하게 작성할 수 있다.
      • 함수 체인은 필요한 시점까지 실행을 미루는 느긋한 평가(lazy evaluation)을 수행한다.
      // lodash에서 chain을 사용하면 value()를 호출해야지 값을 얻을 수 있다.
      // 즉 value()를 호출 하지 않는다면 일련의 코드를 전부 실행하지 않는 다는 것이다.
      _.chain(list)
      .filter(item => item.price > 1000)
      .value();
    • 리액티브 패러다임을 실현하여 이벤트 중심 코드의 복잡성을 줄인다.

      • 리액티브 패러다임이 무엇인지 조사가 필요해 보인다. 이해를 잘 못 하겠다…
      • 리액티브 패러다임의 가장 큰 장점은, 더 높은 수준으로 코드를 추상하며 비동기, 이벤트 기반 프로그램을 설정하느라 반복되는 판박이 코드를 아예 잊고 비즈니스 로직에만 전념할 수 있게 해준다는 것이다.
      • 리액티브 패러다임은 옵저버블(opservable)이라는 아주 중요한 장치를 매개로 움직인다.
  • 정리

    • 순수 함수를 사용한 코드는 전역 상태를 바꾸거나 깨뜨릴 일이 전혀 없음므로 테스트, 유지보수가 더욱 더 쉬운 코드를 개발할 수 있게 해준다.
    • FP는 코드를 선언적으로 작성하므로 헤아리기 쉽고 전체 애플리케이션의 가독성이 향상된다. 또 함수와 람다 표현식으로 보다 깔끔하게 코딩할 수 있다.
    • 컬렉션 데이터는 map, reduce를 이용하면 함수 체인으로 연결하여 매끄럽게 처리 할 수 있다.
    • FP는 함수를 기본적인 구성 요소로 취급한다. 이는 일급/고계함수 개념에 기반을 두며 코드의 모듈성, 재사용성을 높여준다.
    • 리액티브/함수형 프로그램을 융합하면 이벤트 기반 프로그램 특유의 복잡성을 줄일 수 있다.

고계 자바스크립트

  • 자바스크립트는 객체지향과 함수형을 혼합한 하이브리드 언어이다.

  • 자바스크립트 함수는 주요 작업 단위로서 애플리케이션에게 할 일을 시키는 역할뿐만 아니라 객체 정의, 모듈 생성, 이벤트 처리 등의 책임도 맡는다.

  • 자바스크립트는 어디까지나 함수형인 동시에 객체지향 언어라는 사실에 주의해야 한다. 함수형 스타일에 반하는 가변 연산, 명령식 제어 구조, 객체 인스턴스의 상태를 변경하는 코드를 사용하게 된다면 이는 진짜 함수형 자바스크립트 코드가 아니다. 결국 코드를 어떻게 작성하느냐에 따라서 함수형 코드가 될 수 있을수도, 없을 수도 있는 것이다.

  • 함수형 VS 객체지향

    • 객체지향 프로그램
    • 자바스크립트는 객체지향 언어지만 자바 등 타 언어에서는 당연한 클래스 상속을 지원하지 않는다.
    • class나 extends 같이 보기 좋은 키워드로 설정은 가능하지만, 자바스크립트 프로토타입 체제의 진정한 작동 방식과 강력함을 애써 숨기는 꼴이 되고 말았다. 결국 반쪽짜리가 된 것이다.
    • 객체지향 애플리케이션은 인스턴스 메서드를 통해 가변 상태를 노출하고 조작할 수 있도록, 객체 기반의 캡슐화에 지나치게 의존한 채 가변 상태의 무결성을 유지한다. 결국 객체의 데이터와 잘게 나뉜 기능이 단단히 유착되어 응집도가 높은 패키지가 형성된다.
    • 함수형 프로그램
    • 호출자(caller)로부터 데이트를 숨길 필요 없이 소규모의, 아주 단순한 자료형만을 대상으로 동작한다.
    • 데이터와 기능을 느슨하게 결합하는 형태인데, 함수형 코드는 잘게 나뉜 인스턴스 메서드 대신 여러 자료형에 두루 적용가능하고 굵게 나뉜 연산에 더 의존한다.
    • FP로 개발한 코드는 객체 데이터가 특정 코드에 종속되지 않아서 재사용성, 유지 보수성에 좋다. 차이점
    • 객체지향은 데이터와 데이터 관계의 본질에 초점을 두지만, 함수형의 관심사는 해야 할 일, 즉 기능이다.
    • 자바스크립트는 객체지향 + 함수형 언어이므로 함수형 자바스크립트로 개발할 때에는 상태 변화 관리에 신경 써야 한다.
    • 객체 지향과 함수형 프로그래밍의 중요 특징 비교
    함수형 객체지향형
    합성단위 함수 객체(클래스)
    프로그래밍 스타일 선언적 명령형
    데이터와 기능 독립적인 순수함수가 느슨하게 결합 클래스 안에서 메서드와 단단히 결합
    상태 관리 객체를 불변 값으로 취급 인스턴스 메서드를 통해 객체를 변이시킴
    제어 흐름 함수와 재귀 루프와 조건 분기
    스레드 안전 동시성 프로그래밍 가능 캡슐화하기 어려움
    캡슐화 모든 것이 불변이라 필요 없음 데이터 무결성을 지키기 위해 필요함
  • 자바스크립트 객체의 상태 관리

    • 프로그램의 상태란 어느 한 시점에 찍은 모든 객체에 저장된 데이터의 스냅샷을 뜻한다.

    • 자바스크립트 객체는 너무나 동적이어어서 언제건 속성을 추가, 삭제, 수정 할 수 있어서 객체 상태를 보호하는 측면에 최악이다.

    • 불변 기능을 지닌 불변 객체는 순수 객체로 볼 수 있는데, 이를 이용하면 코드의 이해/관리가 쉬워진다.

    • 그렇다면 자바스크립트에서는 불변 객체를 어떻게 만들 수 있을까?

    • 객체를 값으로 취급하는 방법

      • 문자열과 숫자는 처음부터 불변 값이기 때문에 가장 이해하기 쉬운 자료형이다. FP에서는 이런 식으로 움직이는 형식을 이라고 한다. 불변성을 바탕으로 사고하려면 모든 객체를 값으로 취급해야 한다.
      • 자바 final이나 F#같은 언어는 별도로 지정하지 않으면 불변 변수가 되지만 자바스크립트는 이런게 가능하지 않다(const가 있지만…) 기본형 값은 변경할 수 없지만, 기본형을 가리키는 변수 상태가 변경될 수 있기 때문이다. 그래도 FP를 하려면 적어도 데이터를 불변 레퍼런스로 바라보게 해서 사용자 정의 객체도 처음부터 불변이었던 것처럼 작동 시킬 수 있어야 한다.
      • ES6부터 추가된 const로 어느정도 가능하다. 값을 재할당하거나 레퍼런스를 다시 선언할 수 없게 해준다. 하지만 객체의 내부 상태가 변경 되는 것까지는 막지 못한다.
      const name = 'jonathan';
      name = 'dave';    // const는 재할당 못함.
      
      const person = {
        age: 20,
        name: 'jonathan'
      };
      person.name = 'dave' // 하지만 객체 내부 상태가 변경되는 것은 막지 못함.
      • 이를 위해서 값 객체 패턴을 사용한다. 아래 코드를 보면 쉽게 이해할 수 있다.
      const person = (age, name) => {
        let _age = age;
        let _name = name;
      
        return {
          age: () => _age,
          name: () => _name,
        }
      };
      
      const a = person(10, 'jonathan');
      console.log(a.age());   // 10
      console.log(a.name());  // jonathan
      • 메서드를 일부만 호출자에게 공개하고, 불변객체로 하고 싶은 변수들을 프라이빗 변수처럼 다루는 객체 리터럴 인터페이스를 반환하는 형식이다. 이런 변수는 클로져(closure)를 거쳐야만 객체 리터럴에 접근 할 수 있다. 이렇게 반환된 객체는 사실상 변이를 일으키는 메서드가 전혀 없는 기본형처럼 작동한다.
      • 값 객체 패턴은 이상적이지만, 실세계의 문제를 전부 모형화하기엔 충분하지 않다. 실무에서는 레거시 객체와 상호작용하거나 계층적 데이터를 처리하는 코드가 필요할 경우가 생긴다. 이럴때는 Object.freeze를 사용한다.
    • 가동부의 깊이를 동결하는 방법

      • Object.freeze() 함수는 writable 속성을 false로 셋팅해서 객체 상태를 변경하지 못하도록 동결한다.
      class Person {
        constructor(name, age) {
          this.name = name;
          this.age = age;
        }
      };
      
      const jonathan = new Person( 'jonathan', 10);
      Object.freeze(jonathan);
      jonathan.name = 20; // 책에서는 이경우 에러가 발생한다 하는데.. 에러가 안발생함..
      console.log(jonathan) // Person { name: 'jonathan', age: 10 } -> 값이 변경되지 않음
      
      const ted = new Person({ last: "ted", first: "chang" }, 10);
      Object.freeze(ted);
      ted.age = 20;
      ted.name.last = "whang";
      console.log(ted); // Person { name: { last: 'whang', first: 'chang' }, age: 10 }
                        // name 객체 속성은 변경이 되는 것을 볼 수 있는데 freeze는 중첩된 객체 속성까지 동결하지는 않는다.
      • 위에 예제에서 본것 처럼 중첩된 객체 속성까지는 동결하지는 않기 때문에 하위 객체까지 확실하게 동결 하고 싶을 경우에는 객체 내부를 일일이 freeze() 해줘야 한다. 이처럼 최상위 객체만 동결하는 것을 얕은 동결(shallow freeze)라고 한다.
      • 값 객체 패턴, Object.freeze() 등은 불변성을 코드에 강조하는 기법이다. 하지만 상태를 전혀 변경하지 않는 것은 현실적이지 않는다. 따라서 자바스크립트에서는 이런 복잡성을 줄이기 위해 원본 객체에서 새로운 객체를 만드는 엄격한 정책을 적용하면 큰 도움이 된다. FP에서 객체의 불변 상태를 한곳에서 관리하는 렌즈기법이라 한다.
    • 렌즈 기법

      • OOP에서 메서드를 호출해 객체의 내부 배용을 바꾸는 것은 비일비재하다. 그 결과, 상태를 조회한 결과를 보장하기 어렵고 어떤 객체가 원래 본모습일 거라 기대했던 모듈은 기능 자체게 무용지물이 되는 경우가 발생한다. 개발자가 만약 내부 값이 바뀔 경우 새로운 객체를 만들어 반환하는 방법도 있지만 이는 따분하고 에러도 나기 쉬운 코드가 된다. 만약 도메인 모델에 속성이 100개가 넘는다면 100개 넘는 속성이 하나하나 바뀔때마다 새로운 객체를 리턴하는 코드를 짜야된다.
      • 렌즈(lense), 또는 함수형 레퍼런스(Functional reference)라고도 불리는 이 기법은 상태적 자료형의 속성에 접근하여 분변화하는 함수형 프로그래밍 기법이다.
      • 렌즈를 직접 구현할 필요는 없고 람다JS 라이브러리를 쓰면 쉽게 사용 가능하다.
      const R = require('ramda');
      
      class Person {
        constructor(name, age) {
          this.name = name;
          this.age = age;
        }
      };
      
      const jonathan = new Person('jonathan', 10);
      const ageLense = R.lensProp('age');
      // R.set을 호출하면 원래 객체 상태는 그대로 유지한체 새로운 값이 포함된 객체 사본을 반환한다.
      const newJonathan = R.set(ageLense, '20', jonathan);
      
      console.log(jonathan);    // Person { name: 'jonathan', age: 10 }
      console.log(newJonathan); // { name: 'jonathan', age: '20' } -> 사본이 생성됬다.
      // R.view는 get method와 비슷하다.
      console.log(R.view(ageLense, jonathan));    // 10
      console.log(R.view(ageLense, newJonathan)); // 20
      • 렌즈는 불변 래퍼라는 보호막을 제공할 뿐만 아니라, 필드에 접근하는 로직을 객체로부터 분리하여 this에 의존할 일을 없애고 어떤 객체라도 그 내용물에 접근하여 조작할 수 있는 강력한 함수를 내어주겠다는 FP와도 잘 어울린다.
  • 함수

    • FP에서 함수작업의 기본 단위이다. 모든일은 함수를 중심으로 행해진다.
    • 함수(function)는 () 연산자를 적용하여 평가할 수 있는 모든 호출 가능 표현식을 가리키며, 호출자에게 계산한 값 또는 void 함수일 경우 undefined를 반환한다. 다만 FP에서는 사용 가능한 결과를 낼 경우에만 유의미하며, 그 외에는 외부 데이터 변경 등의 부수효과를 일으킨다 볼 수 있다. 결국 결과를 나타낼수 있는 값많을 함수라 본다.
    • 표현식(expression -> 값을 내는 함수)과 구문(statement -> 값을 내지 않는 함수)을 잘 구분해야 한다.
    • 자바스크립트 함수는 모두 Function 형식의 인스턴스이다. length 속성은 정규 매개변수 개수를 나타내며, apply()call() 메소드는 주어진 콘텍스트로 함수를 호출 한다.
    • 함수를 선언하는 방법
    // 1.함수 선언
    function adder(a, b) {
      return a + b;
    }
    
    // 2.익명 함수
    const adder = function (a, b) {
      return a + b;
    }
    
    // 3.람다 표현식
    const adder = (a, b) => a + b;
    
    // 4. method 형태
    const obj = {
      adder: function (a, b) {
        return a + b;
      }
    };
    
    // 5. 생성자를 이용하는 방법
    const adder = new Function('a', 'b', 'return a + b');
    • 함수는 일급 시민이다.

    • 자바스크립트에서 함수는 실제로 객체이기 때문에 일급(first-class)이다. 일급의 조건은 다음과 같다.

      • 변수에 담을 수 있어야 한다.
      • 함수나 메소드에 인자로 넣을 수 있어야 한다.
      • 함수나 메소드에 리턴할 수 있어야 한다.
    • 자바스크립트에서 함수는 위 조건을 만족 하므로 일급 시민이라 할 수 있다.

    • 고계 함수

    • 함수는 함수 인자로 전달하거나 함수를 반환받을 수 있다고 하였는데 이런 함수를 고계함수(higher-order function) 라고 한다.

    • 자바스크립트 함수는 일급 + 고계 함수여서 여느 값이나 다름없다. 즉, 자신이 받은 입력값을 기반으로 정의된 언제가는 실행될 값에 불과 한것이다.

    • 예시

      function applyOperation(a, b, opt) {
      return opt(a, b);
      }
      
      const multiplier = (a, b) => a * b;
      const applyOperation(2, 3, multiplier);   // 6
    • 자바스크립트에서 함수는 일급이라서 일단 변수에 할당한 뒤 나중에 실행해도 상관없다.

    • 함수 호출 유형

    • 자바스크립트는 호출 시점의 런타임 콘텍스트, 즉 함수 본체 내부의 this값을 자유롭게 지정할 수 있으며 호출 하는 방법도 다양하다.

      // 1. 전역 함수로 호출
      function doWork() {
      this.myVar = '어떤 값';
      }
      
      doWork();
      
      // 2. 메소드로 호출
      var obj = {
      prop: '어떤 속성',
      getProp: function() {
        return this.prop
      }
      };
      
      obj.getProp();
      
      // 3. new를 붙여 생성자로 호출
      function MyType(arg) {
      this.prop = arg;
      }
      
      var someVal = new MyType('test');
    • this 레퍼런스가 가리키는 대상은 어휘적 콘텍스트(코드상 위치)가 아니라 함수를 사용하는 방법(적역, 객체 메소드, 생성자 등)에 따라 달라진다. 결국 함수가 실행되는 콘텍스트를 잘 살펴봐야 한다.

    • 하지만 함수형 코드에서 this를 쓸 일은 거의 없으며 써서도 안된다. 마찬가지로 apply(), call()도 써서는 안된다.

  • 클로저

    • 클로저는 함수를 선언할 당시의 환경에 함수를 묶어둔 자료구조이다. 함수 선언부의 물리적 위치에 의존하므로 정적 스코프 혹은 어휘 스코프라고도 한다.
    • 스코프는 일련의 변수 바인딩을 한데 모아 변수가 정의된 코드 영역을 확정하는데, 클로저는 함수의 스코프를 상속한 것이라 볼수 있다.
    function makeAddFunction(amount) {
      function add(number) {    // add 함수는 makeAddFunction에 어휘적으로 바인딩되어
        return number + amount; // amount 변수에 접근이 가능하다.
      }
      return add;
    }
    
    function makeExponentialFunction(base) {
      function raise (exponent) {         // raise 함수는 makeExponentialFunction에 어휘적으로
        return Math.pow(base, exponent);  // 바인딩되어 base 변수에 접근 가능하다.
      }
      return raise;
    }
    
    var addTenTo = makeAddFunction(10);
    addTento(10);   // 20
    
    var raiseThreeTo = makeExponentialFunction(3);
    raiseThreeTo(2); // 9
    • 일반적으로 함수의 클로저는 다음 두가지를 포함한다.

      • 모든 함수 매개변수(예제의 params, params2)
      • (전역 변수를 포함해서) 바깥 스코프에 위치한 모든 변수, additionalVars 함수 이후에 선언된 변수를들도 포함된다.
    • 클로저는 다음과 같은 상황에서 유용하게 사용할 수 있다.

      • 프라이빗 변수처럼 사용할 때
      • 서버 측 비동기 호출할 때
      • 가상의 블록 스코프 변수를 생성해야 할 때
  • 스코프

    • 전역 스코프

      • 가장 단순하며, 가장 나쁜 스코프
      • 스크립트 최외곽에 선언된(어느 함수에도 속하지 않은) 객체 및 변수가 자리하며 모든 스크립트 코드가 자유롭게 접근이 가능하다
      • 전역 데이터는 변수 상태가 언제 어떻게 바뀌는지 머릿속에서 따라가야 해서 점점 알 수 없는 프로그램을 만드는 부작용을 초래한다. FP 스타일로 개발할 땐 여하한 경우에도 전역 변수는 사용하면 안된다.
    • 함수 스코프

      • 함수 내부에 선언된 변수는 모두 해당 함수의 지역 변수라서 다른 곳에서는 안 보이고, 함수가 반환되는 시점에 이들은 모두 사라진다.
      • 변수를 이름으로 찾는 것은 제일 안쪽 스코프에서 바깥쪽 방향으로 체크해 나가는데 정리하면 다음처럼 동작한다.
      • 변수의 함수 스코프를 체크한다.
      • 지역 스코프에 없으면 자신을 감싼 바깥쪽 어휘 스코프로 이동해서 전역 스코프에 도달 할 때까지 변수 레퍼런스를 계속 찾는다.
      • 그래도 변수가 참조하는 대상이 없으면 undefined를 반환한다.
    • 의사 블록 스코프

      • 표준 ES5 자바스크립트는 for, while, if, switch처럼 제어 구조를 중괄호 {}로 깜싼 블록 수준의 스코프를 지원하지 않는다. 단 catch 블록에 전달된 error 변수는 예외이다.
      • 자바스크립트 함수 스코프는 블록 안에 선언된 변수는 함수 어디서건 접근이 가능하다.
      function doWork() {
      if (!myVar) {
        var myVar = 10;   // 만약 var를 let, const로 변경할 경우 myVar is not defined 에러가 발생!
      }
      console.log(myVar);   // 10
      }
      doWork();
  • 정리

    • 자바스크립트는 OOP와 FP 양쪽 다 가능한 팔방미인 언어이다.
    • OOP에 불변성을 도입하면 함수형 프로그래밍을 멋지게 섞어 쓸 수 있다.
    • 고계/일급 함수는 함수형 자바스크립트를 구사하는 근간이다.
    • 클로저는 정보 감춤, 모듈 개발뿐만 아니라, 여러 자료형에 걸쳐 굵게 나뉜 함수에 원하는 기능을 매개변수로 넘기는 등 다양한 쓰임새를 자랑한다.
Loading script...