본문 바로가기
SK Planet ASAC

JavaScript 함수형 프로그래밍 패러다임 ~ 스코프 체인

 

함수형 프로그래밍 패러다임

자바스크립트는 함수형 프로그래밍 패러다임을 추구하며, 객체지향 프로그래밍 패러다임도 지원한다. 

자바스크립트의 핵심은 함수와 객체다. 클래스와 객체를 활용할 수 있으며, TS를 통해 인터페이스(다형성)을 도입할 수 있다.  때문에 JS 개발을 위해서는 함수형 프로그래밍에 대한 이해가 필요한데

(컴포넌트를 만들다보면 함수로 만들면 매우 좋은 것 같긴하다. 클래스로 만들면 중구난방 this로 인해 헷갈리게 될지도... hook을 함수로 만드는 것도 같은 의미 아닐까.)

 

함수형 프로그래밍은 2가지 조건을 만족하는 것을 의미한다. 

 

1. 일급 함수: 함수 변수 + 함수 파라미터 + 함수 반환

함수 변수 할당 = 함수 표현식 

var expression = function() {
	console.log("hello");
}
expression();

 

2. 함수 파라미터 

var array = [1,2,3,4,5]
var parameter = element => {
	return element * 10
}

var calcarray = array.map(parameter);
console.log(calcarray)

 

3. 함수 반환

function returnValue(unit){
	return parameter => {
    	console.log(unit * parameter)
    }
}

 

 

2. 순수함수

일정 값(파라미터)을 넣으면, 일정한 값(반환값)이 나오며, 프로그램의 어느것도 건들지 않는다.

 

