개발철학&개발용어

화살표 함수와 람다식, 어디서 왔을까 - 1930년대 수학에서 JavaScript까지

화살표 함수와 람다식, 어디서 왔을까 - 1930년대 수학에서 JavaScript까지

 

JavaScript 화살표 함수와 람다식은 이제 프론트엔드, 백엔드 가릴 것 없이 매일 쓰는 문법이 됐습니다. 그런데 이 => 기호가 사실은 컴퓨터가 세상에 나오기도 전, 90년 전 수학에서 출발했다는 걸 아는 분은 생각보다 많지 않습니다. 이 글은 람다라는 개념이 어디서 시작해 어떻게 JavaScript의 화살표 함수까지 흘러왔는지, 그리고 화살표 함수가 일반 함수와 진짜로 다른 지점이 어디인지 정리한 글입니다.

현업에서 이런 이야기를 자주 듣습니다.

 

 

"화살표 함수, 그냥 function 짧게 쓴 거 아니에요?"
"콜백 안에서 this가 자꾸 undefined 뜨는데 이유를 모르겠어요."
"람다랑 화살표 함수랑 같은 건가요?"
"그럼 그냥 다 화살표로 바꾸면 안 되나요?"

 

 

저도 처음엔 화살표 함수를 그냥 "타이핑 줄여주는 문법" 정도로 봤습니다. 그런데 그 배경을 알고 나니 => 하나가 왜 이렇게 오래 걸려서 언어에 들어왔는지, 왜 어떤 자리에선 쓰면 안 되는지가 훨씬 선명하게 보이더군요. 그래서 이번 글은 문법 요약보다는 "왜 이렇게 생겨먹었나"에 무게를 두려고 합니다.

개발 입문한 지 얼마 안 됐는데 화살표 함수와 일반 함수의 차이가 헷갈리는 분, 혹은 매일 쓰면서도 이게 어디서 왔는지 한 번쯤 궁금했던 분께 도움이 될 겁니다.

📋 목차

  1. 람다는 컴퓨터보다 나이가 많습니다
  2. 수학 기호가 어쩌다 프로그래밍 언어로
  3. 그런데 왜 오랫동안 안 보였을까
  4. 람다가 다시 불려 나온 배경
  5. JavaScript에 화살표 함수가 등장하다
  6. 화살표 함수의 진짜 차이는 문법이 아니라 this
  7. 화살표 함수가 하지 못하는 것들
  8. 언제 쓰고 언제 피해야 할까

1. 람다는 컴퓨터보다 나이가 많습니다

람다의 출발점은 프로그래밍이 아니라 순수 수학입니다. 미국의 수학자 앨런조 처치(Alonzo Church)가 1930년대에 "계산이란 무엇인가"를 형식적으로 정의하려다 만든 체계가 람다 대수(lambda calculus)예요. 재밌는 건 이게 앨런 튜링의 튜링 머신보다 몇 달 앞선다는 점입니다. 우리가 흔히 "컴퓨터의 이론적 기원"으로 튜링을 떠올리지만, 같은 시기에 처치는 기계가 아니라 함수라는 완전히 다른 방향에서 같은 질문에 답하고 있었던 거죠.

처음 만든 체계는 논리적으로 모순이 있다는 게 밝혀졌고(1935년 클레이니-로서 역설), 처치는 1936년에 계산에 필요한 부분만 따로 떼어 다시 발표합니다. 이게 지금 우리가 아는 무타입 람다 대수예요. 나중에 처치와 튜링은 람다 대수와 튜링 머신이 계산 능력 면에서 서로 같다는 걸 증명했고, 이게 그 유명한 처치-튜링 명제입니다.

 

 

📌 핵심


람다 대수의 세계관은 단순합니다.

"모든 것은 함수다." 값도 함수, 값을 다루는 것도 함수.

우리가 지금 JavaScript에서 함수를 변수에 담고, 함수를 인자로 넘기고,

함수에서 함수를 돌려받는 그 모든 행동의 뿌리가 여기 있습니다.

 

2. 수학 기호가 어쩌다 프로그래밍 언어로

람다 대수는 발표되고도 한참 동안 프로그래밍과는 상관없는 수학·논리학의 물건이었습니다. 실제로 프로그래밍 언어와 연결되기 시작한 건 1950년대 후반, 존 매카시(John McCarthy)가 리스프(Lisp)를 만들면서입니다. 매카시는 1958년 MIT에서 인공지능 연구를 위한 언어를 구상하다가, 기호 계산을 다루려면 함수를 값처럼 자유롭게 넘길 수 있어야 한다는 걸 깨닫습니다.

