[자바스크립트 Deep Dive] 연산자

률루랄라·2022년 3월 17일
0
post-thumbnail

7. 연산자

연산자는 하나 이상의 표현식을 대상으로 산술, 할당, 비교, 논리, 타입, 지수 연산 등을 수행하여 하나의 값을 만든다. 이때 연산의 대상은 피연산자이다. 피연산자는 당연히 값으로 평가될 수 있는 표현식이어야하고 연산자 표현식도 값으로 평가될 수 있는 표현식이다.
즉, 연산자는 값으로 평가된 피연산자 또는 값으로 평가된 표현식을 연산해 새로운 값 또는 표현식을 만든다.

7.1. 산술 연산자

Algebra or Arithmetic operator
피연산자를 대상으로 수학적 계산을 통해 새로운 숫자 값을 만든다. 피연산자간 산술 연산이 불가능한 경우 NaN을 반환한다.


7.1.1. 이항 산술 연산자 / Binary

2개의 피연산자를 산술 연산하여 숫자 값을 만드는 연산자로서 사용된 피연산자의 값을 변경하는 side effect가 없는 것이 특징이다. 즉 언제나 새로운 값을 만들어낸다.


+ 
//덧셈
- 
// 뺄셈
*
// 곱셀
/ 
//나눗셈
% 
// 나머지
5%2 = 1
// 5를 2로 나눈후 (정수만) 남은 값

7.1.2. 단항 산술 연산자 / Unary

1개의 피연산자만을 대상으로 산술 연산하여 숫자 값을 만든다.


증가, 감소 연산자는 피연산자의 값을 변경하는 부수 효과가 있다.
다음 예제로 살펴보자.

var x = 1;

x++;

console.log(x)
// 2

x--;
console.log(x)
// 1

또한 증가, 감소 연산자는 연산자의 위치에 따라 값이 달라질 수 있다.

var x= 5, result;

//선할당 후증가 (postfix increment operator)
result = x++;

console.log( x, result )
// 6, 5

//선증가 후할당 (prefix increment operator)
result = ++x;

console.log( x, result)
// 7, 7

//선할당 후감소 (postfix increment operator)
result = x--;

console.log( x, result )
// 6, 7

//선감소 후할당 (prefix increment operator)
result = --x;

console.log( x, result)
// 5, 5

+, - 단항 연산자는 그 어떠한 피연산자에 주는 부수효과가 없다.
다음예제를 통해 정리해보자.

+10
// 10
+(-10)
// 10
-(-10)
// 10

-'10' // -10. 문자열은 연사자의 피연사자일 때 숫자로 치환되는데 

-'x' // NaN. 숫자로 치환할 수 없는 문자열일 경우 NaN

숫자 타입이 아닌 피연산자에 + 단항 연산자를 사용하면 피연산자를 숫자 타입으로 변환하여 반환한다.
다만 피연산자를 변경하는 것이 아니라 단지 연산에 사용될 피연사자의 값을 숫자 타입으로 변환하여 연산에 사용한다.

var x = '1';

console.log(+x); //1 as number

//부수효과 없음
console.log(x); // "1" as string

x = true;

console.log( +x ); // 1 as number

console.log(+x+1); // 2 as number. true는 숫자와 연산시 숫자 1로 치환된다.

//부수효과 없음
console.log(x); // true

x = false;

console.log( +x ); // 0 as number

console.log(+x+1); // 1 as number. false는 숫자와 연산시 숫자 0으로 치환된다.

//부수효과 없음
console.log(x); // false

x = 'x';

console.log(+x); // NaN

//부수효과 없음
console.log(x); //'x'

7.1.3. 문자열 연결 연산자

  • 연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작한다. 그 외의 경우는 산술 연산자로 동작.

//피연산자 중 하나 이상이 문자열인 경우
"1"+2; // '12' as string

1 + '2'; // 12 as string

// 피연산자 중 하나 이상이 문자열인 경우 외의 경우

1 + 2; // 3

1 + true; // 2

1+ false; // 1

1 + null; // 1. null 또한 산술 연산자로 작동한 연산식에서는 0으로 치환된다. 

1 + undefined; // NaN

+undefined; // NaN

불리언 타입, null 타입이 산술 연산자로 동작한 연산식에 있을 경우 자바스크립트 엔진은 타입과 값을 변경한다. 또한 string 타입이 피연산자 중 하나로서 연산자가 문자열 연결 연산자로 동작할 경우 string은 number 타입과 값으로 변경된다. 다만 string값이 number의 값으로서 치환될 수 없을 경우 NaN으로 치환된다.

