표현식이란 결과적으로 어떤 값으로 평가받는 것이다. 표현식을 평가한다는 의미는 표현식의 값, 변수, 함수 등의 값을 바탕으로 식의 값을 계산하는 행위를 의미합니다. 가장, 간단한 표현식은 숫자, 문자열, 논리값 등의 원시 값입니다.
3.14, "hello", true, false, null
변수, 프로퍼티, 배열 요소, 함수 호출, 메서드 호출도 표현식
sum, circle.radius, a[3], square(5), card.getSum()
또한 연산자를 사용하면 표현식을 조합하여 더욱 복잡한 표현식을 만들어 낼 수 있습니다. 다음은 연산자를 사용한 예입니다.
a - b
그룹 연산자 () 가 우선이다. 연산자의 우선순위는 우리가 수학시간에 배웠던 것과 동일하다. 즉 * 가 + 보다 우선적으로 계산된다.
24 / 6 * 2처럼
나누기와 곱하기는 연산우선순위가 동일합니다. 이럴 경우에는 왼쪽에서 오른쪽 방향으로 결합합니다.
x+y 표현식은 변수 값을 바꾸지 않지만, x = y 처럼 대입하는 표현식은 변수 x 값을 바꿉니다. 이처럼 변수 값을 바꾸는 표현식은 일반적으로 부수 효과가 있는 표현식이라고 합니다. 대입 연산자, 증가 연산자, 감소 연산자, delete가 부수 효과가 있는 연산자 입니다. 나머지 연산자에는 모두 부수 효과가 없습니다.
산술 연산자란? 피연산자가 숫자인 연산자입니다. 피연산자가 숫자 타입이 아닐 경우에는 타입을 숫자타입으로 바꾸어 연산합니다. 연산 결과로는 숫자 값이 나오지만 피연산자가 숫자로 바꿀 수 없는 값이거나 계산할 수 없을떄는 NaN이 나옵니다. 모든 산술 연산은 64비트 부동 소수점 연산으로 이루어집니다.
증가 연산자
++a : a에 1을 더한 다음에 a 값을 평가한다.
a++ : a를 평가한 다음에 1을 더한다.
+연산자는 피연산자가 모두 문자열이면 문자열로 연결합니다
"HELLO" + "WORLD" // "HELLO WORLD!"
"1" + "2" // "12"
피연산자 중 하나가 문자열 또는 문자열로 변환할 수 있는 객체라면 다른 피연산자의 타입을 문자열로 바꾼 다음 연결합니다.
10 + "Hello Yongmin" // "10 Hello Yongmin"
1 + {} // "1[object Object]
true + (new Date()) // 'trueMon Feb 20 2023 14:35:40 GMT+0900 (한국 표준시)'
var languageObj = new String("Everything is beautiful");
위의 코드 처럼 원시 값을 객체로 변환하는 행위를 가리켜 래핑(wrapping)한다고 합니다. string 객체에는 문자열을 처리하기 위한 다양한 프로퍼티와 메서드가 있으니 나중에 필요할떄 mdn을 통해 찾아서 사용하자!
문자열은 객체가 아니므로 프로퍼티를 가지고 있지 않습니다. 그런데 이것이 어떻게 동작할까요? 문자열에서 프로퍼티를 사용하려고 하면 문자열이 자동으로 string 객체로 변환되기 떄문입니다.
아래 코드를 실행해보자
var msg = "Every morning";
var c = msg.charAt(3);
console.log(c); // r
이 코드 실행시 내부적으로 아래와 같은 작업이 일어납니다.
var msgObj = new String(msg); // 문자열을 string 객체로 변환
var c = msgObj.charAt(3); // string객체 메서드 사용
msjObj 실행시 일시적으로 생성되는 string 객체이므로 사용자에게는 보여지지 않습니다. => 처리가 끝나면 곧바로 메모리에서 삭제가 됩니다.
이러한 객체를 가리켜 래퍼 객체라고 합니다.
자바스크립트에서 원시 값을 처리할 떄 원시 값을 래퍼 객체로 자동 변환합니다. 그리고 래퍼 객체의 기능을 활용해서 다양한 작업을 수행합니다. 문자열은 String 객체, 숫자는 Number객체, 논리값은 Boolean 객체로 변환됩니다. 단, null과 undefined에는 wrapper(래퍼) 객체가 없습니다.
즉, 우리가 생성한 "Every morning"이라는 문자열은 자동으로 래퍼 객체인 String객체로 변환되며 그로 인해 우리가 .length, .charAt, .subString, .slice와 같은 것들을 사용할 수 있습니다.
var msg = new String("Everything is funny.");
console.log(msg); // -> String {"Everything is funny."}
var msg = new String("Everything is funny.").valueOf();
console.log(msg); // Everything is funny
문자열을 읽을 떄는 charAt 메서드 대신 대괄호를 사용할 수 있습니다.
msg[3] // r
msg[msg.length-1] // .
그러나 배열처럼 값을 대입해서 수정할 수는 없습니다. 대입해도 무시됩니다.
msg[3] = "R";
console.log(msg); // Everything is funny
관계 연산자는 두 개의 피연산자를 비교한 결과를 논리값(true, false)로 반환한다.
==, !=, <, >, <=, >= 이 있고 타입까지도 검사하는 ===, !== 이 있다.
좌우 피연산자의 타입이 다를떄
1. undefined와 null은 같은 것으로 친다.
2. 한쪽이 숫자고 다른 한쪽이 문자열이면 문자열을 숫자로 변환해서 비교합니다.
3. 둘중에 한쪽이 논리 값이면 true는 1, false는 0으로 변환해서 비교합니다.
4. 한쪽이 객체고 다른 한쪽이 숫자 또는 문자열이면 객체를 toString이나 vlaueOf 메서드를 사용해서 원시 타입으로 변환한 다음에 비교합니다.
5. 앞의 규칙에서 벗어나면 모두 '같지 않음'으로 판정!
null === undefined // true
1 == "1" // true (문자를 숫자로 변환)
"0xff" == 255 // true
true == 1 // true
true == "1" // true
(new Sting("a")) == "a" // true
(new Number(2)) == 2 // true
[2] == 2 // true
&& 논리곱 : a와 b가 모두 true면 true 나머지는 false
|| 논리합 : a와 b중 하나라도 true면 true 모두기 false면 false
! 부정 : a가 true면 false, false면 true
논리 연산시 논리값이 아니면 필요에 따라 타입을 변환합니다
0, -0, "", NaN, null, undefined => false
0을 제외한 숫자, 빈 문자열을 제외한 문자열, 모든 객체, 심벌 => true
단항 연산자이고, 피연산자의 데이터 타입을 뜻하는 문자열을 반환합니다
var lang = "hello";
console.log(typeof lang); // string
typeof 연산자는 함수 이외의 객체에 대해 모두 object를 반환합니다. 객체 유형은 파악할 수 없습니다. 객체 유형을 조사할 떄는 instanceof연산자와 객체의 constructor 프로퍼티를 이용합니다.
조건(?:)연산자는 주어진 조건의 참과 거짓에 따라 값을 선택합니다.
var parity = (a % 2 == 0)? "짝수" : "홀수";
즉, a가 짝수면 짝수가 되고, 홀수면, 홀수가 됩니다. 삼항 연산자라고도 부릅니다.
10 + "cookies" // "10cookies"
100 + "" // "100" : 숫자에 빈 문자열을 더해도 문자열로 변환 가능
("0000" + 12).slice(-4) // "0012" : 앞부분에 0을 넣어 네 자릿수 정수를 표현하는 문자열로 만듬
Number 객체의 메서드를 활용하는 방법
toString, toLocaleString, toFixed, toExponential, toPrecision 등을 활용해서 바꿀 수 있다.
String 함수를 활용
String 생성자 앞에 new연산자를 붙이면 String 객체를 생성하는 함수로 사용할 수 있지만, new연산자를 붙이지 않으면 일반적인 함수로 활용할 수 있습니다.
String(26) // -> "26"
// String 함수에는 모든 데이터 타입을 문자열 타입으로 바꾸는 기능이 있다.
String("ABC") // "ABC"
String(true) // "true"
String(NaN) // "NaN"
String({x:1, y:2}) // "[object Object]"
String([1, 2, 3]) // -> "1, 2, 3"
var s = "2";
s - 0 // 2
+s // 2
parseInt("3.14") // 3
parseFloat("3.14") // 3.14
parseInt("3.14 meters") // 3 : 숫자다음 문자열 무시
parseInt("0xFF") // 255 16진수로 해석
parseInt(".5") // NaN 문자열 앞부분에 . 이 있으므로 해석 x
parseInt("abc") // NaN 숫자로 해석할 수 없음
parseFloat("\100") // NaN: 문자열 앞부분에 \가 있으므로 해석 x
Number("2.718") // 2.718
Number(false) // 0
Number(NaN) // NaN
Number(undefined) // NaN
Number(null) // 0
Number({x:1, y:2}) // NaN
Number([1, 2, 3]) // NaN
!!x // ! 연산자는 논리타입이 아닌 값의 타입을 논리타입으로 변경함. ! 하나 더붙여서 참과 거짓을 변경. !!만을 사용하여 값의 타입을 논리타입으로 바꿀 수 있다.
Boolean(x)