이때 함수를 표기할 방법이 필요했는데, 매카시가 가져다 쓴 게 처치의 람다 표기법이었습니다. 여기서 개인적으로 좋아하는 일화가 하나 있어요. 매카시는 나중에 회고하길, 처치의 책에서 람다 표기법만 빌려 왔을 뿐 나머지 내용은 잘 이해하지 못했다고 합니다. 이론 전체를 완벽히 파악해서 옮긴 게 아니라, 필요한 도구만 실용적으로 집어 온 셈이죠. 그런데도 훗날 리스프 구현이 람다 대수와 놀랄 만큼 가까웠다는 게 이 이야기의 묘미입니다.

이렇게 lambda라는 키워드가 리스프에 자리 잡으면서, 수학 기호였던 람다는 처음으로 "코드에서 실제로 실행되는 것"이 됩니다. 리스프가 최초의 함수형 언어로 불리는 이유이기도 하고요.

3. 그런데 왜 오랫동안 안 보였을까

여기서 한 가지 의문이 생깁니다. 1950년대에 이미 리스프가 함수를 값처럼 다뤘는데, 왜 람다는 2010년대가 되어서야 주류 언어들에 우르르 들어왔을까요?

이유는 여러 가지가 얽혀 있습니다. 오랫동안 산업 현장을 지배한 건 절차형과 객체지향 패러다임이었습니다. C, C++, 초기 Java가 세운 세계관에서는 "데이터와 그 데이터를 다루는 메서드를 클래스로 묶는다"가 기본이었고, 함수를 값처럼 떠돌게 만드는 사고방식은 낯설고 심지어 위험해 보이기도 했어요. 하드웨어 사정도 있었습니다. 함수를 계속 만들고 넘기는 방식은 그 시절 성능 관점에서 부담이었고요.

그래서 함수형과 람다는 학계나 특정 언어(리스프 계열, 하스켈 등)의 영역에 오래 머물렀습니다. 현업 개발자 입장에서는 "그런 게 있다더라" 정도로 들리던 시절이 꽤 길었죠.

4. 람다가 다시 불려 나온 배경

흐름을 바꾼 건 두 가지 변화였다고 봅니다.

하나는 멀티코어입니다. 클럭 속도만 올리던 시대가 끝나고 코어를 늘리는 방향으로 가면서, 여러 작업을 안전하게 병렬로 돌리는 게 중요해졌어요. 상태를 함부로 바꾸지 않는 함수형 스타일이 이 지점에서 다시 주목받습니다.

다른 하나는, 특히 JavaScript 쪽에서 절박했던 문제인데 - 콜백입니다. 비동기가 일상이 되면서 함수를 인자로 넘기는 일이 폭발적으로 늘었어요. 저도 2012년 무렵 jQuery로 작업할 때 Ajax 콜백을 몇 겹씩 중첩시켜 놓고 나중에 그 코드를 다시 읽다가 한숨 쉰 적이 많습니다. 그 시절엔 콜백 하나 넘길 때마다 function(){ ... }를 길게 늘어놓아야 했으니까요.

 

 

💡 정리


람다가 부활한 건 어떤 언어가 "혁신을 하겠다"고 결심해서가 아니라,

콜백과 병렬 처리라는 현실 문제가 함수를 값처럼 가볍게 다루는 문법을 필요로 했기 때문입니다.

필요가 먼저였고 문법은 그 뒤를 따라온 셈이죠.

 

5. JavaScript에 화살표 함수가 등장하다

이런 흐름 속에서 2015년, ECMAScript 2015(흔히 ES6라고 부르는) 사양이 화살표 함수를 정식으로 들여옵니다. function 키워드 없이 => 기호로 함수를 쓰는 그 문법이요.

// ES5 방식
var double = function (x) {
  return x * 2;
};

// ES6 화살표 함수
const double = (x) => x * 2;

 

람다는 특정 언어만의 것이 아니라 시대의 흐름이었기 때문에, 비슷한 시기에 여러 언어가 저마다의 형태로 람다를 받아들였습니다. 아래는 대략적인 도입 시점입니다.

