함수와 연산자에 전달되는 값은 대부분 적절한 자료형으로 자동 변환됨.
명시적 형 변환: 전달받은 값을 의도를 갖고 원하는 타입으로 변환하는 경우.
alert 메서드는 매개변수로 문자형을 받기 때문에 자동 변환된다.
String(value) 함수를 호출해 전달받은 값을 명시해서 변환할 수도 있다.
let value = true;
alert(typeof value); // boolean
value = String(value); // 변수 value엔 문자열 "true"가 저장됩니다.
alert(typeof value); // string
숫자형이 아닌 값에 / 나누기를 적용한 경우,
Number(value) 함수를 사용한 경우에도 명시해서 변환할 수 있다.
alert( "6" / "2" ); // 3, 문자열이 숫자형으로 자동변환된 후 연산이 수행됩니다.
let str = "123";
alert(typeof str); // string
let num = Number(str); // 문자열 "123"이 숫자 123으로 변환됩니다.
alert(typeof num); // number
그러나 숫자 이외의 글자가 들어가 있는 문자열을 숫자형으로 변환하려고 하면, 그 결과는 NaN이 된다.
let age = Number("임의의 문자열 123");
alert(age); // NaN, 형 변환이 실패합니다.
그 외에도 숫자형으로 변환 시 적용되는 규칙을 알아두자.
논리 연산을 수행할 때 발생한다.
Boolean(value)를 호출하면 명시적으로 형 변환을 할 수 있다.
alert( Boolean(1) ); // 숫자 1(true)
alert( Boolean(0) ); // 숫자 0(false)
alert( Boolean("hello") ); // 문자열(true)
alert( Boolean("") ); // 빈 문자열(false)
문자열 "0"은 true이다. 자바스크립트에선 비어있지 않은 문자열은 언제나 true이다.
a % b: a를 b로 나눈 이후에 그 나머지를 정수로 반환해준다.
a**b : a를 b번 곱한 값이 반환된다.
제곱근을 구할 때 사용할 수도 있다.
alert( 4 (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)
이항 연산자 +를 사용ㅎ알 때는 피연산자 중 하나가 문자열이면 다른 하나도 문자열로 변환된다.
덧셈만 오직 문자열 연결과 변환이라는 특별한 기능을 제공한다.
뺄셈과 나눗셈 연산자는 문자형 피연산자를 다르게 다룬다.
alert( 6 - '2' ); // 4, '2'를 숫자로 바꾼 후 연산이 진행됩니다.
alert( '6' / '2' ); // 3, 두 피연산자가 숫자로 바뀐 후 연산이 진행됩니다.
덧셈 연산자 +는 이항 연산자뿐만 아니라 단항 연산자로도 사용이 가능.
단항 덧셈 연산자는 짧은 문법으로도 Number(...)와 동일한 일을 할 수 있게 해준다.
실제로 폼 필드에서 값을 가져올 때 그 값이 문자열인 경우 자주 사용한다.
let apples = "2";
let oranges = "3";
// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화합니다.
alert( +apples + +oranges ); // 5
// `Number(...)`를 사용해서 같은 동작을 하는 코드를 작성할 수 있지만, 더 기네요.
// alert( Number(apples) + Number(oranges) ); // 5
순서를 기억할 필요는 없지만, 동일한 기호의 단항 연산자는 이항 연산자보다 우선순위가 더 높다는 것에 주목하면 된다.
또한 우선순위 숫자가 클수록 먼저 실행된다.
=도 무언가를 할당할 때 쓰이는 연산자이다.
우선순위는 3으로 아주 낮기 때문에 보통 계산이 행하고 할당된다.
자바스크립트에서 대부분의 연산자들은 값을 반환하고, = 역시도 값을 반환한다.
그렇기 때문에 이러한 코드 또한 가능하다.
let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
alert( a ); // 3
alert( c ); // 0
위 예제에서 표현식 (a = b + 1)은 a에 값을 할당하고, 그 값인 3을 반환합니다. 그리고 반환 값은 이어지는 표현식에 사용된다.
할당 연산자는 체이닝 또한 가능하다.
여러 개를 연결할 수 있고, 모든 변수가 단일 값을 같이 공유하게 되는 형태가 가능하다.
*=, += 연산자를 사용하여 짧은 문법으로 연산을 실행할 수 있다. 할당 연산자와 우선 순위가 동일하기 때문에 다른 연산자가 대부분 실행된 이후에 실행된다.
let n = 2;
n += 5; // n은 7이 됩니다(n = n + 5와 동일).
n *= 2; // n은 14가 됩니다(n = n * 2와 동일).
alert( n ); // 14
변수에만 사용할 수 있는 연산자이다. 증가 감소 연산자는 변수 앞이나 뒤에 올 수 있다.
counter++와 같이 피연산자 뒤에 올 때는, '후위형(postfix form)'이라고 부른다.
++counter와 같이 피연산자 앞에 올 때는, '전위형(prefix form)'이라고 부른다.
두 형의 차이는 반환 값을 사용할 때 드러난다.
전위형의 경우에는
let counter = 1;
let a = ++counter; // (*)
alert(a); // 2
후위형의 경우에는
let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈
alert(a); // 1
이렇듯, 반환 값을 사용하지 않는다면 전위형과 후위형에는 차이가 없다.
그러나 값을 증가한 이후 바로 사용하기 위해서는 전위형 증가 연산자를 사용하면 된다.
반대로, 값을 증가시키지만 증가 전의 기존값을 사용하려면 후위형 증가 연산자를 사용하면 된다.
비트 연산자는 개발에서 주로 사용하지 않기 때문에 강의에서 우선 생략되었다.
비교 연산자 역시 값을 반환한다.
값을 불린형으로 true, false 형태로 반환한다.
alert( '2' > 1 ); // true, 문자열 '2'가 숫자 2로 변환된 후 비교가 진행됩니다.
alert( '01' == 1 ); // true, 문자열 '01'이 숫자 1로 변환된 후 비교가 진행됩니다.
0과 false 를 구별하지 못한다.
alert( 0 == false ); // true
빈 문자열일 때도 같은 문제가 발생한다.
alert( '' == false ); // true
형이 다른 피연산자를 비교할 떄 피연산자를 숫자형으로 바꾸기 때문에 발생한다.
빈 문자열, false 는 숫자형으로 변환하면 0이 된다.
그렇기 때문에 일치 연산자를 사용하면 형 변환 없이 값을 비교할 수 있다.
불일치 연산자는 !== 형태로 사용할 수 있다.
몇 가지 규칙을 살펴보자.
alert( null === undefined ); // false
두 값의 자료형이 다르기 때문에 거짓이 반환됨.
alert( null == undefined ); // true
동등 연산자를 사용해 비교하면 특별한 규칙이 적용돼서 true가 반환된다.
이 둘은 묶어서 생각하는 것이 편하다.
그러나 산술 연산자나 기타 비교 연산자를 사용하여 둘을 비교하면 null과 undefined 는 숫자형으로 변환된다.
null은 0, undefined는 NaN으로 변환된다.
alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
null이 숫자형으로 변환되었기 때문에 1은 거짓을, 3은 참을 반환한다.
그러나 동등 연산자 ==는 피연산자가 undefined나 null일 때 형 변환을 하지 않기 때문에 false 를 반환한다. ( undefined 와 null을 비교할 때만 true 를 반환)
alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)
1과 2에서는 undefined가 NaN으로 숫자형으로 변환되지만 NaN이 피연산자인 경우 비교 연산자는 항상 false를 반환한다.
그러나 undefined 는 null이나 undefined 와 같고, 그 외와는 같지 않기 때문에 3은 false를 반환한다.
이 둘은 동등 비교시(==) 서로 같지만 다른 값과는 같지 않다.
null이나 undefined 가 될 확률이 있는 변수가 > 또는 < 의 다른 피연산자로 올 때는 주의해야 한다. 이 둘의 여부를 확인할 수 있는 코드를 따로 두는 것이 좋다.
if(...)문은 괄호 안에 들어가는 조건을 평가, 그 결과가 true면 블록이 실행된다.
조건이 true일 때 복수의 문을 실행하고 싶다면 중괄호로 코드 블록을 감싸야 한다. (웬만하면 가독성을 위해서 감싸는 것이 좋다.)
if (year == 2015) {
alert( "정답입니다!" );
alert( "아주 똑똑하시네요!" );
}
괄호 안의 표현식을 평가하고 그 결과를 불린값으려 변환한다.
if(0)은 그렇기 때문에 절대 실행되지 않고, if(1)은 항상 실행된다.
else 뒤에 이어지는 코드 블록은 조건이 거짓일 때 실행된다.
let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');
if (year == 2015) {
alert( '정답입니다!' );
} else {
alert( '오답입니다!' ); // 2015 이외의 값을 입력한 경우
}
유사하지만 약간씩 차이가 있는 조건 여러 개를 처리할 때 사용한다.
let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');
if (year < 2015) {
alert( '숫자를 좀 더 올려보세요.' );
} else if (year > 2015) {
alert( '숫자를 좀 더 내려보세요.' );
} else {
alert( '정답입니다!' );
}
처음부터 차례차례 조건을 확인하며 내려온다.
마지막에 붙는 else 는 필수가 아닌 선택 사항이다.
물음표 연산자(조건부 연산자)는 피연산자가 세 개이기 때문에 삼항 연산자라고도 부른다.
let result = condition ? value1 : value2;
평가대상인 condition이 truthy라면 value1이, 그렇지 않으면 value2가 반환된다.
물음표 연산자는 우선순위가 낮기 때문에 비교 연산자가 실행되고 난 뒤에 실행된다.
// 연산자 우선순위 규칙에 따라, 비교 연산 'age > 18'이 먼저 실행됩니다.
// (조건문을 괄호로 감쌀 필요가 없습니다.)
let accessAllowed = age > 18 ? true : false;
물음표 연산자 ?를 여러 개 연결하면 복수의 조건을 처리할 수 있다.
let age = prompt('나이를 입력해주세요.', 18);
let message = (age < 3) ? '아기야 안녕?' :
(age < 18) ? '안녕!' :
(age < 100) ? '환영합니다!' :
'나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';
alert( message );
이걸 if.. else를 사용하면 아래와 같이 변형할 수 있다.
if (age < 3) {
message = '아기야 안녕?';
} else if (age < 18) {
message = '안녕!';
} else if (age < 100) {
message = '환영합니다!';
} else {
message = '나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';
}
물음표 ?를 if 대용으로 사용하는 경우도 종종 있다.
그러나 가독성이 떨어지기 때문에 코드 길이가 짧아진다고 ?를 대신 쓰는 것은 좋지 않다.
let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');
(company == 'Netscape') ?
alert('정답입니다!') : alert('오답입니다!');
이 코드보다는
let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');
if (company == 'Netscape') {
alert('정답입니다!');
} else {
alert('오답입니다!');
}
이렇게 작성하는 것이 훨씬 눈에 잘 들어온다.
인수 중 하나라도 true이면 true를 반환, 그렇지 않으면 false 를 반환한다.
피연산자가 모두 false인 경우를 제외하고 연산 결과는 항상 true이다.
alert( true || true ); // true
alert( false || true ); // true
alert( true || false ); // true
alert( false || false ); // false
피연산자가 불린형이 아니면, 평가를 위해서 불린형으로 변환된다.
if문에서 보통 사용된다.
if (1 || 0) { // if( true || false ) 와 동일하게 동작합니다.
alert( 'truthy!' );
}
result = value1 || value2 || value3;
AND 연산자는 두 피연산자가 모두가 참일 때 true를 반환.
그 외의 경우에는 false를 반환.
alert( true && true ); // true
alert( false && true ); // false
alert( true && false ); // false
alert( false && false ); // false
OR 연산자와 동일하게 AND 연산자의 피연산자도 타입에 제약이 없다.
result = value1 && value2 && value3;
OR 연산자와 비슷한 알고리즘으로 동작한다.
"정리해 보자면 이렇습니다. AND 연산자는 첫 번째 falsy를 반환합니다. 피연산자에 falsy가 없다면 마지막 값을 반환합니다."
&&의 우선순위가 ||보다 높습니다.
if를 ||나 &&로 대체하지 마세요.
!를 사용해서 만들 수 있다.
not 연산자는 인수를 하나만 받는다.
NOT을 두 개 연달아 사용하면 불린형으로 변환할 수 있다.
여러 피연산 중 그 값이 확정되어있는 변수를 찾을 수 있다.
최근에 추가된 문법이기 때문에 구식 브라우저는 폴리필이 필요하다.
a ?? b의 평가 결과는 다음과 같다.
nullish 병합 연산자 없이 동일한 동작을 하는 코드를 작성하게 된다면 이렇게 길어진다.
x = (a !== null && a !== undefined) ? a : b;
둘은 비슷해보여도 다른 차이점이 존재한다.
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
||는 height에 0을 할당했지만 0을 falsy 한 값으로 취급했기 때문에 null이나 undefined 를 할당한 것과 동일하게 처리한다.
반면에 ??는 height가 정확하게 null이나 undefined 일 경우에만 100이 된다. 0을 할당했기 때문에 0을 반환한다.
??의 연산자 우선순위는 대다수의 연산자보다 낮고 ?와 =보다는 높다.
괄호 없이 ??를 ||나 &&와 함께 사용하는 것은 아직 금지되어 있다.