JS가 발전함에 다라 언어 설계자들은 초기(ES5 이전) 버전의 결함을 수정하려 했으나, 하위 호환성 유지 문제로 인해 결함이 심각하더라도 제거할 수 없는 구식 기능이 있었다.
때문에 ES5 이후 버전에서는 초기 버전의 실수를 대부분 해결한 스트릭트 모드를 사용할 수 있다.
객체 프로퍼티나 배열 요소에 접근하기 위해 사용한 .
이나 []
도 표현식이다.
표현식은 값을 계산할 뿐 프로그램의 상태를 어떤 형태로든 바구지 않는다.
문은 값을 갖지는 않지만 프로그램의 상태를 바꾼다.
JS는 두 번째 행을 첫 번째 행의 연속이라고 분석할 수 없을 경우 줄바꿈을 세미콜론으로 해석한다.
하지만 세 가지 예외가 있는데 그 중 첫번째는 return
, throw
, yield
, break
, continue
문과 관련이 있다.
이들은 독립적으로 사용될 수 있기 때문에 이 뒤에 줄바꿈이 일어난다면 줄바꿈을 세미콜론으로 해석해버린다.
즉 아래와 같이 돼버린다.
return;
true;
따라서 이들 뒤에 특정 표현식을 작성한다면 그 사이에 줄바꿈이 일어나면 안된다.
두 번째 예외로는 ++
과 --
가 있다. 이들은 전위 연산자, 후위 연산자로 사용할 수 있는데, 이들을 후위 연산자로 사용한다면 반드시 적용할 표현식과 같은 행에 써야한다.
세 번째 예외로는 화살표 함수이다.
=>
는 반드시 매개변수 리스트와 같은 행에 있어야 한다.
JS에서 string
, number
, boolean
, Symbol
, null
, undefined
이외에는 모두 객체이다. (null
도 typeof
연산자에서는 object
로 취급하긴 한다.)
객체는 객체 타입의 멤버이며 프로퍼티의 집합이다.
Set
객체는 값의 집합이고, Map
객체는 키와 값의 연결이다.
JS에서 함수와 클래스는 그저 문법의 일부분이라고 볼 수는 없다.(이 점이 다른 정적 언어와의 차이점이다.)
JS의 함수와 클래스는 그 자체가 값이므로 프로그램에서 조작할 수 있다.
기본 값이 아닌 다른 값과 마찬가지로 함수와 클래스도 특별한 객체이다.
JS의 객체 타입은 mutable
하며 기본 타입은 immutable
하다.
JS는 값의 타입을 자유롭게 변환한다.
예를 들어 프로그램에서 문자열이 와야 할 곳에 숫자를 쓰면 JS는 자동으로 그 숫자를 문자열로 변환한다.
전역 함수 isNaN
은 인자가 NaN
이거나 숫자가 아니면서 숫자로 변환할 수도 없는 값일 때 true
를 반환한다.
Number
메서드 isNaN
은 인자가 NaN
일때만 true
를 반환한다.
JS를 비롯해 최신 프로그래밍 언어에서 사용하는 IEEE 754 부동 소수점 표현
은 이진 표현이기 때문에 1/2
, 1/8
, 1/1024
같은 분수는 정확하게 표현할 수 있으나 1/10
, 1/100
같은 숫자는 정확하게 표현하지 못한다.
때문에 JS는 1/10
을 이에 근사한 값으로 표현하는데 이는 가까울 뿐 완전히 정확한 것은 아니기 때문에 문제가 생길 수 있다.
let x = 0.3 - 0.2; // 0.3 - 0.2 = 0.1
let y = 0.2 - 0.1; // 0.2 - 0.1 = 0.1
x === y; // false???
x === 0.1; // false???
y === 0.1; // true???
반올림 오류로 인해 0.3
과 0.2
의 차이의 근삿값은 0.2
와 0.1
의 차이의 근삿값과 같지 않다.
부동 소수점 근삿값으로 인해 프로그램에 문제가 생긴다면 이를 정수로 변환하는 것을 고려해야 한다.
const
를 써야 할 때const
키워드의 사용에 대해 재밌는 두 가지 의견이 있어 정리해보았다.
const
를 써야한다.const
로 선언한 다음 실제로 값을 바꿔야 한다고 인식했을 때 let
으로 바꾼다.이 책의 필자는 전자를 따른다고 하나, 나는 후자를 따른다.
두 의견모두 변수를 변수처럼 사용하자는 의견은 동일한 것 같다.
왜냐면 1
번 경우는 변수로서 사용되는 변수는 변수로 상수로서 사용되는 변수는 상수로 작성하는 것이 옳다라는 측면이고
2
번 경우는 실제로 변수로서 사용되는 경우만 변수로 하고 실제 값이 변하지 않는다면 상수로 취급하는 것이 옳다라는 측면이기 때문에 사실 둘 다 변수와 상수의 개념은 흐리지 않았다.
다만 나의 경우 변수로서 사용되는지 여부로 판단하는 것이 가독성, 코드 예측성 측면에서 더 유리하다고 판단했기 때문에 후자를 따른다.
- 표현식: 값으로 평가되는 문
- 연산자: 피연산자(보통 두개)의 값을 특정 형태로 조합해 새 값으로 평가하는 문(?)
- expression
.identifier
: 마침표 접근법- expression
[expression]
: 대괄호 접근법
- expression
?.identifier
- expression
?[expression]
일반적인 프로퍼티 접근 표현식을 쓸 때 접근법 좌변에 있는 표현식이 null
이나 undefined
일 경우 TypeError
가 발생한다.
하지만 옵셔널 체이닝 연산자(?.
, ?[]
)를 사용하면 좌변이 null
이나 undefined
일 때 ?
뒤의 표현식을 실행하지 않고 좌변 값을 반환한다.
null
병합 연산자
- expression
??
expression
??
는 ||
와 비슷하게 동작하지만 ||
는 좌변 값이 falsy
할 경우에 우변을 평가하고 ??
는 좌변 값이 null
이거나 undefined
일때만 우변을 평가한다.
===
)일치 연산자는 피연산자를 먼저 평가한 다음, 두 값을 아래와 같이 비교화되, 타입 변환은 수행하지 않는다.
null
| undefined
이어야만 같은 값이다.(null
=== null
, undefined
=== undefined
)NaN
이면 같은 값이 아니다(NaN
은 자기 자신을 포함해 어떤 값과도 같지 않다.)