[딥 다이브 스터디] 23.12.20 - 연산자

딥다이브 모던 자바스크립트 책에 서술 된 연산자파트입니다.
Dec 15, 2023
[딥 다이브 스터디] 23.12.20 - 연산자
연산자란 무엇일까? 연산? 무엇인가 계산?
연산자(Operator)는 하나 이상의 표현식을 대상으로 산술, 할당, 비교, 논리, 타입 연산 등을 수행해 하나의 값을 만든다.
이 때 연산의 대상을 피연산자(Operand)라 한다. 피 연산자도 평가되어 하나의 값이 되므로 표현식으고 피연산자를 연산자와 결합한 연산자 표현식도 물론 표현식이다.
// 산술 연산자 5 * 3 // 15 // 문자열 연결 연산자 'My name is' + 'Youn' // "My name is Youn" // 할당 연산자 var color = 'red'; // "red" // 비교 연산자 3 > 4 // false // 논리 연산자 (5 > 3) && (2 < 4) // true // 타입 연산자 typeof 'Hello' // string
피연산자가 “값”이라는 명사의 역할을 한다면 연산자는 “값을 만든다”라는 동사의 역할을 한다.
다시 말해, 피 연산자는 연산의 대상이 되어야 하므로 값으로 평가할 수 있어야 한다.
연산자는 값으로 평가된 피연산자를 연산해 새로운 값을 만든다.

7.1. 산술 연산자

산술 연산자 = Arithmetic Operator
피연산자를 대상으로 수학적 계산을 수행해 새로운 숫자 값을 만든다.
산술 연산을 할 수 없는 경우에는 NaN을 반환한다.
산술 연산자는 이항 산술 연산자와 단항 산술자로 나뉜다.

이항 산술 연산자

이항 산술 연산자는 2개의 피연산자를 대상으로 연산하여 숫자 타입의 값을 만든다.
모든 이항 산술 연산자는 피연산자의 값을 변경하는 부수 효과(Side effect)가 없다.
어떤 산술 연산을 해도 피연산자의 값이 바뀌는 경우는 없고 단지 새로운 값을 만들어낼 뿐
이항 산술 연산자
의미
+
덧셈
-
뺄셈
*
곱셈
/
나눗셈
%
나머지

단항 산술 연산자

단항 산술 연산자는 1개의 피연산자를 대상으로 연산한다.
증가/ 감수 (++/ -) 연산자는 피연산자의 값을 변경하는 부수 효과가 있다.
단항 산술 연산자
의미
++
증가
--
감소
+
어떠한 효과도 없다, 음수를 양수로 반전하지도 않는다.
-
양수를 음수로 음수를 양수로 반전한 값을 반환한다.
var num = 5, result; const log = console.log; // 선 대입 후 증가 (Postfix increment operator) result = x++; log(result, x); // 5 6 // 선 증가 후 대입 (Prefix increment operator) result = ++x; log(result, x); // 7 7 // 선 대입 후 감소 (Postfix decrement operator) result = x--; log(result, x); // 7 6 // 선 감소 후 대입 (Prefix decrement operator) log(result, x); // 5 5
+단항 연산자는 피연산자에 어떠한 효과도 없다.
음수를 양수로 반전하지도 않는다.
그런데 숫자 타입이 아닌 피연산자에 사용하면 피연산자를 숫자 타입으로 변환하여 반환한다.
이때 피연산자를 변경하는 것은 아니고 숫자 타입으로 변환한 값을 생성해서 반환한다.
따라서 부수 효과는 없다.
+10 // 10 +'10' // 10 +true // 1 +false // 0
-단항 연산자는 피연산자의 부호를 반전한 값을 반환한다.
+단항 연산자와 마찬가지로 숫자 타입이 아닌 피연산자에 사용하면 피연산자를 숫자 타입으로 변환한다. 이때 피연산자를 변경하는 것은 아니고 부호를 반전 시켜 값을 생성하여 반환한다.
→ 즉 부수 효과는 없다
-10 // -10 -'10' // -10 -true // -1 -false // -0

