Truthy/Falsy 연산
if("" == 0) console.log("hello")
는 출력이 될까 안될까? 된다. (빈문자열, 0은 둘다 false로 간주. 즉, 빈 문자열은 falsy한 값이다.)
let x;
console.log(1 < x); //false
console.log(x < 3); //false
if(1 < x < 3) console.log("hi") //hi
위의 코드에서는 x < 3
마저도 false
가 출력되고, 1 < x < 3
이 연산되는 기묘한 현상이 일어난다.
비교 연산자는 undefined
랑 연산을 할때, NaN
으로 간주되어 무조건 false
를 반환한다.
그렇다면, null
은 어떨까? null
은 놀랍게도 0
으로 간주된다.
이는 Javascript
의 타입변환(Type Coercion)
규칙 중 하나이다. 이러한 암묵적 형변환 때문에 실제 개발에서는 가능한 명시적인 비교나 타입 체크를 하는 것이 권장되는 것이다.
1 < x < 3
은 놀랍게도 참으로 간주된다. 이는 순차적으로 연산이 되기 때문이다. 1 < x
는 false를 반환, false는 0으로 간주되므로 false < 3
은 true가 되어 hi가 출력되는 것이다.
Truthy값
Falsy값
0n은 BigInt의 자료형이다.
단락 회로 평가
OR 연산자
먼저 참이 오는 값을 반환한다.
true || true
false || true
true || false
false || (3 == 4)
위의 코드는 당연히 true, true, true, false
순으로 값이 반환될 것이다.
하지만, "Cat" || "Dog"
-> Cat이 반환됨.
이는 OR연산자는 참값을 뱉어내는것이 아니라, 먼저 오는 참인 값을 반환하는 것이기 때문이다. 둘다 거짓인 경우에는, 뒤의 값이 반환된다.
"Cat" || "Dog" // "Cat"
"Cat" || false // "Cat"
false || "Cat" // "Cat"
"" || false // false
false || "" // ""
false || varObject // varObject
const result = null || 0 || undefined || "" || " " || 2 || "hello";
// result는 " "가 반환됨.
이를 활용한 간단한 예시
let input = prompt("값을 입력하세요")
let result = parseInt(input) || 10;
result += 2
입력값이 존재하지 않거나 숫자가 아니라면 기본값이 12가 된다.
AND 연산자
true && true
false && true
true && false
false && (3 == 4)
위의 코드는 당연히 true, false, false, false
가 반환된다.
하지만, "Cat" && "Dog"
-> Dog가 반환됨.
이는 AND 연산자는 먼저 오는 falsy인 값을 반환하기 때문에, 앞단이 true라면 뒤의 값도 검사해봐야하기 때문에 Dog가 반환된다.
false가 먼저 오고 true가 나중에 온다면, falsy의 값이 반환될 것이다.
false && "Cat"
"Cat" && false
"" && false
false && ""
false && varObject
const result = "a" && 3 && "undefined" && 0 && " " && 2;
// result는 0를 반환
이처럼, 단락회로 평가를 이용하면 불필요한 중첩 조건문을 간결하게 만들어줄 수 있다. 아래는 x의 형식이 string형식이며, 숫자형식의 문자열이고 30을 넘지 않는지 검사하는 코드이다.
//Before
if(typeof x = "string"){
if(!isNaN(x)){
if(parseInt(x) < 30){
console.log("통과")
}
}
}
//After
let valid = typeof x === "string" && !isNaN(x) && parseInt(x) < 30;
연산자들 간의 우선순위도 존재한다. 예를들어, &&는 | 보다 우선적으로 처리됨. |
const result = true || false && false
true가 반환 const result = (true || false) && false
false가 반환
기본값 설정하는 법
1. OR 연산자를 사용하는 방법
let name = null || "default string" //기본값으로 항상 default string을 반환
OR 연산자는 모든 falsy한 값에 대해 기본값을 적용하게 된다.
2. 널 병합 연산자를 사용하는 방법
좌항이 null/undefined일 경우, 우항을 반환하는 연산자. 이외의 경우는 좌항을 반환함.
let foo = null ?? "default string" //기본값으로 항상 default string을 반환
let baz = 0 ?? 42 // 0
널병합 연산자를 사용할때 유의할 점은, 오직 좌항이 null/undefined의 자료형일때만 우항을 반환하며, false나 기타 falsy값이어도 좌항을 반환한다.
숫자 산술 연산
3 + "3" // 33
3 * "3" // 9
3 + "a" // NaN
3 * "a" // NaN
NaN은 Not a Number의 약자
특정 값이NaN
인지 Infinity
인지 확인하는 방법은 한가지 밖에 없다. isNaN(), isFinite()
함수를 통해 비교 확인 가능
전개연산자
전개연산자는 배열이나 객체를 펼치는 연산자이다. 배열/객체 내의 요소들을 펼치는 역할을 한다.
const array = [1, 2, 3, 4, 5];
const result = [...array];
console.log(result) //[1, 2, 3, 4, 5]
전개연산자는 어디에 쓰이냐에 따라 다른 역할을 한다.
- 배열 복사
얕은 복사를 할때 사용한다. (참조타입까지는 연결이 끊어지지 않는다.)
//원시 타입은 연결이 끊어진다.
const original = [1, 2, 3];
const copy = [...original];
// 배열 자체는 별개의 인스턴스
console.log(original === copy); // false
// 최상위 요소 변경은 서로 영향 없음
copy[0] = 100;
console.log(original[0]); // 1 (변경되지 않음)
console.log(copy[0]); // 100
//but, 참조타입은 연결이 끊어지지 않는다.
const original = [1, {name: 'John'}, [3, 4]];
const copy = [...original];
// 참조 타입 요소 변경은 서로 영향을 미침
copy[1].name = 'Jane';
copy[2][0] = 99;
console.log(original[1].name); // 'Jane' (변경됨)
console.log(original[2][0]); // 99 (변경됨)
깊은 복사에 대한 내용은 여기에서 더 자세히 확인해볼 수 있다.
- 배열 결합
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const result = [...array1, ...array2];
console.log(result) //[1, 2, 3, 4, 5, 6]
- 객체 복사
const obj = {a: 1, b: 2, c: 3};
const result = {...obj};
console.log(result) //{a: 1, b: 2, c: 3}
- 객체 결합
const obj1 = {a: 1, b: 2};
const obj2 = {c: 3, d: 4};
const result = {...obj1, ...obj2};
console.log(result) //{a: 1, b: 2, c: 3, d: 4}
- 함수 매개변수로 사용되면, 명칭과 사용법이 달라진다.