언어 / 체계 시점 형태
람다 대수 1936 수학 표기 λx.x
Lisp 1958~ lambda 키워드
Python 1990년대~ lambda 식
JavaScript 2015 (ES6) 화살표 함수 =>

표에서 JavaScript는 오히려 늦은 축입니다. 그만큼 필요가 무르익은 뒤에 들어왔다고 볼 수도 있고요.

6. 화살표 함수의 진짜 차이는 문법이 아니라 this

많은 분이 화살표 함수를 "짧게 쓰는 함수"로만 기억하는데, 사실 문법 길이는 곁가지에 가깝습니다. 진짜 차이는 this를 다루는 방식이에요.

일반 함수는 호출되는 방식에 따라 this가 그때그때 달라집니다. 화살표 함수는 자기만의 this를 아예 만들지 않고, 자신이 정의된 바깥 스코프에서 this를 그대로 물려받습니다. 이걸 렉시컬(lexical) this라고 부릅니다.

왜 이게 중요한지는 옛날 코드를 보면 바로 와닿습니다. ES6 이전에는 콜백 안에서 바깥 this를 쓰려고 이런 패턴을 흔히 썼어요.

// ES5: this를 변수에 담아 두고 콜백에서 꺼내 쓰기
function Timer() {
  var self = this;
  self.count = 0;
  setInterval(function () {
    self.count++; // this 대신 self를 써야 했음
  }, 1000);
}

 

var self = this;는 그 시절 거의 관용구였습니다. var that = this;라고 쓰는 사람도 있었고요. 콜백 안에서 this가 엉뚱한 걸 가리키니까, 바깥 this를 미리 다른 이름에 저장해 둔 겁니다. 처음 배울 때 이게 왜 필요한지 이해가 안 돼서 한동안 그냥 외워서 썼던 기억이 나네요.

화살표 함수는 이 문제를 문법 차원에서 정리합니다.

// ES6: 화살표 함수는 바깥 this를 그대로 사용
function Timer() {
  this.count = 0;
  setInterval(() => {
    this.count++; // 바깥 this를 그대로 물려받음
  }, 1000);
}

 

즉 화살표 함수의 등장은 "타이핑을 줄이자"보다 "콜백에서 this 때문에 겪던 고질적인 혼란을 없애자"에 가깝습니다. 짧아진 건 결과일 뿐이고요.

7. 화살표 함수가 하지 못하는 것들

그렇다고 화살표 함수가 일반 함수의 상위 호환은 아닙니다. 자기 this를 안 만든다는 그 성질 때문에, 오히려 쓰면 안 되는 자리가 분명히 있어요. 정리하면 이렇습니다.

항목 일반 함수 화살표 함수
자신의 this 있음 (호출 방식에 따라) 없음 (바깥에서 물려받음)
arguments 객체 있음 없음
생성자(new) 가능 불가 (에러 발생)
객체 메서드 적합 주의 (this가 객체를 안 가리킴)

특히 객체의 메서드를 화살표로 정의하면, 그 this가 객체가 아니라 바깥 스코프를 가리켜서 의도한 대로 동작하지 않는 경우가 많습니다. "화살표가 최신이니까 무조건 화살표" 식으로 접근하면 이 지점에서 발이 걸립니다.

8. 언제 쓰고 언제 피해야 할까

실무 감각으로 정리하면 대략 이렇습니다.

화살표 함수가 잘 맞는 자리 - 콜백 함수, 배열의 map·filter·reduce 같은 고차 함수 인자, 짧게 값 하나 돌려주는 함수, 그리고 바깥 this를 그대로 이어 쓰고 싶은 경우입니다.

일반 함수가 나은 자리 - 객체의 메서드, 생성자로 쓸 함수, arguments 객체가 필요한 경우, 그리고 자기 this가 상황에 따라 달라져야 하는 함수입니다.

 

 

💡 팁


둘 중 뭘 쓸지 고민될 때 저는 "이 함수가 자기만의 this를 가져야 하나?"를 먼저 묻습니다.

가져야 하면 일반 함수, 바깥 걸 그대로 써도 되면 화살표.

이 기준 하나로 대부분의 선택이 정리됩니다.

 

마무리