위의 일련의 변경 과정을 암묵적 타입 변환 (implicit coercion) 또는 타입 강제 변환 (type coercion) 이라고 한다. to be continue in CH.9 타입 변환과 단축 평가

7.2. 할당 연산자 / Assignment operator

변수에 값을 할당하는 여러 연산자


var x;

x= 10;
// 10

x +=5 // x = x+5
// 15

var str = "My name is";

str += "Lee"; // str = str + "Lee"
// My Name is Lee

앞서 표현식은 값으로 평가될 수 있는 문으로 문에는 표현식인 문과 아닌 문이 있다고 정리했다.

그렇다면 할당문은 표현식인 문일까?

할당문은 변수에 값을 할당하는 부수 효과만 일을 뿐 값으로 평가되지 않을 것 처럼 보인다.
하지만 값으로 평가되는 표현식인 문으로서 할당된 값으로 평가 된다.

var x;

console.log(x=10);
// 10

따라서 다음과 같은 동일한 값을 연쇄 할당도 할 수 있는 것이다.

var a, b, c;

a = b = c = 10;

console.log(a, b, c)
// 10, 10, 10

7.3. 비교 연산자 / Comparison operator

좌항과 우항의 피연산자를 비교 후 결과를 불리언 값으로 반환하는 연산자.


7.3.1. 동등/일치 비교 연산자

동등 비교 (loose equality) 연산자와 일치 비교 (strict equality) 연산자는 좌항과 우항의 피연산자가 같은 값으로 평가되는지 비교해 불리언 값을 반환한다. 다만 그 엄격성의 정도가 다르다.
shallow vs deep

동등 비교 연산자는 좌항과 우항의 피연산자를 비교할 때 먼저 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값인지 비교한다. 즉, 좌항과 우항의 피연산자가 같은 타입이 아니더라도 암묵적 타입 변환 후 같은 값이라면 true일 수 있다.

5 ==5; // true

5 == '5'; // true

이처럼 암묵적 타입 변환이 이뤄지기 때문에 결과를 예측하기 어렵고 의도치않은 결과가 나올 수 있다. 다음과 같다.

'0' == ''; // false
0 == ''; // true
0 == '0'; // true

false == 'false'; // false
false == '0'; // true
false == 0; // true
false == null; // false
null == 0; // false*
false == undefined; //false

이처럼 동등 비교 연산자는 예측하기 어려운 결과를 만들어낸다. 대신 일치 비교 연산자, deep comparison / deep equality를 사용하는 것이 좋다.

추가적으로 같이 보면 좋을것들
truthy and falsey
문자열 '0'은 문자열 연결 연산자로 작동하는 연산문에서 숫자 0 으로 타입 변경이 된다.
false는 0으로 true는 1로 타입 변경 및 값이 변경된다.
null은 0으로 타입과 값이 변경된다.
하지만 비교 연산자에서 동등 비교 연산시 null은 null로서 남아있는다.

0 == null; // false

일치비교 연산자는 좌항과 우항의 피연산자의 타입과 값이 모두 같은 경우에만 true를 반환한다.
즉, 암묵적 타입 변환이 이뤄나지 않아 결과 예측이 쉽다.

5 ===5; // true
5 ==='5'; // false

하나 짚고 넘어가야할 부분은 NaN이다.

NaN === NaN; // false

'1' == NaN; // false

NaN은 자신과 일치하지 않은 유일한 값이다. 따라서 비교 연산자에서 값이 NaN인지 조사하려면 함수 Number.isNaN을 사용하여야 한다.

Number.isNaN(NaN); // true
Number.isNaN(10); // false
Number.isNaN(1 + undefined); // true

숫자 0 또한 양의 0과 음의 0이 모두 존재하는데 이 둘을 비교하면 true가 반환된다.

0 === -0; // true
0 == -0; // true

// Object.is 함수를 이용하면 좀 더 예측 가능한 정확한 비교가 가능하다.

0 === -0; // true
Object.is(-0, +0); // false

NaN === NaN; // false
Object.is(NaN, NaN); // true

7.3.2. 대소 관계 비교 연산자

대소 관계 비교 연산자 비교표

대소 관계 비교 연산자예제설명부수 효과
> x > y x가 y보다 크다. x
<x < yx가 y보다 작다.x
>=x >= y x가 y보다 같거나 크다.x
<=x <= yx가 y보다 작거나 같다.x

7.4. 삼항 조건 연산자 / ternary operator

삼항 조건 연산자는 조건식의 평가 결과에 따라 변환할 값을 결정한다. 부수 효과는 없고 다음과 같이 사용한다.


var result = score >=60 ? 'pass' : 'fail'