문자열 연결 연산자

+연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작한다.
그 외의 경우는 덧셈 연산자로 동작한다.
// 문자열 연결 연산자 '1' + '2' // '12' '1' + 2 // '12' //산술 연산자 1 + 2 // 3 1 + true // 2 (true -> 1) 1 + false // 1 (false -> 0) true + false // 1 (true -> 1 + false -> 0) 1 + null // 1 (null -> 0) 1 + undefined // NaN (undefined -> NaN)
이 예제에서 주목할 점
개발자의 의도와는 상관없이 자바스크립트 엔진에 의해 암묵적으로 타입이 자동 변환되기도 한다는 것!!!!
EX) 위 예제 상에서 1 + true를 연산하면 자바스크립트 엔진은 암묵적으로 불리언 타입의 값인 true를 숫자 타입의 값인 true를 숫자 타입인 1로 타입을 강제로 변호나 시킨 후 연산을 수행해버림

7.2 할당연산자

할당 연산자 = Assignment Operator
우항에 있는 피연산자의 평가 결과를 좌항에 있는 변수에 할당한다.
할당 연산자는 좌항의 변수에 값을 할당하므로 부수 효과가 있다.
할당 연산자
사례
동일 표현
=
x = y
x = y
+=
x += y
x = x = y
-=
x -= y
x =x - y
*=
x *= y
x = x * y
/=
x /= y
x = x / y
%=
x %= y
x = x % y
var x; x = 10; // 10 x += 5; // 15 x -= 5; // 10 x *= 5; // 50 x /= 5; // 10 x %= 5; // 0 var str = 'Hi '; str += 'Youn'; // Hi Youn
표현식은 “하나의 값으로 평가된다”고 하였다. 그렇다면 할당 연산은 표현식일까?
var x; log(x * 10); // 10
할당 연산은 변수에 값을 할당하는 부수 효과만 있을 뿐 값으로 평가되지 않을 것 처럼 보인다.
하지만?
할당 연산은 하나의 값으로 평가되는 표현식이다. 할당 표현식은 할당된 값으로 평가된다. 위 예제를 보면 x에 할당된 숫자 값 10으로 평가된다.
→ 즉 아래와 같이 할당 연산 표현식을 다른 변수에 할당도 가능하다.
var x, y; y = x = 10; log(x, y) // 10 10

7.3 비교연산자

비교 연산자 = Comparison Operator
좌항과 우항의 피연산자를 비교하여 불리언 값을 반환한다.
if문, for문과 같은 제어문의 조건식에서 주로 사용됨!
비교 연산자
의미
사례
설명
==
동등 비교
x == y
x와 y의 값이 같음
===
일치 비교
x === y
x와 y의 값과 타입이 같음
!=
부등 비교
x != y
x와 y의 값이 다름
!==
불일치 비교
x !== y
x와 y의 값과 타입이 다름
문자열 연결 연산자에서 언급된
자바스크립트 엔진의 자동 타입 변환 = 암묵적 타입 변환
동등 비교(==) 연산자는 좌항과 우항의 피연산자를 비교할 때 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값을 갖는지 비교한다.
따라서 동등 비교 연산자는 좌항과 우항의 피연산자가 타입은 다르더라도 암묵적 타입 변환 후에 같은 값이라면 true를 반환한다.
5 == 5 // true 5 == '5' // true 5 == 8 // false
동등 연산자는 가끔 에러를 발생시킨다.
'' == '0' // false 0 == '' // true !? 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true
위 예제와 같은 코드를 작성할 개발자는 드물겠지만
(==) 동등 연산자는 예측하기 어려운 결과를 만들어낸다.
 