1. 참조 투명성(Referentially Transparent: 함수가 외부 상태에 의존하지 않는다

Inconsistent Reuslts 비일관 결과: 같은 파라미터에 다른 값 

var c= 3
fuction sideEffect_a(a,b){
	console.log(a+b+c)
}
sideEffect_a(1,2)
var c = 5
sideEffect_a(1,2)

c값이 바뀌어도 함수가 의존하지 않는다.

 

2. 부수 효과 없음 (No side-Effects): 함수가 외부 상태를 변경하지 않는다

만약 아래와 같은 상황이 있다고 가정하자.

var object = {name: "kim", age:10}
function sideEffect_b() {
	object.name = "seo"
}
sideEffect_b()
console.log(obejct)

sideEffect_b 함수는 외부 상태를 변경하고 있다. 만약 어떤 개발자가 자신의 의도대로 외부 객체를 변경하면 어느 누군가는 의도치 않게 변경된 객체를 사용하게 된다. 

 

이를 위해 불변 객체(Immutability)를 이용할 수 있다. 복습을 위한 포스팅이니 잘 기억나지 않는다면 이 곳

우리는 보통 object라는 변수가 객체를 가리키는 주소값을 갖는다는 것을 알고 있다. 그러나 단순하게 object 변수만을 복사해서 사용하게 되면, (JS의 특성)에 의해 새로운 변수 또한 object가 저장되어 있는 곳을 가리키게 된다. 

즉, 새로운 변수의 프로퍼티를 바꾸면 object 또한 바뀌게 된다. 그러니까... 같은 곳을 바라보는거다.

 

얕은 복사는 1계층만 복사함을 말한다. 

var object = {
	name: "kim",
    address: {
    	location: "seoul"
    }
}

var copy = Objet.assign({}, object) //address의 location 계속 같은 곳을 참조한다

 

객체 안에 객체가 있다면 그 객체까지도 복사를 해야한다. 이것을 재귀적으로 호출해서 해결할 수 있다. 

단순하게 해당 프로퍼티가 객체면 다시 복사 함수를 호출해서 return 받는 것이고, 그렇지 않다면 name과 같이 똑같이 복사해서 새로운 (주소를 참조하는) 변수를 만들게 되는것이다. 이를 깊은 복사라함.

하지만 좀 더 쉬운 방법이 있는데, Stringify하여 Object를 -> String으로 만들었다가 다시 역으로 String -> Object로 변환하면 됨! 

 

(순수함수에 이어서)

Thread-safe를 할 수 있다는 특징이 있는데, 병렬적으로 수행되는 모든 함수들은 서로에게 영향을 주어선 안 되고, 외부의 값을 변경해서도 안 된다. 때문에 멀티 스레드를 활용한 개발 시 순수함수의 특성이 매우 중요하다. 

순수 함수에 대한 내용 이 포스팅

 

 

 

자바스크립트의 변수, 함수 정의 및 사용 

변수

ECMSScript 6 (2015) 이전에는 var 하나의 방법으로만 선언했다. 6 이후부터 let과 const로 선언할 수 있다. 

let: 가변 변수 선언 시  

const: 불변 변수 선언 시

var와 const는 호이스팅이 발생한다.

 

스코프 

1. 함수 스코프

함수가 생성 시 스코프 영역이 생겨난다. 

2. 블록 스코프

블록이 생성될 때 스코프 ({}로 엮어진다)

 

 

자바스크립트 엔진의 수행 방식 

자바스크립트 엔진은 언어를 실행하는 것이다. 때문에 자바스크립트 파일을 실행한다고 생각하지만, 사실 함수를 실행하고 파일은 main 함수인 격이다. 

그래서 자바스크립트의 파일 구동 방식은 함수 구동 방식과 동일하다. 자바스크립트 함수 구동 방식은 간단히 2단계로 나누어 진행된다. 

1. Creation(Pre-parsing)Phase: 실행에 앞서 어떤 변수와 함수가 정의되어 있는지 먼저 분석
2. Excecution Phase: 변수에 값을 할당하고 함수를 실행

 

함수 실행을 위한 메모리 영역은 실행 컨텍스트와 렉시컬 환경이다. 

Stack: 실행 컨텍스트와 같으며 함수 실행 환경이다.

Heap: 렉시컬 환경(Lexical Envrionment)는 변수와 함수의 저장소다. 

 

실행 컨텍스트 

프로그램에 메모리와 CPU 자원을 할당한 뒤 구동하면 프로세스라고 한다. 

모든 함수의 구동은 그 함수 구동을 위한 메모리 영역을 확보하는 것에서부터 시작한다. 이 때 이 메모리 영역을 실행 컨텍스트라고 한다. 

다시, 실행 컨텍스트 = Lexical Envrionment + Variable Envrionment

 

다시 JS 엔진 실행 단계로 돌아가서,

 

1. Creation(Pre-parsing) Phase: 함수(파일) 분석하여 메모리 내 변수, 함수 적재 

메모리(실행 컨텍스트와 Lexical Envrionment) 내 변수와 함수 적재 

 

2. Execution Phase: 함수 실행을 위한 메모리 영역 확보 및 실행 

함수 실행을 하기 위해 실행 컨텍스트와 Lexical Environmnt를 확보 후에 실행한다. 

(add)let 같은 경우는 1단계에서 선언되지 않고 2단계에서 선언과 할당이 동시에 이뤄진다. 

 

Lexical Scope와 Scope Chain, Hoisiting

Lexical(Static) Scope: 함수 호출 시점에서의 스코프가 아닌 함수 선언 시점에서의 스코프 = 박제

Scope Chain: Execution Phase 시 변수 선언이 안 되어 있을 때, 호출 순서로 이전 실행 컨텍스트에서 검색한다. 

var name = 'zero';
function log() {
  console.log(name);
}

function wrapper() {
  name = 'nero'; 
  log();
}
wrapper();

위와 같은 예제는 아래와 같이 호이스팅 된다. 위에서 부터 읽어 내려가면, name은 zero로 할당되고 시작했지만 wrapper에서 nero로 할당했으므로 출력은 nero다.

var name; 

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

function wrapper(){
  name = "nero"
  log();
}
name = "zero"


wrapper();

 

Scope Chain

Execution Phase 시 변수 선언이 안 되어 있을 때, 호출 순서로 이전 실행 컨텍스트에서 검색한다. 

Global Execution Context(전역 컨텍스트)까지 다 찾아봐도 없으면 그 자리에 var 선언 및 할당한다. 

현재 Context는 자신이 선언된 시점의 Lexical Envrionment만 참조할 수 있어서 가장 가까운 요소부터 차례대로 접근할 수 있고 다른 순서로 접근하는 것이 불가능하다. 만약 여러 스코프에서 같은 변수를 선언한 경우 무조건 스코프 체인 상 가장 가까운 스코프의 변수를 참조한다.