자바스크립트에서 문자열을 숫자로 변환할 때 parseInt(), parseFloat(), Number() 등의 메서드를 사용하기도 하지만, 단항 연산자(+)를 사용하면 더욱 간단하고 가독성 좋게 변환할 수 있다.
단항 연산자(+)는 한 개의 피연산자, 즉 한 개의 인수와 짝을 이루어 역할을 합니다. 더하기를 의미하는 기존의 (+) 기호와는 달리, 숫자로 변환해주는 역할을 담당하는 단항 연산자 (+)는 인수의 바로 앞에 붙습니다. ECMA 공식 문서에 따르면 단항 연산자 (+)는 문자열인 인수를 숫자 형태로 빠르고 간단하게 바꾸어주는 문법입니다. 간단하게 형을 바꾸어준다는 장점이 있지만, 그렇게 할 수 없는 경우도 있기 때문에 각각의 경우를 알아보겠습니다.
문자열 앞에 단항 연산자 (+))를 붙여주면, 문자열을 숫자 타입으로 변환하여 리턴합니다. 문자열 뿐만 아니라 true, false, null값 또한 숫자 타입으로 변환합니다. 또 이진법과 16진법 수도 변환해줍니다. 다양한 경우에 어떤 숫자로 변환해주는지 알아봅시다.
console.log(+"10"); // 10
console.log(+"10.1");// 10.1
console.log(+"-10"); // -10
console.log(+true); // 1
console.log(+false); // 0
console.log(+0xBABE) // 47806 (Hexadecimal)
console.log(+null) // 0
원래 숫자일 경우에는 +를 붙여도 아무 변화가 없습니다. +를 붙인다는 것의 의미가 양수로 만들어준다는 뜻은 아닙니다.
const a = -10
console.log(+a); // -10
문자열의 내용에 해당하는 숫자를 합치려면, 예를 들어 "10"과 "25"를 합해서 "35"의 결과가 나오도록 하려면 각각 숫자로 변환한 후 더해야 합니다. 문자열 상태에서 더한다면 문자가 나열된 상태로 리턴되기 때문입니다. 예시를 보겠습니다.
let bread = "2500"
let cake = "30000"
console.log(+(bread+cake)) // 250030000
console.log(+bread + +cake) //32500
문자열을 숫자로 변경할 수 없다면 NaN (Not a Number)를 리턴합니다. 대표적으로 문자열, 또는 빈 문자열이나 함수, 빈 객체는 숫자로 변환할 수 없기 때문에 NaN으로 리턴합니다.
console.log(+"abc"); // NaN
console.log(+function(val) {return val}) // NaN
console.log(+'') // NaN
console.log(+'123a') // NaN
console.log(+{}) // NaN
이전에 작업한 가계부 앱에서 단항 연산자를 사용했습니다. 폼으로 사용자의 거래 날짜와 금액을 받은 후 그 값대로 sort 및 filter를 하기 위해 단항 연산자(+)를 활용했습니다. 그리고 나서 사용자가 선택한 수입 또는 지출 선택지에 따라 따로 + 또는 - 기호를 붙여주었습니다.
//Add transaction
const addTransaction = (e) => {
e.preventDefault()
//Generate random ID
const generateID = () => Math.floor(Math.random() * 100000000)
if (text.value.trim() === '' || amount.value.trim() === '') {
alert('내역과 금액을 모두 입력해주세요.')
} else {
const sign = radio[0].checked === true ? '+' : '-'
const transaction = {
id: generateID(),
text: text.value,
amount: +`${sign}${amount.value}`,
date: +`${yearInput.value}${monthInput.value}${dayInput.value}`
}
transactions.push(transaction) //add the transaction into the transactions array
updateValues() // update the calculated transaction
radio[0].checked = false
radio[1].checked = false
yearInput.value = ''
monthInput.value = ''
dayInput.value = ''
text.value = ''
amount.value = ''
updateLocalStorage()
init()
}
}
//Sort by date
const sortByDate = () => {
return transactions.sort((a, b) => {
if (a.date > b.date) {
return 1
} else if (a.date < b.date) {
return -1
} else {
return 0
}
})
}
//Rendering storage data
const renderTransactions = () => {
if (sort_plus.classList.contains('sort')) {
list.innerHTML = ''
const incomeTransactions = transactions.filter((transaction) => transaction.amount > 0)
incomeTransactions.forEach((transaction) => {
addTransactionDOM(transaction)
})
} else if (sort_minus.classList.contains('sort')) {
list.innerHTML = ''
const expenseTransactions = transactions.filter((transaction) => transaction.amount < 0)
expenseTransactions.forEach((transaction) => {
addTransactionDOM(transaction)
})
}
}
//Update the balance, income and expense
const updateValues = () => {
//map() method result array
const amounts = transactions.map((transaction) => transaction.amount)
const total = amounts.reduce((acc, item) => (acc += item), 0)
const income = amounts
.filter((item) => item > 0)
.reduce((acc, item) => (acc += item), 0)
const expense = amounts
.filter((item) => item < 0)
.reduce((acc, item) => (acc += item), 0)
balance.innerText = `₩${numberWithCommas(total)}`
money_plus.innerText = `${numberWithCommas(income)}`
money_minus.innerText = `-${numberWithCommas(Math.abs(expense))}`
}