08 - 조건문
8.2 조건문
If 문의 조건식이 불리언 값이 아니면 암묵적으로 불리언 값으로 강제 변환된다는 것을 알게 되었다.
Switch문에 대해서 논의하고 싶었던 것이 있음.!
Switch 문을 적용하지 않았을 때 - 20줄
Switch 문을 적용한 사례 - 30줄
8.3 반복문
for (;;) { ... }
로 for 문 무한루프가 가능하다는 것을 알게됨. 잘 쓸 것 같지는 않다..
While True가 무한루프 표현에 더 직관적이지 않을까 싶다.
8.4 break 문
레이블 문에 대해 알게 되었다.
outer: for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (i + j === 3) break outer;
console.log(`inner [${i}, ${j}]`);
}
}
console.log('Done!');
GOTO 문의 역할을 한다! 하지만 남용할 경우 GOTO 문의 단점처럼 코드가 난잡해진다는 단점이 존재한다.
09 - 타입 변환과 단축 평가
9.2 암묵적 타입 변환
표현식 평가 시 개발자의 의도와 무관하게 문맥을 해석해 암묵적 타입 변환을 할 때가 있다! → 이 케이스들을 잘 숙지하고 있어야 예기치 않은 상황의 발생을 피할 수 있겠다 싶었습니다.
1 + '2' -> "12"
1 - '1' -> 0
1 * '10' -> 10
1 / 'one' -> NaN
if ('') console.log('1');
if (true) console.log('2');
if (0) console.log('3');
if ('str') console.log('4');
if (null) console.log('5');
9.4 단축 평가
단축 평가를 활용한 null / undefined 체크와 초기화 로직 사례를 잘 봐놓는 것이 좋겠다.
개인적으로 단축 평가를 그렇게 잘 사용하지 않는 것 같다.
논리 연산자 && 사용시 0이나 ‘’은 객체로 평가될 수 있다는 것도 흥미로웠다.
var str = '';
var length = str && str.length;
console.log(length); -> ''. 길이를 참조하지 못함.
상황에 따라 적절한 연산자를 사용할 줄 알아야겠다.
이건 습관적인 부분이라 노력이 필요할듯 😭
10 - 객체 리터럴
10.2 객체 리터럴에 의한 객체 생성
var person = {
name: 'Lee',
sayHello: function () {
console.log(`Hello! My name is ${this.name}.`);
},
};
10.3 프로퍼티
var person = {
firstName: 'Daejin', // 네이밍 규칙을 준수.
'last-name': 'Lee', // 네이밍 규칙을 준수하지 않아 따옴표를 사용.
};
네이밍 규칙을 준수하지 않으면 실제로 차이가 발생하는 것을 확인하게 되어 인상깊었다.
10.5 프로퍼티 접근
var person = {
name: 'Lee',
};
console.log(person.name);
console.log(person['name']);
대괄호 접근법에 대해 알게되었다.
(하지만 그렇게 매력적으로 보이진 않는다.. 굳이?)
var person = {
'last-name': 'Lee',
1: 10,
};
person.last - name; // -> 브라우저 환경: NaN
// -> Node.js 환경: RefrenceError: name is not defined
위 예제에서 person.last-name
의 실행 결과가 Node.js 환경과 브라우저 환경에서 다르다.
위 표현식을 평가할 때 JS엔진은..
person.last
를 평가 → undefinedperson.last-name
→undefined - name
name
식별자 찾음.
Node.js 환경에서는 name 식별자의 선언을 찾을 수 없으므로 레퍼런스 에러가 발생한다.
하지만 브라우저 환경에서는 전역 객체 window의 프로퍼티인 전역 변수 name이 존재한다.
기본적으로 이것은 빈 문자열이다.
따라서 person.last-name
은 undefined-''
와 같으므로 NaN이 된다.
11 - 원시 값과 객체의 비교
JS 데이터 타입을 원시 타입과 객체 타입으로 나눈 이유와 그에 관련된 부분들을 심도 있게 다뤘다.
11.1 원시 값
변수와 값의 분리
→ 연장해서 상수와 변경 불가능한 값의 차이
→ 상수는 재할당이 금지된 변수
위 맥락을 통해 용어의 엄밀한 정의를 다시 짚고 넘어갔다.
그리고 원시 값의 불변성에 관한 이야기
- 재할당 시 메모리 주소가 변경되는 이유
- 불변하지 않다면 값의 변경 사항, 즉 상태 변경을 추적하기 어려워진다.
그리고 “값의 의한 전달”도 사실 값이 아니라 메모리 주소를 전달한다는 것을 다시 짚어주는 것도 좋았다.
11.2 객체
JS의 객체 관리 방식도 알아놓기 좋을 것 같다.
→ 프로퍼티 키를 인덱스로 쓰는 해시 테이블
“값에 의한 전달”과 “참조에 의한 전달”은 식별자가 기억하는 메모리 공간에 저장되어 있는 값을 복사해서 전달한다는 면에서 동일하다.
다만 변수에 저장된 값이 원시 값이냐 참조 값이냐의 차이만 있을 뿐이다.
따라서 자바스크립트에는 “참조에 의한 전달”은 존재하지 않고 “값에 의한 전달”만이 존재한다.
JS에는 포인터가 없기 때문에 포인터가 존재하는 타 언어의 “참조에 의한 전달”과 의미가 정확히 일치하지 않는다는 점도 짚고 넘어갈 만 했다.
12 - 함수
12.4 함수 정의
각 함수 정의 내부 동작 차이에 대해 기억할 필요가 있다.
이렇게 여러 정의가 나뉘어진 건 함수가 일급 객체이기 때문이지 않을까 싶다.
12.4.1 함수 선언문
함수 선언문은 표현식이 아닌 문으로써, 변수에 할당할 수 없다. 그러므로 아래 코드는 작동할 수 없어야 한다.
var add = function add(x, y) {
return x + y;
};
console.log(add(2, 5)); // 7
하지만 동작하는 이유는 JS 엔진은 함수 이름이 있는 함수 리터럴을 단독 사용하면 함수 선언문으로 해석하고, 함수 리터럴이 값으로 평가되어야 하는 문맥이면 함수 리터럴 표현식으로 해석하기 때문이다.
function foo() {
console.log('foo');
}
(function bar() {
console.log('bar');
});
foo(); // foo
bar(); // ReferenceError: bar is not defined
함수명은 함수 몸체 내에서만 존재할 수 있는 식별자이다.
그렇다면 어떻게 foo를 호출할 수 있었을까?
foo는 함수 객체를 가리키는 식별자여야 한다.
foo는 JS 엔진이 암묵적으로 생성한 식별자이다.
JS 엔진은 생성된 함수를 호출하기 위해 함수명과 동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당한다.
12.4.2 함수 표현식
함수 리터럴로 생성한 함수 객체를 변수에 할당하는 정의 방식을 함수 표현식이라고 한다.
어차피 변수에 할당되기에 함수명은 생략 가능하며(이것이 일반적이다), 이러한 함수를 익명 함수라고 한다.
// 기명 함수 표현식
var add = function foo(x, y) {
return x + y;
};
console.log(add(2, 5)); // 7
console.log(foo(2, 5)); // ReferenceError
그럼 결과적으로 JS 엔진은 함수 선언문을 함수 표현식으로 변환하여 함수 객체를 생성하니, 함수 선언식 == 함수 표현식인가? 그렇지 않다.
함수의 생성 시점이 다르다.
12.4.3 함수 생성 시점과 함수 호이스팅
console.dir(add);
console.dir(sub);
console.log(add(2, 5));
console.log(sub(2, 5));
function add(x, y) {
return x + y;
}
var sub = function (x, y) {
return x - y;
};
함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 JS 고유의 특징을 함수 호이스팅이라 한다.
변수 할당문의 값은 런타임에 평가되므로 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다. 즉 함수 표현식으로 함수를 정의하면 함수 호이스팅이 아닌 변수 호이스팅이 발생한다.
함수 호이스팅은 함수 호출 전 꼭 함수를 선언해야 한다는 규칙을 무시한다.
이런 문제로 함수 선언문 대신 함수 표현식을 사용할 것을 권장한다.
12.5 함수 호출
함수 호출 시 몸체 내에서 암묵적으로 매개변수가 생성되고 일반 변수처럼 undefined로 초기화된 후 인수가 순서대로 할당된다. → 내부 동작을 알게되어 좋았다!
그리고 매개변수 개수 - 인수 개수 맞는지 체크 안한다는 점.
- 인수가 부족한 경우 할당되지 않은 것들 undefined.
- 인수가 초과된 경우 arguments 객체 프로퍼티로 보관.
function add(x, y) {
console.log(x, y);
return x + y;
}
console.log(add(2)); // NaN
console.log(add(2, 5, 10)); // 7
12.6 참고에 의한 전달과 외부 상태의 변경
함수로 전달받은 객체를 변경하면 부수 효과가 발생한다.
이는 상태 변화를 추적하기 어려워지게 만든다.
이런 외부 상태를 변경하지 않고 외부 상태에 의존하지 않는 함수를 순수 함수라고 하며, 이를 통해 부수 효과를 최대한 억제하여 프로그램 안정성을 높이려는 패러다임을 함수형 프로그래밍이라고 한다.
→ 함수형 프로그래밍이 뭔지 정확히 몰랐는데, 엄밀한 정의를 알게 되어 좋았다.
12.7 다양한 함수의 형태
12.7.4 콜백 함수
함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라고 하며, 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 한다.
고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.
고차 함수는 매개변수를 통해 전달받은 콜백 함수의 호출 시점을 결정하여 호출한다. 즉, 콜백 함수는 고차 함수에 의해 호출되며 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
12.7.5 순수 함수와 비순수 함수
함수형 프로그래밍에서는 부수 효과가 없는 함수를 순수 함수, 부수 효과가 있는 함수를 비순수 함수라고 한다.
함수형 프로그래밍은 순수 함수 + 보조 함수의 조합으로 부수 효과를 최소화해 불변성을 지향하는 프로그래밍 패러다임이다.
→ 콜백 함수와 고차 함수의 관련성을 다룬 부분이 좋았다.
그리고 슬슬 함수형 프로그래밍에 대해 다루는 것 같아 기대가 된다. 😀
'모던자바스크립트-DeepDive' 카테고리의 다른 글
13 ~ 15 챕터 (0) | 2024.07.24 |
---|---|
04 ~ 07 챕터 (3) | 2024.07.24 |