몇일 전 개발을 하다가 JSON파일의 number
타입의 id
의 값을
컴포넌트의 id
값으로 할당하고 다시 JSON파일 속 id
와 비교를 할 때 엄청난 애를 먹은적이있다.
filter를 이용해서 걸러내려는 함수를 작성했는데 콘솔에 같은 값이 찍히는대도 불구하고
filter함수가 걸러내질 못했다. 콘솔을 좀 더 잘 확인했다면 따옴표를 잘 보고 타입이 달랐다는 것을 알 수 있었겠지만 그거 하나 못봐서 3시간을 고생했다. (좀 더 꼼꼼히 확인하자)
너무나도 당연한 것이지만 HTML의 속성으로 부여된 id의 값은 string이라는 것을 간과해버렸다.
(할당한 id가 숫자 타입이라 당연 숫자로 인식되는줄 ㅠ)
위 3시간의 삽질 아닌 삽질은 무한의 스트레스를 주었고 동시에 자괴감과 자존감을 바닥으로 짖눌러 버렸다.
하지만 다음 날 긍정적인(이라고 쓰고 생각없는 이라고 말하는) 마인드로 덕분에 다시한번 자바스크립트 데이터 타입을 공부해봐야 겠다는 생각이 들어 다행이라고 결론짓고
이 참에 한번 간략하게 정리해보려한다.
변수를 선언하고 값을 할당할 때 어떤일이 일어나고 후에 변수 값을 참조할 때 어떤 식으로 이루워지는지 간략하게 알아보기.
프로그래밍은 변수를 통해 값을 저장하고 참조한다고 한다. 그래서 그 변수는 값의 위치를 나타내는 인간의 언어라고 한다. 변수를 할당했는데 값의 위치를 나타낸다니 정말 웃기는 짬뽕이다.
그 말인 즉슨 할당이라는 코드가 작성되면 컴퓨터는 어느 저장소 한곳에 그 값을 저장하는데
변수가 그 값을 가지고 있는 것이 아니라 메모리상에 값이 저장된 저장소의 위치를 가지고 또는 가르키고 있는 것이다. (여태까지 가지고 있는줄)
let bar = 1
이라고 선언 할당을 하면 bar
의 값은 1 이지만 사실상 딥하게 bar
를 파보면 컴퓨터의 언어로 본인이 저장한 저장소의 1이 어디에 저장되어있는지 위치를 알려주는 것이다.
더 나아가 메모리에 값을 저장하려면 먼저 메모리 공간을 확보하는데 이는 데이터 타입에 따라 다르다고 한다. 구글에 관련한 것들을 검색해보면 컴퓨터 공학적인 이야기가 엄청 나오는데
다 각설하고 자바스크립트에 관해서만 알아보자.
자바스크립트는 동적인 언어이다. 그래서 타입들 또한 동적인데 이 말인 즉슨 다른 언어들은 (사용안해봐서 잘 모르지만 this is what google says)
선언과 함께 데이터 타입을 알려준다고 한다고 알고있다.
하지만 자바스크립트는 그런것이 없다. 그냥 내가 string이든 number든 할당하고 싶은 것들을 선언과 함께 할당해주면 알아서 잘 인식해준다.
자바스크립트는 변수의 타입지정이 따로 없이 값을 할당하는 과정에서 자동으로 알아서 변수의 타입을 결정한다. 그래서 자유롭게 재 할당이 가능한 것이다.
(그래서 Typescript가 대세로 떠오르고 있는것인가?)
어쨋든 자바스크립트는 선언과 할당 과정에서 별도의 타입 지정이 없이 타입 추론을 통해 알아서 결정해준다. 그렇기 때문에 자바스크립트 데이터 타입에 대해서 깊에 공부를 해보려 생각하지 않았나보다 (변명)
그럼 알아서 일어나는 자바스크립트의 데이터 타입 할당(?)을 조금 더 발전시켜서 공부해보자.
어떤 데이터 타입이 존재하고 할당될 때 변수는 그것들을 어떻게 사용하는 것인지.
크게 원시타입(primitive data type)과 객체(object/reference type)으로 나뉜다.
원시 타입이란 변경 불가능한 값이며 값에 의해 전달된다.
여기서 변경 불가능한 값이란 뜻은 immutable의 해석으로써 컴퓨터가 한번 데이터를 저장소에 저장하면
나중에 변수에 다른 원시타입의 값이 할당 되었을 때 저장된 위치의 값을 바꾸는 것이 아니라
저장소의 새로운 위치에 값을 저장하고 그 주소를 변수가 갖는다는 뜻이다.
간단한 예를 보면
//foo라는 변수에 숫자 1 할당.
let foo = 1
//...
//foo라는 변수에 숫자 20 재할당
foo = 20
이런식으로 foo
에 1을 할당하고 나중에 20을 다시 할당한다고 가정해보자.
처음 코드를 읽어들일때 1은 메모리에 할당된다.
그리고 그 메모리의 위치를, 예를 들어, 100이라고 가정하자.
그 후에 foo
를 사용하게 되면 컴퓨터는 메모리의 100 이라는 위치에서 그 값을 가져와서 사용하는 것이다.
만약 나중에 foo
에 20을 재 할당하면 어떻게 될까?
컴퓨터는 메모리에서 100이라는 위치를 찾아가서 1을 20으로 바꾸는 것이 아니라
메모리의 새로운 위치에 20을 저장하고 변수 foo
에 그 위치값을, 예를 들어, 200 이라면 200을 저장한다.
이것이 불변성 immutable이다. (리액트에서 state관리할 때 정말 중요한 개념 + 배열과 객체인 데이터 가공시에도 매우 중요 )
원시 타입 데이터들은 할당된 값, 즉 원시 값을 직접 변형할 수 없고 대신 교체가 가능한 것이다.
반대로 뒤에서 살펴볼 mutable은 직접 변형이 가능하다. 물론 교체도 가능하지만 이로 인해 원본이 훼손되는 (의도치 않게) 경우가 발생한다.
특히 리액트에서는 state의 데이터를 mutate 하는 경우 리랜더링이 일어나지 않는 일도 발생한다.
그렇기 때문에 setState
를 이용해야하며 직접적으로 state의값을 건들여서는 안된다.
자세한건 나중에 mutation rhk non-mutation을 정리하며 알아볼 것인데
어쨋든 배열과 객체도 똑같이 key의 value에 대해서 모두 메모리의 위치값을 가지고 있기 때문에 shallow copy를 하여 값을 변경하거나 변형시키면 원본도 훼손된다.
여튼 좀 많이 조심해야한다. 내장 함수들 중에서도 배열과 객체를 mutate과 non-mutate하는 함수로 분류된다. (암튼 나중에 더 deep 하게 정리)
여튼 이런 원시 타입들은
boolean
null
undefined
number
string
symbol (ES6에서 추가)
이 있다.
데이터 타입에 대해서는 이름만 봐도 알 수 있으니 깊게 정리하지 않고 특징 몇개만 짚어서 같이 정리해보자.
기본적으로 자바스트립트는 이진수로 숫자를 저장한다고 한다.
정수만을 위한 타입이 없고 실수라는데 아마 10 이라는 숫자도 10.000000 이런식으로 인식한다는 뜻인것 같다.
그럼 소수점 몇까지 똑같은지 실험을 해봐야겠다.
console.log(10 === 10.000000000000001)
// false
console.log(10 === 10.0000000000000001)
// true
소수점 15번째 자리까지만 인식가능하다.
그럼 다음 경우는 어떨지 생각해보자.
console.log(0.3 === 0.1+0.2)
// true? false?
답은 false 이다. 인터넷에 찾아보니 0.2의 2진수 표현이 정확하지 않다던데
이부분은 수학적으로 공부가 더 필요하다.
아무튼 소수점을 비교할때는, 그리고 사용할 때는 조심하고 좀 더 알아보면서 사용해야한다.
그리고 string은 문자열이다. 즉 따옴표안에 적힌애들은 모두 문자열인데
특이한 것이 문자열과 숫자의 연산에서 웃긴 결과가 나온다.
console.log("1"+1)
//11
console.log("1"-1)
//0
console.log(1+"1")
//11
console.log(1-"1")
//0
console.log(-1+"1")
//-11
console.log(-1-"1")
//-2
console.log(-"1"+"1")
//-11
console.log(-"1"-"1")
//-2
console.log(-"1"+1)
//0
console.log(-"1"-1)
//-2
console.log(+"1"+1)
//2
console.log(+"1"+1)
//2
자바스크립트는 숫자로 이루어진 string을 연산하려 할때 기본적으로 숫자로 치환해서 연산한다고 한다.
하지만 +를 만나는 경우 문자열 합성 기능이 있어서 문자열로 합성을 먼저 고려한다고 한다.
true와 false를 나타내는 값이다.
값이 할당되면 true가 되고 할당이 안되어 있으면 false이다.
또한 그냥 하나의 변수에 true/false를 할당도 가능하다.
"", undefined, null, 0은 false이다.
즉 0,"", undefined, null이 할당된 값은 boolean check에서 false이다.
원시타입을 제외한 나머지 값들인데
배열, 함수, 정규표현식 그리고 객체 타입인데 통괄적으로 객체타입으로 생각하면 된다.
간단하다.
이 다음에는 var let const와 호이스팅에 대해서 알아보고
그 다음에 더 ellaborate해서 스포크, 렉시컬, 클로저 그리고 실행문맥을 묶어서 알아보자