본문은 JavaScript 언어에 대한 이해를 높이기 위해 "You Don't Know JS(카일 심슨 저)"를 읽고 공부한 내용을 정리한 글입니다. 공부가 목적이기 때문에 필요에 따라 생략이나 수정, 추가된 부분이 있을 수 있습니다.
1. 문과 표현식
const a = 3 * 6;
const b = a;
b;
1) 3 * 6, a, b -> 표현식
2) const a = 3 * 6, const b = a -> 선언문(Declaration Statetment)
3) a = 3 * 6, b = a -> 할당 표현식(Assignment Expression)
모든 문은 완료 값(Completion Value)을 가진다. 이는 브라우저 개발자 콘솔 창에서 쉽게 확인할 수 있다. 콘솔 창은 가장 최근에 실행된 문의 완료 값을 기본적으로 출력한다. 아래의 결과를 통해 블록은 내부의 가장 마지막 문/표현식의 완료 값으로 반환한다는 사실을 알 수 있다.

2. 레이블
// bar() 함수는 앞에서 정의되었다.
{
foo: bar()
}
다음과 같은 형태로 레이블 문(Labled Statement)을 정의할 수 있다. 이는 중첩된 for문에서 continue와 break문과 함께 사용하여 흐름을 좀 더 원활하게 제어할 수 있다.
let cnt = 0
// 'foo' 레이블 루프
foo: for (let i =0; i<4; i++) {
console.log(`외부: ${i}`)
for (let j=0; j<4; j++) {
cnt++;
console.log(`내부: ${j}, cnt: ${cnt}`)
if (cnt > 8) {
break foo
}
}
}
console.log(`foo 탈출`);
외부: 0
내부: 0, cnt: 1
내부: 1, cnt: 2
내부: 2, cnt: 3
내부: 3, cnt: 4
외부: 1
내부: 0, cnt: 5
내부: 1, cnt: 6
내부: 2, cnt: 7
내부: 3, cnt: 8
외부: 2
내부: 0, cnt: 9
foo 탈출
3. 단락 평가
&&, || 연산자는 단락 평가(short circuiting)의 특성을 지닌다. &&, || 연산자의 경우 좌측 피연산자의 평가 결과만으로 전체 결과가 이미 결정될 경우 우측 피연산자의 평가를 건너뛴다. 이렇게 가능한 한 빨리 지름길을 택한다는 의미에서 단락(Short Circuited)라는 말이 유래됐다.
예를 들어 a && b에서 a가 falsy면 b를 신경 쓰지 않고, 반대로 a || b에서 a가 truthy면 b를 신경 쓰지 않는다.
'falsy'란?
불리언으로 강제변환하면 false가 되는 값
- undefined
- null
- false
- +0, -0, NaN
- ""
'truthy'란?
falsy를 제외한 나머지
이러한 특성을 다음과 같이 유용하게 사용할 수 있다.
1) && 연산에서 좌측 피연산자를 일종의 '가드'로 사용함으로써 에러를 피할 수 있다.
- 만약 opts가 undefined인 상태에서 cool이라는 프로퍼티에 접근하려 한다면 에러가 발생할 것이다.
- 여기서 opts를 먼저 체크한다. undefined는 falsy한 값이므로 우측 피연산자에 접근하지 않는다.
function doSomething(opts) {
if (opts && opts.cool) {
...
}
}
2) || 연산에서 좌측 피연산자를 먼저 체크해서 True라면 굳이 우측 피연산자에 접근하지 않는다. 따라서 불필요한 작업이 줄어든다.
- opts.cache가 true라면 primeCache()라는 함수를 호출하지 않는다.
function doSomething(opts) {
if (opts.cache || primeCache()) {
...
}
}
4. 세미콜론 자동 삽입
ASI(Automatic Semicolon Insertion, 자동 세미콜론 삽입)은 자바스크립트 엔진에 내장된 '파서 에러 감지 시스템'으로 필요한 세미콜론이 코드에서 누락된 경우 파서 에러가 나면 자동으로 삽입해보고 실행에 문제가 없도록 도와준다.
개발자마다 세미콜론을 쓸 지 안 쓸 지에 대한 의견은 분분하지만(가독성 vs 원칙), 필자는 세미콜론을 쓰는 편을 주장하고 있다.
5. 에러
자바스크립트 에러는 크게 '조기 에러'와 '런타임 에러'로 분류된다.
- 조기 에러(Early Error): 컴파일러가 던진 잡을 수 없는 에러
- 런타임 에러(Runtime Error): try~catch로 잡을 수 있는 에러
모든 구문 에러는 프로그램을 실행 전 중단시키는 조기 에러가 분명하지만, 다른 유형의 에러들도 있다.
6. 함수 인자
arguments 배열의 사용을 자제하되, 꼭 사용해야 할 경우 argumetns의 원소와 이에 대응하는 명명된 인자를 사용하지 말 것을 주의해야 한다. 되도록이면 ES6부터 지원되는 Rest 인자를 사용하자!
Rest 파라미터 - JavaScript | MDN
Rest 파라미터 구문은 정해지지 않은 수(an indefinite number, 부정수) 인수를 배열로 나타낼 수 있게 합니다.
developer.mozilla.org
7. try ~ finally
try(또는 try~catch)에 붙는 finally절에는 실행 처리 순서 면에서 다소 복잡하며, 특히 레이블 블록과 함께 사용할 때 그 혼란은 가중된다. 따라서 사용에 주의해야 한다.
function foo () {
try {
return 42;
} finally {
console.log("Hi");
}
}
console.log(foo());
// Hi
// 42
foo();
// Hi
return 42에서 foo( ) 함수의 완료 값은 42로 세팅되고, try 절의 실행이 종료되면서 곧 바로 finally 절로 넘어간다. 그 후 foo( ) 함수 전체의 실행이 끝나고 완료 값은 호출부 console.log( ) 문에 반환된다. 다음과 같은 흐름이다.
foo 함수 호출 -> try절 실행 -> 완료 값 42로 세팅(return 42) -> finally절 실행 -> 리턴 값 반환
throw, continue, break도 return과 유사하게 작동한다.
또한, finally절에서 명시적으로 작성된 return은 그 이전의 실행된 try나 catch절의 return을 덮어쓰기 때문에 그 사용에 있어 주의해야 한다.
function foo() {
try {
return "return by try";
} finally {
return "return by finally";
}
}
console.log(foo()); // return by finally
'프로그래밍 언어 > JavaScript + TypeScript' 카테고리의 다른 글
[You Don't Know JS] 6. 호이스팅(Hoisting) (0) | 2021.07.03 |
---|---|
[You Don't Know JS] 5. 스코프(Scope) (0) | 2021.07.02 |
[You Don't Know JS] 3. 네이티브(Native) (0) | 2021.06.24 |
[스크랩] JavaScript(ES6), TypeScript, Node.js 개발자를 위한 무료 e북 4가지 (0) | 2021.06.22 |
[You Don't Know JS] 2. 값(Value) (0) | 2021.06.22 |
본문은 JavaScript 언어에 대한 이해를 높이기 위해 "You Don't Know JS(카일 심슨 저)"를 읽고 공부한 내용을 정리한 글입니다. 공부가 목적이기 때문에 필요에 따라 생략이나 수정, 추가된 부분이 있을 수 있습니다.
1. 문과 표현식
const a = 3 * 6;
const b = a;
b;
1) 3 * 6, a, b -> 표현식
2) const a = 3 * 6, const b = a -> 선언문(Declaration Statetment)
3) a = 3 * 6, b = a -> 할당 표현식(Assignment Expression)
모든 문은 완료 값(Completion Value)을 가진다. 이는 브라우저 개발자 콘솔 창에서 쉽게 확인할 수 있다. 콘솔 창은 가장 최근에 실행된 문의 완료 값을 기본적으로 출력한다. 아래의 결과를 통해 블록은 내부의 가장 마지막 문/표현식의 완료 값으로 반환한다는 사실을 알 수 있다.

2. 레이블
// bar() 함수는 앞에서 정의되었다.
{
foo: bar()
}
다음과 같은 형태로 레이블 문(Labled Statement)을 정의할 수 있다. 이는 중첩된 for문에서 continue와 break문과 함께 사용하여 흐름을 좀 더 원활하게 제어할 수 있다.
let cnt = 0
// 'foo' 레이블 루프
foo: for (let i =0; i<4; i++) {
console.log(`외부: ${i}`)
for (let j=0; j<4; j++) {
cnt++;
console.log(`내부: ${j}, cnt: ${cnt}`)
if (cnt > 8) {
break foo
}
}
}
console.log(`foo 탈출`);
외부: 0
내부: 0, cnt: 1
내부: 1, cnt: 2
내부: 2, cnt: 3
내부: 3, cnt: 4
외부: 1
내부: 0, cnt: 5
내부: 1, cnt: 6
내부: 2, cnt: 7
내부: 3, cnt: 8
외부: 2
내부: 0, cnt: 9
foo 탈출
3. 단락 평가
&&, || 연산자는 단락 평가(short circuiting)의 특성을 지닌다. &&, || 연산자의 경우 좌측 피연산자의 평가 결과만으로 전체 결과가 이미 결정될 경우 우측 피연산자의 평가를 건너뛴다. 이렇게 가능한 한 빨리 지름길을 택한다는 의미에서 단락(Short Circuited)라는 말이 유래됐다.
예를 들어 a && b에서 a가 falsy면 b를 신경 쓰지 않고, 반대로 a || b에서 a가 truthy면 b를 신경 쓰지 않는다.
'falsy'란?
불리언으로 강제변환하면 false가 되는 값
- undefined
- null
- false
- +0, -0, NaN
- ""
'truthy'란?
falsy를 제외한 나머지
이러한 특성을 다음과 같이 유용하게 사용할 수 있다.
1) && 연산에서 좌측 피연산자를 일종의 '가드'로 사용함으로써 에러를 피할 수 있다.
- 만약 opts가 undefined인 상태에서 cool이라는 프로퍼티에 접근하려 한다면 에러가 발생할 것이다.
- 여기서 opts를 먼저 체크한다. undefined는 falsy한 값이므로 우측 피연산자에 접근하지 않는다.
function doSomething(opts) {
if (opts && opts.cool) {
...
}
}
2) || 연산에서 좌측 피연산자를 먼저 체크해서 True라면 굳이 우측 피연산자에 접근하지 않는다. 따라서 불필요한 작업이 줄어든다.
- opts.cache가 true라면 primeCache()라는 함수를 호출하지 않는다.
function doSomething(opts) {
if (opts.cache || primeCache()) {
...
}
}
4. 세미콜론 자동 삽입
ASI(Automatic Semicolon Insertion, 자동 세미콜론 삽입)은 자바스크립트 엔진에 내장된 '파서 에러 감지 시스템'으로 필요한 세미콜론이 코드에서 누락된 경우 파서 에러가 나면 자동으로 삽입해보고 실행에 문제가 없도록 도와준다.
개발자마다 세미콜론을 쓸 지 안 쓸 지에 대한 의견은 분분하지만(가독성 vs 원칙), 필자는 세미콜론을 쓰는 편을 주장하고 있다.
5. 에러
자바스크립트 에러는 크게 '조기 에러'와 '런타임 에러'로 분류된다.
- 조기 에러(Early Error): 컴파일러가 던진 잡을 수 없는 에러
- 런타임 에러(Runtime Error): try~catch로 잡을 수 있는 에러
모든 구문 에러는 프로그램을 실행 전 중단시키는 조기 에러가 분명하지만, 다른 유형의 에러들도 있다.
6. 함수 인자
arguments 배열의 사용을 자제하되, 꼭 사용해야 할 경우 argumetns의 원소와 이에 대응하는 명명된 인자를 사용하지 말 것을 주의해야 한다. 되도록이면 ES6부터 지원되는 Rest 인자를 사용하자!
Rest 파라미터 - JavaScript | MDN
Rest 파라미터 구문은 정해지지 않은 수(an indefinite number, 부정수) 인수를 배열로 나타낼 수 있게 합니다.
developer.mozilla.org
7. try ~ finally
try(또는 try~catch)에 붙는 finally절에는 실행 처리 순서 면에서 다소 복잡하며, 특히 레이블 블록과 함께 사용할 때 그 혼란은 가중된다. 따라서 사용에 주의해야 한다.
function foo () {
try {
return 42;
} finally {
console.log("Hi");
}
}
console.log(foo());
// Hi
// 42
foo();
// Hi
return 42에서 foo( ) 함수의 완료 값은 42로 세팅되고, try 절의 실행이 종료되면서 곧 바로 finally 절로 넘어간다. 그 후 foo( ) 함수 전체의 실행이 끝나고 완료 값은 호출부 console.log( ) 문에 반환된다. 다음과 같은 흐름이다.
foo 함수 호출 -> try절 실행 -> 완료 값 42로 세팅(return 42) -> finally절 실행 -> 리턴 값 반환
throw, continue, break도 return과 유사하게 작동한다.
또한, finally절에서 명시적으로 작성된 return은 그 이전의 실행된 try나 catch절의 return을 덮어쓰기 때문에 그 사용에 있어 주의해야 한다.
function foo() {
try {
return "return by try";
} finally {
return "return by finally";
}
}
console.log(foo()); // return by finally
'프로그래밍 언어 > JavaScript + TypeScript' 카테고리의 다른 글
[You Don't Know JS] 6. 호이스팅(Hoisting) (0) | 2021.07.03 |
---|---|
[You Don't Know JS] 5. 스코프(Scope) (0) | 2021.07.02 |
[You Don't Know JS] 3. 네이티브(Native) (0) | 2021.06.24 |
[스크랩] JavaScript(ES6), TypeScript, Node.js 개발자를 위한 무료 e북 4가지 (0) | 2021.06.22 |
[You Don't Know JS] 2. 값(Value) (0) | 2021.06.22 |