7. 연산자
in 모던자바스크립트
- 목차
연산자
- 연산자 : 하나 이상의 표현식을 대상으로 산술, 할당, 비교, 논리, 타입, 지수 연산 등을 수행해 하나의 값을 만든다.
- 이때 연산의 대상을 피연산자.
- 피연산자 : 값으로 평가될 수 있는 표현식
// 산술 연산자
5 * 4 // 20
// 문자열 연결 연산자
'hello' + 'world' //helloworld
// 할당 연산자
color = 'red' // 'red'
// 비교 연산자
3 > 5 // false
// 논리 연산자
true && false //false
// 타입 연산자
typeof "hi" // string
- 피연산자 : “값” 이라는 명사 역할. 연산의 대상이 되므로 값으로 평가할 수 있어야 한다.
- 연산자 : 피연산자를 연산한 새로운 값을 만든다. 의 동사 역할
산술 연산자
- 피연산자를 대상으로 수학적 계산을 수행해 새로운 숫자 값을 만든다.
- 산술 연산이 불가능한 경우 NaN 반환
- 피연산자의 개수에 따라 이항 산술 연산자, 단항 산술 연산자로 구분
이항 산술 연산자
- 2개의 피연산자를 산술 연산하여 숫자 값을 만듦
- 모든 이항 산술 연산자는 피연산자의 값을 변경하는 부수 효과(side effect)가 없다.
- 어떤 산술 연산을 해도 피연산자의 값이 바뀌지 않고 새로운 값을 만든다.
단항산술 연산자
- 1개의 피연산자를 산술 연산하여 숫자 값을 만든다.
- ++, — (부수 효과 있음) : 피연산자의 값을 변경
- +, - (부수 효과 없음) : 타입 강제 변환
- : 어떠한 효과도 없다. 음수를 양수로 반전하지도 않는다.
- : 양수를 음수로, 음수를 양수로 반전한 값을 반환한다.
var x = 5, result
// 선할당 후증가
result = x++
// 선증가 후할당
result = ++x
// 선할당 후감소
result = x--
// 선감소 후할당
result = --x
+10 //10
+(-10) // -10
- 숫자 타입이 아닌 피연산자에 + 단항 연산자를 사용하면 피연산자를 숫자 타입으로 변환한다.
- 이때, 피연산자를 변경하는 것이 아닌, 숫자 타입으로 변환한 값을 생성하여 반환한다 (부수효과 x)
// 부수효과 없다
var x = '1'
console.log(typeof +x) //number
console.log(typeof x) //sstring
x = true
console.log(+x) //1
console.log(x) //true
x = "hello"
console.log(+x) //NaN
console.log(x) //hello
-(-10) // 10
-'10' // -10
-true // -1
-'hello' //NaN
문자열 연결 연산자
- 연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작
// 문자열 연결 연산자
1 + "1" // 11
console.log(typeof (1 + "1")) //stirng
// true는 1로 암묵적으로 타입 자동 변환
1 + true // 2
console.log(typeof (1 + true)) //number
// false 는 0 으로 타입 변환
1 + false // 1
// null은 0으로 타입 변환
1 + null // 1
console.log(typeof (1 + null)) //number
// undefined는 숫자로 타입 변환 x
+undefined // NaN
1+undefined // NaN
- 개발자의 의도와 상관없이 js엔진에 의해 암묵적으로 타입이 자동 변환된다. (=== 암묵적 타입 변환, 타입 강제 변환)
할당 연산자
- 우항에 있는 피연산자의 평가 결과를 좌항에 있는 변수에 할당한다.
- 좌항의 변수에 값을 할당하므로 변수 값이 변하는 부수 효과가 있다.
- =, +=, -=, *=, /=, %=
var x
x = 20
console.log(x=20) //20
// 할당문은 표현식인 문!
- 할당문은 값으로 평가되는 표현식인 문으로서 할당된 값으로 평가된다.
var a, b, c;
// 연쇄 할당. 오른쪽 > 왼쪽
a = b = c = 0;
비교 연산자
- 좌항과 우항의 피연산자를 비교한 다음 그 결과를 불리언 값으로 반환
동등/일치 비교 연산자
- 좌항과 우항의 피연산자가 같은 값으로 평가되는지를 비교
- 동등 : 느슨한 비교
- 일치 : 엄격한 비교
- 동등 비교(==)는 좌항과 우항의 피연산자를 비교할 때, 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값인지 비교한다.
- 동등 비교는 예측하기 어려운 결과를 만들어냄 (안티패턴) 따라서 사용 지양
- 일치 비교(===)는 좌항과 우항의 피연산자가 타입도 같고 값도 같은 경우에 한하여 true 반환 (암묵적 타입 변환 x)
console.log(NaN === NaN) //(false) // NaN은 자신과 일치하지 않는 유일한 값
console.log(isNaN(NaN)) //true
console.log(isNaN(10)) //false
console.log(isNaN(1 + undefined)) //true
console.log(0 === -0) //true js의 버그
console.log(0 == -0) //true
- js에는 양의 0과 음의 0 이 있는데 이 둘을 비교하면 true이다.
ES6에 도입된 Object.is 메서드는 예측 가능한 정확한 비교 결과를 반환한다. 그 외에도 일치 비교 연산자(===)와 동일하게 동작
console.log(0 === -0) //true
console.log(Object.is(-0, +0)) //false
console.log(NaN === NaN) //false
console.log(Object.is(NaN, NaN)) //true
대소 관계 비교 연산자
- 피연산자의 크기를 비교하여 불리언 값을 반환
console.log(undefined >= 60) // false
console.log(true >= 60) // false
console.log("hello" >= 60) // false
console.log(null >= 60) // false
삼항 조건 연산자
- 조건식의 평가 결과에 따라 반환할 값을 결정한다.
- js의 유일한 삼항 연산자이며, 부수효과 x
var result = score >= 60 ? 'pass' : 'fail'
// score >= 60 ? 'pass' : 'fail' 은 표현식인 문이다.(값으로 사용될 수 있다.)
if (score >= 60) result = 'pass'
else result = 'fail'
var result = if(x%2) {result='홀수'} else {result='짝수'}
//SyntaxError: Unexpected token 'if'
// if-else 는 표현식이 아닌 문이다.
// if-else는 값처럼 사용될 수 없다.
- 조건식의 평가 결과가 불리언이 아니면, 불리언으로 암묵적 타입 변환된다.
- if-else문과 유사하나, 삼항 조건 연산자 표현식은 값처럼 사용할 수 있지만 if-else 는 x
- if-else는 표현식이 아닌 문이다. 따라서 if-else는 값처럼 사용할 수 없다.
- 삼항 조건 연산자 표현식은 값으로 평가할 수 있는 표현식인 문
- 따라서 값처럼 다른 표현식의 일부가 될 수 있다.
- 조건에 따라 어떤 값을 결정해야 한다면 if-else보다 삼항 조건 연산자 표현식이 더 유리
- 조건에 따라 수행해야할 문이 하나가 아닌 여러개라면 if-else문이 가독성 더 좋다.
논리 연산자
- 우항과 좌항의 피연산자를 논리 연산한다
, &&, ! - 논리 부정 연산자(!) 반환값은 언제나 불리언 값이다.
- 하지만 피연산자가 불리언일 필요는 없다.
// 피연산자가 불리언 값이 아니라면, 암무적 타입 변환된다.
console.log(!0) //true
console.log(!'hello') //false
//console.log(Boolean('hello')) //true
// 단축 평가
console.log('cat' || 'dog') //cat
console.log('cat' && 'dog') //dog
- 논리합, 논리곱의 평가 결과는 불리언이 아닐 수도 있다.
- 논리합, 논리곱은 2개의 피연산자 중 어느 한쪽으로 평가된다. (=== 단축 평가)
논리연산자로 구성된 복잡한 표현식은 가독성이 좋지 않다. 드로므간의 법칙을 활용하여 가독성 올리자 !(x || y) === (!x && !y) !(x && y ) === (!x || !y)
쉼표 연산자
- 왼쪽 피연산자부터 차례대로 피연산자를 평가하고 마지막 피연산자의 평가가 끝나면 마지막 피연산자의 평가 결과를 반환한다.
var x, y, z
x = 1, y = 2, z = 3 // 3
- console.log(x = 1, y = 2, z = 3 )// 1 2 3 ??
그룹 연산자
- 소괄호로 피연산자를 감싸는 그룹 연산자는 자신의 피연산자인 표현식을 가장 먼저 평가한다.
- 연산자의 우선순위를 조절할 수 있다. (연산자 우선순위 가장 높다)
typeof 연산자
- 피연산자의 데이터 타입을 문자열로 반환한다.
- string, number, boolean, undefined, symbol, object, function 중 하나 반환
- null은 반환 x
- 7개의 데이터 타입과 반환값이 정확히 일치하지 않는다.
console.log(typeof null) //object js의 버그
console.log(typeof /test/gi) //object
console.log(typeof function(){}) //function
console.log(typeof "") //string
console.log(typeof undefined) //undefined
console.log(typeof NaN) //number
console.log(null === null) //true
console.log(typeof name) //undefined
// 선언하지 않은 식별자 연산시 RefefenceError가 아닌 undefined
지수 연산자
- ES7 에 도입됨
- 좌항의 피연산자를 밑으로, 우항의 피연산자를 지수로 거듭 제곱하여 숫자 값을 반환
console.log(2 ** 2); //4
console.log(2 ** 2.5); //5.65685424949238
console.log(2 ** 1); //2
console.log(2 ** -2); //0.25
console.log((-5) ** 2); // 25
Math.pow(2, 2);
Math.pow(2, 2.5);
Math.pow(2, 1);
Math.pow(2, -2);
console.log(2 ** (2 ** 2)); //18
Math.pow(Math.pow(2, 2), 2); //16
- 도입 이전에는 Math.pow 메소드 사용.
- 지수 연산자가 가독성이 더 좋다.
- 음수가 좌항일 경우 괄호 묶어야 한다.
// 할당 연산자와 함께 사용할 수 있다.
var num = 5
num **= 2 //(num = num ** 2) //25
// 이항 연산자 중에서 우선순위가 가장 높다.
2 * 5 ** 2 // 2 * (25) = 50
그 외의 연산자
- ?. : 옵셔널 체이닝 연산자
- ?? : null 병합 연산자
- delete : 프로퍼티 삭제
- new : 생성자 함수를 호출할 때 사용하여 인스턴스를 생성
- instanceof : 좌변의 객체가 우변의 생성자 함수와 연결된 인스턴스인지 판별
- in : 프로퍼티 존재 확인
연산자 부수 효과
- 대부분의 연산자는 다른 코드에 영향을 주지 않는다.
- 부수 효과가 있는 연산자는 할당 연산자 (=), 증가/감소 연산자(++, —), delete 연산자
연산자 우선순위
- 여러 개의 연산자로 이뤄진 문이 실행될 때 연산자가 실행되는 순서
- ()
- new (매개변수 존재), , ()(함수호출), ?.(옵셔널 체이닝 연산자)
- new (매개변수 미존재)
- x++, x—
- !x, +x, -x, ++x, —x, typeof, delete
- **
- *, /, %
- +, -
- <, ≤, >, ≥, in, instanceof
- ==. ≠, ===, ≠=
- ?? (null 병합 연산자)
- &&
- ? … : … (삼항 연산자)
- 할당 연산자
,
- 종류가 매우 많으므로 기억에 의존하기보다는 우선순위가 가장 높은 그룹 연산자를 사용하여 우선순위를 명시적으로 조절하자!
연산자 결합 순서
- 연산자의 어느 쪽부터 평가를 수행할 것인지 나타내는 순서
좌항 > 우항: +, -, /, %, <, ≤, >, ≥, &&, , [], (), ??, ?., in, instanceof - 우항 > 좌항 : ++, —, 할당 연산자, !x, +x, -x, ++x, —x, typeof, delete, 삼항연산자