CodeSpitz77 2회_Flow control statement (1)

CodeSpitz77 2회_Flow control statement (1)

목차

🌕🌑🌑

코드스피츠 강의 정리록


복습

Flow란?
우리가 짠 파일메모리에 적재되고,
적재된 순간, 명령과 데이터로 나눠져서 적재된 다음에
명령이 쭉 한꺼번에 실행되는데,
명령이 차근차근 실행되는 과정.



0. Record, Completion Record

자바스크립트 언어의 기본적인 문처리 기법을 알아보자.


0.1 Record

자바스크립트는 문을 처리할때 식과 다르게 처리한다.
식은 하나의 값으로 처리될 뿐이지만,
문은 실행단위로 처리된다.
문을 10개 쓰면, 10개의 실행단위가 생각난다.
(식은 10개 써도, 값 하나로 수렴될 뿐이다.)
문의 갯수를 늘리면, 자바스크립트 엔진은 갯수만큼을 처리해야할 과제로 알고 있다.
한줄한줄의 문이 생길때 마다 과제로 등록해 놓는다.
=> Record

우리가 일반적으로 을 짜면 Record 하나하나로 번역이 된다.
자바스크립트 엔진은 우리가 짠 코드를 파싱할때 들을 Record단위로 파싱한다.
Record가 하나하나 생성이되면 flow를 타고 쭉 움직인다.

Record를 만들고
Record를 실행하는 과정이
자바스크립트 엔진의 주 작동원리이다.

요즘 현대 브라우저들은 자바스크립트 3.1엔진에서 돌지 않는다.
(인사이드 자바스크립트나 자바스크립트를 말하다와 같은 책들은 좋지만, 작동원리는 현대 브라우저와 다르다. (3.1버전 엔진기준으로 설명된 책))
모든 항목에 있어서 브라우저들이 해석하는 방식이 달라졌다. 스펙문서도 달라짐.
자바스크립트 엔진의 작동원리를 지금 버전에서 배워도, 매년 스펙이 갱신되기 때문에 내가 알고 있던 지식이 다음해에는 무의미해질 수 있다.
기저층의 작동원리보다는
무엇을 의미하고 추상적인 의미는 무엇인지 체계를 배우는 것이 더 의미있다..
= 작동원리보다는 근본적인 부분을 배우자.

  • 자바스크립트 엔진에서 Record를 부르는 말은 굉장히 많다. 언어의 버전마다 다르다

정리

  • 우리가 문을 작성하면 문을 하나의 Record로 바꿔준다는 것.
  • 자바스크립트는 이런 Record를 모아서 Record를 처리해가면서 작동한다는 사실만 알면 된다.

0.2 Flow Control Statement, Completion record

if문이라서 분기를 할 수 있다던지, loop구분이라서 계속 flow를 돌릴 수 있는
flow 제어를 하면 레코드를 선택하거나 레코드를 순환시킬 수 있는 권한을 갖게 된다.

flow 제어를 할 수 있는 문을 record로 바꿀때는
Completion record로 바뀐다.
completion record은 record를 뭘 선택할 수 있는지 flow에 관여할 수 있다.

자바스크립트 엔진은 우리가 작성한 문을
Record와 Completion record로 나누고,
Completion record들이 어떤 레코드를 선택할지 결정하는데 사용한다.

  • 문은 컴파일러에게 주는 힌트일 뿐이라고 했었다.
  • if나 for문을 쓰면 값으로 환원되지 않고
    Completion record가 어떻게 작동할지를 자바스크립트에게 알려주는 힌트가 될 뿐.
  • 자바스크립트는 그 힌트를 받아서 내부적으로 이런 flow 흐름도를 만드는
    completion record를 생성하게 된다.

정리

  1. 우리가 짜는 문 하나하나가 flow를 구성한다.
  2. flow control하는 문들은 별도로 구성한다.


1. Direct flow control

직접 flow control하는 명령어를 배워보자.

1.1 label

자바스크립트에서 사용할 수 있는 직접 flow control에는 label이 있다.

  • 다중 for문을 사용했을 때 바깥쪽 for문으로 빠져나오고 싶으면, break를 사용하면 된다.

1.1.1 Identifier (= 식별자)