화살표 함수는 겉으로 보면 function=>로 줄인 문법입니다. 하지만 그 뒤에는 1930년대 처치의 수학, 1958년 매카시의 리스프, 그리고 콜백과 멀티코어라는 현실 문제까지, 거의 한 세기에 걸친 이야기가 깔려 있습니다. 문법을 외우는 것과 이 맥락을 아는 것은 코드를 대하는 태도를 바꿔 놓는다고 봅니다. 적어도 this가 undefined로 뜰 때 당황하는 일은 줄어들 테고요.

물론 여기 정리한 판단 기준이 절대적인 건 아닙니다. 팀의 컨벤션이나 프로젝트 성격에 따라 다를 수 있고, 시간이 더 지나면 또 다른 문법이 이 자리를 대체할지도 모릅니다. 다만 "왜 이렇게 만들어졌나"를 알아 두면, 새 문법이 나와도 그 배경을 짐작하기가 한결 수월해집니다.

❓ 자주 묻는 질문 (FAQ)

Q. 람다식과 화살표 함수는 같은 건가요?
넓게 보면 같은 갈래입니다. 람다는 "이름 없이 함수를 값처럼 쓰는 것"이라는 개념이고, JavaScript에서 그 개념을 구현한 문법이 화살표 함수입니다. 다른 언어에서는 lambda 키워드 등 다른 이름으로 부릅니다.

Q. 화살표 함수는 항상 일반 함수보다 좋은가요?
아닙니다. 자기 this를 만들지 않기 때문에 객체 메서드나 생성자로는 부적합합니다. 콜백이나 짧은 함수에 강점이 있는 것이지 상위 호환은 아닙니다.

Q. 콜백에서 this가 undefined로 뜨는 이유가 뭔가요?
일반 함수 콜백은 호출 방식에 따라 this가 바뀌기 때문입니다. 바깥 this를 그대로 쓰고 싶다면 화살표 함수를 쓰거나, 예전 방식대로 bind를 쓰면 됩니다.

Q. 화살표 함수는 언제부터 쓸 수 있었나요?
2015년 ES6(ECMAScript 2015) 사양부터입니다. 지금(2026년) 기준으로는 사실상 모든 환경에서 문제없이 쓸 수 있습니다.

🎲 개발은전투다 블로그 추천 세트

 

MVVM 패턴, 왜 다들 쓸까? 복잡한 UI와 비즈니스 로직을 분리하는 완벽한 아키텍처

현대의 프론트엔드와 모바일 애플리케이션 개발에서 UI와 비즈니스 로직의 분리는 시스템의 안정성을 좌우하는 필수적인 과제입니다. 복잡해지는 화면 상태를 효과적으로 관리하고 유지보수성

devwar.tistory.com

 

개발 실력 늘리는 법은 함수 암기가 아니었습니다 - 제가 개발 블로그를 시작한 이유

"그 함수들 다 외우면 실력 느는 거죠?""굳이 옛날 얘기까지 알아야 하나요. 쓸 줄만 알면 되잖아요.""새로 나온 기술, 그냥 쓸 줄만 알면 되는 거 아니에요?" 저도 신입 때는 똑같이 생각했습니다.

devwar.tistory.com

 

함수와 클래스는 왜 탄생했을까 - 반복이 귀찮았던 함수, 현실이 복잡했던 클래스

"함수랑 클래스가 뭐가 다른 거예요?" "클래스는 대체 언제 써요?" "함수만으로도 잘 돌아가던데 왜 굳이 클래스를 배워야 하죠?" 프로그래밍을 배우다 보면 함수(Function)와 클래스(Class) 앞에서 누

devwar.tistory.com

 

도메인 주도 설계(DDD), 속도는 빨라지는데 사람은 더 필요해집니다

"DDD요? 결국 폴더 구조 이쁘게 나누는 거 아니에요?""책은 읽었는데, 우리 프로젝트 어디서부터 손대야 할지 모르겠어요.""그거 규모 큰 회사에서나 쓰는 거 아닌가요?""도입했더니 오히려 개발이

devwar.tistory.com

 

TDD(테스트 주도 개발)란 무엇인가 - 테스트를 먼저 쓰는 개발이 나온 이유

TDD, 즉 테스트 주도 개발(Test-Driven Development)은 코드를 먼저 짜고 나중에 테스트하는 방식이 아니라, 테스트를 먼저 작성한 뒤 그 테스트를 통과시키는 코드를 만드는 개발 방식입니다. 이 글에서

devwar.tistory.com

반응형