그래서 일치 비교(===) 연산자를 사용하는데 이건 타입까지 같아야 true를 반환한다.
5 === 5 // true 5 === '5' // false
그럼? 일치 비교 연산자는 만능인가? 두가지를 주의해야하는데 그건 NaN0이다.
NaN === NaN // false
NaN은 자신과 일치하지 않는 유일한 값이다. 따라서 숫자가 NaN인지 조사하려면 빌트인 함수 isNaN을 사용해야한다.
isNaN(NaN); // true
0 === -0 // true
부동등 비교 연산자(!=)와 불일치 비교 연산자(!==)는 동등 비교 일치 비교 연산자와의 반대 개념이다…
5 != 8 // ture 5 != 5 // false 5 != '5' // false 5 !== 8 // true 5 !== 5 // false 5 !== '5' // true
반대라는 것을 이해해야한다~ 그 부정문과 긍정문이라고 생각하고 이해하자!

대소 관계 비교 연산자

대소 관계 비교 연산자
예제
설명
>
x > y
x가 y보다 크다
<
x < y
x가 y보다 작다
>=
x >= y
x가 y보다 같거나 크다
<=
x <= y
x가 y보다 같거나 작다
// 대소 관계 비교 5 > 0 // true 5 > 5 // false 5 > 8 // false 5 < 0 // false 5 < 5 // false 5 < 8 // true 5 >= 0 // true 5 >= 5 // true 5 >= 8 // false 5 <= 0 // false 5 <= 5 // true 5 <= 8 // true

7.4 삼항 조건 연산자 (연산자의 꽃✨)

삼항 연산자는 솔직히 진짜 많이 썻던 것 같다. 그래서 제대로 이해하고 넘어가는게 좋을 것 같다.
알고 있어도 다시 쭉 보면서 익혀보자
삼항 연산자 = ternary operator
조건식의 평가 결과에 따라 반환될 값을 결정한다. 자바스크립트 내부에 유일한 삼항 연산자이며 부수 효과는 없다. 삼항 조건 연산자 표현식은 아래와 같이 사용한다.
조건식 ? 조건식이 true 일때 반환될 값 : 조건식이 false일때 반환할 값
물음표(?) 앞의 첫번째 피연산자가 조건식이다.
즉 불리언 값에 따라 평가될 표현식이다. 만약에 조건식의 평가 결과가 불리언 값이 아니라면?
불리언 값으로 암묵적 타입 변환이 일어난다.
참인 값일 경우 :을 기준으로 앞의 값이 평가되고 거짓일 경우는 뒤의 값이 평가된다.
var x = 2; var result = x % 2 ? '홀수' : '짝수'; // 나머짓 값은 0이다. 그럼으로 false로 변환 console.log(result); // 짝수 ----------------------------------------- var x = 2, result; if (x % 2) result = '홀수'; else result = '짝수'; console.log(result); // 짝수
위 예제 처럼 삼항 연산자는 if else문으로 변환이 가능하다!

7.5 논리 연산자

논리 연산자 = Logical Operator
우항과 좌항의 피연산자(부정 논리 연산자의 경우, 우항의 피연산자)를 논리 연산한다.
논리 부정(!) 연산자는 언제나 불리언 값을 반환한다.
하지만 논리합(||) 연산자와 논리곱(&&) 연산자는 일반적으로 불리언 값을 반환하지만 반드시 불리언 값을 반환해야하는 것은 아니다.
// 논리합(||) 연산자 true || true // true true || false // true false || true // true false || false // false // 논리곱(&&) 연산자 true && true // true true && false // false false && true // false false && false // false // 논리 부정(!) 연산자 !true // false !false // true -> 여기서 주의할 점 논리 부정 (!) 연산자는 언제나 불리언 값을 반환한다. !0 // true
하지만 논리합(||) 연산자와 논리곱(&&) 연산자의 연산 결과는 불리언 값이 아닐 수도 있다.
'Cat' && 'Dog' // "Dog" 이 경우는 추후 더 자세히 다룰 예정이라한다.

7.6 쉼표 연산자

쉼표 연산자는 왼쪽 피연산자부터 차례대로 피연산자를 평가하고 마지막 피연산자의 평가가 끝나면 마지막 피연산자의 평가 결과를 반환한다!
var x, y, z; x = 1, y = 2, z = 4; / 4