자바스크립트 변수 identifier
A JavaScript identifier must start with
a letter, underscore (_), or dollar sign ($);
subsequent characters can also be digits (0-9). Because JavaScript is case sensitive, letters include the characters “A” through “Z” (uppercase) and the characters “a” through “z” (lowercase). (참고)

  • $를 시작할수도, 포함할 수도없다. 나머지는 변수 식별자 규칙과 같다.
  • 뒤에 :를 붙여주는 순간 label이 된다.

1.1.2 Scope

  • label의 이름은 같은 범위(scope)내에서 2개가 나올 수 없다.
  • 런타임에 오류가 잡히지 않고
    파싱하는 타임에 오류가 난다.
    • 에러를 사전에 잡을 수 있는 장점이 있다.

Label의 scope?

  • label의 scope는 함수로 결정된다.
  • label scope라는 개념이 있다.
    • label scope도 shadowing이 일어난다.
1
2
3
4
5
6
7
<script>
abc: {
console.log("start");
if (true) break;
console.log("end");
}
</script>

Uncaught SyntaxError: Illegal break statement

1
2
3
4
5
6
7
8
<script>
abc: {
console.log("start");
if (true) break abc;
console.log("end");
}
console.log("test");
</script>

start
test

  • break뒤에 명시된 label 스코프의 마지막으로 jump할 수 있다는 의미이다.
    => flow 수동 제어에 성공
  • label 스코프를 생성하게 되면
    label 스코프 내에서는 label을 빠져나올 수 있는 권리가 주어진다.
    • loop가 아니라서 continue는 사용하지 못하지만 break는 사용할 수 있다.
  • 가장 원초적인 flow control
  • 이 방법을 통해서 label 섹션을 만들면 label 섹션에서 flow control이 가능하다.

label 영역이 아닌곳도 될까?
label 영역이 아는곳에서 되게 하려면 label 영역을 나눠줘야한다.


1.1.3 Label range

  • label range를 인식하려면 label set을 인식할 수 있어야한다.
  • 어떻게 해서 label이 label영역을 확보하는지 알아야 한다.
  1. 이 label에서 다음 label까지가 하나의 label range를 이룬다.
  2. label다음에
    iteration이 오거나,
    switch가 오면 이것들이 다시 label 범위를 한정짓게 된다.
1
2
3
4
5
6
<script>
console.log("0");
abc: if (true) break abc;
console.log("1");
bbb: console.log("2");
</script>

0
1
2

  • label range로 확정했지만, jump하지 못했다.
  • goto처럼 건너뛰려면
    label 스코프를 선언하던지,
    iteration label이 되던지,
    switch label이 되던지 해야지 jump할 수 있다.
  • 자바스크립트에는 goto 구문이 없다는 것에 주의.
    break나 continue에서만 레이블을 사용할 수 있다.
    • 직접 레이블을 선택해서 goto는 안되고
      break, continue로 아래로 내려가는 것만 가능하다.
  • 왔다갔다 할 수 없다. label만 갖고 loop문을 만들 수 없다.
  • 반복적인 실행만 할 수 없을 뿐 jump시킬 수 있다.
  • if문에서는 break 문 뒤에 label을 작성해야하는데,
    while이나 for문에서는 label을 명시적으로 쓰지않고 break문만 쓸 수 있는 이유는 무엇일까
1
2
3
4
5
6
<script>
for (var i = 0; i < 10; i++) {
if (i === 5) break;
}
console.log("end");
</script>

왜 error가 아닐까?


1.1.4 Auto label

1
2
3
4
5
6
7
<script>
temp38:
for (var i = 0; i < 10; i++) {
if (i === 5) break temp38;
}
console.log("end");
</script>
  • 자바스크립트 엔진이 우리 대신에 label을 삽입해준 셈. = auto label
    • iteration(for문)이나 switch문 앞에서 발동된다.
  • auto label이 만들어낸 이름 undefined named label
    (위 예시의 temp38같은)
cf__1 주석을 깨끗하게 쓰고 싶다면?
  • 앞주석을 쓰기 위해서 앞에 쓰기도 한다.
  • 오픈소스에 이렇게 쓰여있는 경우가 많다.
1
2
3
ab: console.log('123')
cd: console.log('123')
dc: console.log('123')

1.1.5 label은 호출됐을 때 처음으로가나요?

jump구문은 jump가 시작하는 문장 블럭의 가장 처음으로 가게 되어있다.

  • for문이 루프돌면, 가장 처음으로 간다.
  • 함수 호출하면 가장 처음으로 간다.
    하지만 break의 label를 본다면.. 처음으로 가야하는 거 아닌가??
    • break의 label은 블럭의 마지막으로 보낸다.