score의 값이 60과 같거나 큰지에 대한 연산이 먼저 실행된다.
?를 기준으로 좌항의 값이 참이면 :뒤의 값을 리턴하고 참이 아니면 fail을 리턴한다.
삼항 연산자는 조건문의 줄임으로 사용될 수 있다.

var x = 2, result;
if (x%2) result = '홀수';
else result = '짝수';

var result = x % 2 ?'홀수' : '짝수';

다만 차이점은 삼항 조건 연산자 표현식은 값처럼 사용할 수 있다. 즉 값으로 평가할 수 있는 표현식인 문이다.

7.5. 논리 연산자 / logical operator

우항과 좌항의 피연산자 (부정 논리 연산자의 경우 우항의 피연산자)를 논리 연산한다.


논리 연산자의미부수 효과
ll논리합(OR)X
&&논리곱(AND)X
!부정(NOT)X

// 논리합 연산자
// || 기준 좌항의 값이 true일 경우 좌항을 return, false일 경우 우항을 return
true || true; // true
true || false; // true
false || true; // true
false || false; // true

// 논리곱 연산자
// && 기준 좌항의 값이 true일 경우 우항을 return, false일 경우 좌항을 return
true && true; // true
true && false; // false
false && true; // false
false && false; // false

// 논리 부정 연산자
!false; // true
!true; // false

논리 부정 연산자는 언제나 불리언 값을 반환한다. 만약 피연산자가 불리언 값이 아니면 불리언 타입으로 암묵적 타입 변환된다.
자세한건 CH.9 단축평가에서....

7.6. 쉼표 연산자.

왼쪽 피연산자부터 차례대로 피연산자를 평가하고 마지막 피연산자의 평가가 끝나면 마지막 피연산자의 평가 결과를 반환

var x, y, z;
x = 1, y=2, z=3; // 3

7.7. 그룹 연산자.

소괄호로 피연산자를 감싸 연산식에서 평가 순서를 컨트롤할 수 있다.

10 *2 +3; // 23

10 * (2 +3); // 50

7.8. typeof 연산자

피연산자의 데이터 타입을 문자열로 반환.
반환되는 문자열은 다음 7가지와 같다.
1. stirng
2. number
3. boolean
4. undefined
5. symbol
6. object
7. function

null을 반환하는 경우는 없으며 예제는 다음과 같다.

typeof ''; // "string"
typeof 1; // "number"
typeof NaN; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof null; // "object"
typeof []; // "object"
typeof {}; // "object"
typeof new Date(); // "object"
typeof /test/gi; // "object"
typeof function() {}; // "function"

typeof null의 경우 object를 반환하는데 이는 자바스크립트의 첫 번째 버전의 버그다.
따라서 값이 null 타입인지 확인할 떄는 일치 연산자(===)를 사용하는 것이 정확하다.

var foo = null;

typeof foo === null; // false
foo === null; // true

7.9. 지수 연산자

ES7에서 도입된 지수 연산자는 좌항의 피연산자를 밑으로, 우항의 피연산자를 지수로 거듭 제곱한다.

2 ** 2; // 4
2 ** 0; // 0

//지수연산자 도입전
Math.pow(2, 2); // 4
Math.pow(2, 0); // 0

//음수를 거듭제곱 시 괄호로 묵어야 한다.
-5 ** 2 // SyntaxError: ...

(-5) ** 2 // 25

// 할당 연산자와 함께 사용 가능
var num = 5;
num **= 2; // 25

7.10. 그 외의 연산자

연산자개요참고
?.옵셔널 체이닝 연산자CH.9.4.2
??null 병합 연산자CH.9.4.3
delete프로퍼티 삭제CH.10.8
new생성자 함수를 호출할 때 사용하여 인스턴스를 생성CH.17.2.6
instanceof좌변의 객체가 우변의 생성자 함수와 연결된 인스턴스인지 판별CH.19.10
in프로퍼티 존재 확인CH.19.13.1

7.12. 연산자 우선순위

우선순위참고
1()
2new(매개변수 존재), ., [](프로퍼티 접근), ()(함수호출), ?.(옵셔널 체이닝 연산자)
3new(매개변수 미존재)
4x++, x--
5!x, +x, -x, ++x, --x, typeof, delete
6** (이항 연산자 중에서 우선순위가 가장 높다)
7*, /, %
8+, -
9<, <=, >, >=, in, instanceof
10==, !=, ===, !==
11?? (null 병합 연산자)
12&&
13ll
14? ~: ~
15할당 연산자 (=, +=. -=. ...)
16,
profile
💻 소프트웨어 엔지니어를 꿈꾸는 개발 신생아👶

0개의 댓글