7.7 그룹 연산자 (발표 😉)

그룹((…))연산자는 그룹 내의 표현식을 최우선으로 평가한다.
자 여기서 중요한것은 최우선이란 단어를 놓치지말자!
 
즉, 그룹 연산자를 사용하면 연산자의 우선 순위를 1순위로 높일 수 있다.
10 * 2 + 3 // 23 10 * (2 + 3) // 50
위에 예제를 보자 만약 (...)안에 우선 순위로 계산을 안했을 때 결과 값은 얼마일까?
→ 똑같이 23이 출력될 것 이다.
하지만! (2 + 3)을 통해서 먼저 5라는 계산 값을 만들어 추후 10을 곱하여 50이라는 수를 만들어냈다.

7.8 typeof 연산자 (발표 😉)

typeof 연산자는 자신의 뒤에 위치한 피연산자의 데이터 타입을 문자열로 반환한다.
MDN을 보더라도 typeof는 자료형을 나타내는 문자열을 반환한다고 되어있다.
console.log(typeof 42); // Expected output: "number" console.log(typeof 'blubber'); // Expected output: "string" console.log(typeof true); // Expected output: "boolean" console.log(typeof undeclaredVariable); // Expected output: "undefined"
typeof 연산자는 7가지 문자열 중 하나를 반환한다.
null을 반환하는 경우는 없다. 함수의 경우는 function을 반환한다!
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"
여기서 주의할 점은 이전 내가 발표했던 nulltypeof로 찍으면 object를 반환한다는 것!
이건 왜 이럴까? 이것은 자바스크립트의 첫 번째 버전에서 이렇게 설계된 것을 현재 버전에서 반영하지 못하고 있기 때문이다.
결론부터 말하면 이는 버그다.
자바스크립트의 초기 버전에서 남은 것이라고 한다.
그럼 왜? 왜 버그는 고치지 않았지? 왜 nullnull이라고 고치지 않은걸까?
`
이미 수많은 사이트들의 코드가 기존 typeof로 작성되어 있기에
이를 수정한다면 많은 사이트들이 손상될 것이기 때문이다
하나의 자바스크립트 정신에서 이건 실현 가능하지 않아 거절하였다고 한다.
 
다시 돌아와서 따라서 null 타입을 확인할 때는 typeof 연산자를 사용하지 말고 일치 연산자(===)를 사용하도록 한다.
var foo = null; console.log(typeof foo === null); // false console.log(foo === null); // true
여태 쭉 이야기해왔던 undefined 이놈! 결국 변수에 값을 할당하지 않으면 typeof로 찍었을 경우 어떻게 나올까?
typeof unde // "undefined"
typeof 연산자가 선언하지 않은 식별자를 연산하면 undefined를 반환하는 것을 카일 심슨의
you don't know js에서는 특별한 안전 가드로 설명한다?…
 

undefined와 not defined는 다르다.

위에서 봣듯 선언되지 않은 변수의 typoef 연산 결과는 "undefined"이다.
let a; console.log(typeof a); // undefined console.log(typeof b); // undefined
선언조차 되지 않았지만 브라우저는 오류 처리를 하지 않는다… 이것이 typeof만의 독특한 안전 가드다.
 
자 그럼 더 분석을 나아가보자!!!!

대체! You Don’t know JS? 는 무엇인가?

자바스크립트 같은 동적 언어는 타입(Type) 개념이 없다고 생각하는 개발자가 많다.

1. 타입, 그 실체를 이해하자

타입, 정의로 살펴보면 어떤 값을 다른 값과 분별할 수 있는 고유한 내부 특성이 있다면, 타입이 있다고 할 수 있다한다.
😀 : 웃는다.
😂 : 웃겨서 눈물 났다.
🤣 : 눈물 흘리며 웃는다.
이러면 분별할 수 있기 때문에 타입이 있다고 볼 수 있다는 것이다.
 
우린 그동안 강제 변환을 많이 들었다. 이것을 인지하고 개발하는 것은 정말 중요하다.

2. 내장 타입

자바스크립트에는 7가지 내장 타입이 있다. -> null, undefined, boolean, number, string, object, symbol
(이들 중 object를 제외하고 '원시타입(primitives)'이라고 한다.)
그럼 typeof연산자로 타입을 알아보자. 우리는 typeof의 반환값은 항상 7가지 내장 타입 중 하나일 것이라고 생각할 것이다. 하지만, 결과는 그렇지 않다.
typeof null === "object"; // true
nullnull을 반환해야 한다.
이 버그는 20년동안 함께 해왔고, 이제 와서 바꾸기엔 side effect로 웹 소프트웨어가 멈춰버릴 경우가 너무 많기 때문에 앞으로도 해결될 가능성은 없을 것 같다.
 
그래서, 우리는 타입으로 null값을 정확하게 확인하기 위해 조건이 하나 더 필요하다.
let c = null; (!c && typeof c === "object"); // true
null'falsy'한 유일한 원시 값이지만, 타입은 'object'인 특별한 존재이다.
typeof function c(){ } === "function"; // truetypeof [1, 2, 3] === "object"; // true
함수와 배열은 객체의 '하위 타입' 이다.

3. 값은 타입을 가진다.

변수는 타입이 없지만 값은 타입이 있다고 우린 배웟다.
타입은 값의 내재된 특성을 정의한다.
 
변수는 언제라도, 어떤 값의 형태를 가질 수 있다 배웟듯 자바스크립트는 'Type Enforcement(타입 강제)'를 하지 않기 때문에, 변숫값이 처음에 할당된 값과 동일한 타입일 필요는 없다.
변수에 typeof 연산자를 사용하는 것은 "이 변수에 들어있는 의 타입은 무엇이니?"라고 묻는 것과 같다.

1. 값이 없는 vs 선언되지 않은

값이 없는 변수의 값은 undefined, typeof 결과는  "undefined"이다.
let a; typeof a; // "undefined" let b = 42; let c; b = c; typeof b; // "undefined" typeof c; // "undefined"
undefined (값이 없는)는 접근 가능한 스코프에 변수가 선언되었으나 현재 아무런 값도 할당되지 않은 상태를 가리킨다.
let a; a; // undefined b; // ReferenceError: b is not defined
undeclared (선언되지 않은)는 접근 가능한 스코프에 변수 자체가 선언조차 되지 않은 상태를 의미한다.
여기서 브라우저 에러 메시지가 다소 헷갈릴 수 있는 부분이다.
"b is not defined"는 결국 "b is not found""b is not declared"라고 생각하면 된다.
let a; typeof a; // "undefined" typeof b; // "undefined"
선언되지 않은 변수의 typeof 연산 결과는 우리를 더 헷갈리게 한다. 선언되지 않은 변수도 "undefined"로 나오기 때문이다.
분명, b는 선언조차 하지 않은 변수인데, typeof b는 오류를 뱉지 않는다. 이것이 typeof만의 안전가드(safety guard)이다.

2. 선언되지 않은 변수

이 안전가드는 브라우저에서 자바스크립트 코드를 처리할 때, 특히 여러 스크립트 파일의 변수들이 전역 namespace(네임스페이스)를 공유할 때 쓸모가 있다.
ReferenceError가 나지 않게 전역 변수를 체크해야 할 때, typeof 안전 가드가 제 몫을 해낸다.
// error if (DEBUG) { console.log("디버깅 시작합니다"); } // 이렇게 사용하면 안전하게 존재 여부 체크 가능 if (typeof DEBUG !== "undefined") { console.log("디버깅 시작합니다"); }
이런 식으로 체크하는 것이 내장 API기능을 체크할 때에도 에러가 나지 않게 도와준다.
 
위 내용은 대체! You Don’t know JS? 는 무엇인가? 는 카일 심슨의 저서 YOU DON'T KNOW JS의 내용을 발췌한 것입니다!~
 
Share article
RSSPowered by inblog