자바스크립트의 label 스펙은 자바의 label 스펙과 동일히다
레이블은 자바스크립트의 3.1버전때부터 있었던 스펙


1.2 Switch

switch의 문법적 요소를 확인해보자.

  • switch라는 키워드가 나오고
  • 괄호가 나오고
  • 괄호 안에 식이들어갈 수 있고,
  • 중괄호가 나온다.
    • for문 다음에 괄호는 단문이 나올 수 있고 중문이 나올 수 있는데, 중문때문에 중괄호를 쓴다.
    • switch문은 그럴 수 없다. 무조건 중괄호가 나와야한다.
    • 문법적인 토큰이라는 뜻이다.
    • switch의 몸체를 나타내는 전용 토큰.
      • 언어 파서가 해석하기 위한 토큰으로서의 중괄호이다.
    • 왜 중괄호를 쓸까.
      switch는 중괄호의 영역을 특별한 영역으로 만든다.
      special label block으로 만든다.
      1. case
      2. 콜론 :

1.2.1 Special label Block

switch는 특별한 레이블 영역을 사용할 수 있는 공간을 만들어주는 문법이라고 생각해도 된다.

  • label과 완전히 일치하다.
  • 컴파일타임에 해석되는 정적인 레이블을 만드는 것이 아니라
    case 안의 식을 동적으로 해석할 수 있는 특수한 레이블로 만들었을 뿐이다.
  • switch는 case와 default label만 사용하도록 한다.

우리는 switch 괄호안에 있는 값의 평가된 것을
런타임에 평가해서
case에 있는 값과 일치하는 label로 보낼 수 있는
특수한 레이블 구문을 만들 수 있는 switch문이라는 것을 알 수 있다.

그 안에 있는 label은 우리가 알고 있는 label과 동일하게 작동한다.

1.2.2 Fall Through

case문 안에서 break를 안쓰면 그 다음 case문이 실행되는 현상

  • break를 걸면, undefined name label로 빠져나오게 된다.
  • switch문 앞에 auto label을 만든다.

1.2.3 Auto Label

1
2
3
4
5
6
7
8
9
10
<script>
switch (true) {
default:
console.log("c");
case true:
console.log("0");
case false:
console.log("1");
}
</script>

언어마다 스페셜 label block 해석 방식이 다르다.

  • 자바스크립트에서는 switch의 스페셜 label block을 위에서 아래로 처리한다.
  • 자바나 c같은 언어는 switch를 쓸때 해석하는 방식이 자바스크립트와 다르다.
1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
temp17:
switch (true) {
default:
console.log("c");
case true:
console.log("0");
break temp17;
case false:
console.log("1");
}
console.log("end");
</script>
  • 자바스크립트 엔진이 break문 뒤에 auto label을 붙여준다고 생각하면 된다.
  • auto label이 발생되는 지점은
    iteration(for문)이나 switch문 앞에서 발동된다.

1.2.4 Runtime switch

자바스크립트에 case문은 runtime에 해석을 한다.

  • runtime에 해석하는 기능때문에 자바스크립트를 2가지 방식으로 switch문을 쓸 수 있게 만든다.
  1. 값에 대한 routing으로 (mini router)
    특정 값에 대한 routing table
  2. 조건 평가에 대한 분기

값에 대한 routing이 정적인 경우 값에 대한 routing에 더 우선순위가 높다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
// 1. mini router
var a = true;
switch (a) {
default:
console.log("c");
case true:
console.log("0");
break;
case false:
console.log("1");
}
console.log("end");

// 2. 조건 평가에 대한 분기
// 디자인패턴 chianable responsibility 패턴
switch (true){
case network() === 'online':
case network() === 'wifi':
case network() === 'offline':
case localcache():
default: // 안내문..
}
</script>

1.2.5 Reverse case

switch구문이 runtime에 해석된다는 것은 뭐냐?
한줄씩 순차적으로 실행된다.

  • switch문을 라우터로 사용하지 않거나, 라우터로 사용하더라도 함수가 개입되거나, 증감현상처럼 상태를 바꾸는 코드가 들어가면 항상 주의해서 써야한다.
  • runtime에서 switch를 해석하는 모든 언어에서 발생한다.
    • python, ruby, javaScript
    • 유의깊에 사용하지 않으면 문제를 일으킨다.
📚