변수, 데이터타입

변수

ECMAScript는 느슨한 변수 타입을 사용합니다.
변수에 어떤 타입의 데이터라도 저장할 수 있다는 의미입니다.
변수를 정의할 때는 var 연산자 다음에 변수 이름을 씁니다.
var는 키워드이며 변수 이름은 식별자입니다.

var message;

message라는 변수를 정의하였으며 이 변수에는 어떤 값이든 할당 할 수 있습니다.
변수를 초기화 하지 않으면 undefined가 할당되게 됩니다.

초기화는 아래와 같이 할 수 있습니다.

var message = "hi";

변수 선언과 동시에 문자열값 hi를 저장하였습니다.
이를 초기화라고 합니다.

변수에 값을 지정했다고 변수 타입이 고정이 되는것은 아닙니다.

var message = "hi";
message = 100;

위와같이 문자열에서 숫자형으로 덮어 써지는게 가능합니다.
물론 변수의 데이터 타입을 저런식으로 바꾸는 행위는 권장하지 않으나 ECMAScript에서는 유효합니다.

var연산자는 로컬스코프에서 정의합니다.

function test(){
    var message = "hi";     //변수선언
}
test();
alert(message);     //오류발생

message변수가 함수 내부에 정의되어있기 때문에 test() 함수를 호출 하면 test변수가 생성되고 함수종료와 함께 파괴됩니다.
함수 종료 후 alert()에서 message 호출 시 message는 이미 파괴되었기 때문에 오류가 발생합니다.

var연산자를 생략하면 변수를 전역으로 지정할 수 있습니다.

function test(){
    message = "hi";     //전역 변수
}
test();
alert(message);     // "hi" 출력

var연산자가 제거됨으로써 message는 전역 변수가 되었습니다.
test()함수가 종료되어도 파괴되지 않으므로 이후 alert()에서 호출이 가능해집니다.

변수 여러개 선언

쉼표(,)를 이용하여 한문장에서 여러 변수를 선언 할 수 있습니다.

var message = "hi",
    found = false,
    age = 25;

변수를 3개 선언하고 초기화 하였습니다.
느슨한 타입을 사용하기 때문에 변수의 데이터타입이 서로 달라도 같은 문장에서 선언이 가능한 특징이 있습니다.

데이터 타입

ECMAScript에는 다섯가지 기본적인 데이터 타입이 존재합니다.
이를 원시 데이터 타입(primitive data type)이라고 부르기도 합니다.

- Undefined
- Null
- Boolean
- Number
- String

그 외에도 객체(키-값)라는 데이터 타입도 있습니다.

ECMAScript에서는 개발자가 데이터 타입을 정의할 수 없으므로 모든 데이터는 위에 나열한 여섯가지 타입중 하나에 속합니다.

typeof 연산자

느슨한 타입을 사용하기 때문에 변수의 데이터 타입을 알아야 할 때가 있습니다.

정의되지 않은 변수 - undefined
불리언 - boolean
문자열 - string
숫자 - number
함수를 제외한 객체 또는 null - object
함수 - function

아래 예제를 봅시다

var message = "some string";
alert(typeof message); // string
alert(typeof(message)); //string
alert(typeof 95) // number

typeof는 함수가 아니라 연산자이기 때문에 괄호를 쓰지 않아도 됩니다.
typeof null은 object를 반환하는데 null은 빈 객체를 참조하는 특별한 값이므로 이는 올바른 것입니다.

undefined타입

undefined라는 값은 특별한 값입니다.
var를 써서 변수를 정의했지만 초기화하지 않은경우 undefined가 할당됩니다.

var message;
alert(message == undefined); //true

var message2 = undefined;
alert(message2 = undefined); //true

추가로
변수를 생성하지 않을경우 오류가 발생하지만 생성하지 않은 변수에 대해서 typeof 연산자를 사용할 경우 undefined를 떨어뜨리게 됩니다.
이해가 잘안되는 부분인데 아래 예제를 봅시다.

var message;
//var age 
//위 변수는 주석처리 했기 때문에 선언되지 않았습니다.

alert(typeof message); // undefined
alert(typeof age); //undefined

두 경우 모두 undefined를 반환합니다.

null 타입

Null타입은 값하나만을 갖습니다.
null은 빈 객체를 가리키는 포인터이므로 null에 typeof를 호출함녀 다음 예제처럼 object를 반환합니다.

var car = null;
alert(typeof car); //object

변수를 정의할 때 해당 변수가 객체를 가리키게 할 생각이라면 null로 초기화 하길 권합니다.
그렇게 한다면 아래와같은 방법으로 해당 변수가 객체를 가리키는지 명시적으로 확인 할 수 있습니다.

if(car != null){
    //car를 사용하는 코드
}

undefined는 null에서 파생했으므로 두 값은 동일한 것으로 정의합니다.

alert(null == undefined); //null

하지만 null과 undefined가 서로 관련되어 있긴 하지만 두 값은 아주 다르게 쓰입니다.
위에서 언급한 내용이지만
변수의 값에 명시적으로 undefined를 할당해서는 안되며, null은 위와같이 객체를 사용해야 하지만 사용할 수 없을 때는 null을 사용합니다.
이렇게 하면 null이 빈 객체를 가리키는 포인터라는 점을 늘 숙지할 수 있고 undefined와 구별할 수 있습니다.

불리언 타입

true, false 두가지 리터럴 값을 가지는 데이터 타입입니다.

ECMAScript에서는 모든 타입을 불리언 값으로 표현할 수 있으며 Boolean()함수를 사용합니다.

var message = "hello world";
var messageAsBoolean = Boolean(message);

위예제에서는 문자일이 boolean값으로 변환되어 저장됩니다.
아래는 변환 규칙입니다.

데이터 타입truefalse
불리언truefalse
문자열비어있지 않은 문자열 모두“”(빈문자열)
숫자0이 아닌 모든 숫자. 무한대 포함0, NaN
객체모든 객체null
Undefined해당 없음undefined

if문 같은 제어문은 위와같이 타입을 자동으로 불리언으로 변경하므로 위에 규칙을 숙지하고 있어야 합니다.

숫자타입

아래와 같이 진법별로 사용할 수 있습니다.

var intNum = 55; //정수

var octalNum1 = 070; // 8진법으로 쓴 56
var octalNum2 = 079; // 9가 범위를 벗어났으므로 79로 간주
var octalNum3 = 08; // 8이 범위를 벗어났으며 8로 간주

var hexNum1 = 0xA; //10의 16진수 표기
var hexNum2 = 0x1f; // 31의 16진수 표기

참고로 strict mode에서는 8진법 리터럴을 허용하지 않으며 문법에러를 반환합니다.

부동소수점

var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; //유효하지만 권장하지 않음

위와같이 저장할 경우 2배의 메모리는 사용한다는 걸 기억합시다.

ECMAScript는 가능하면 정수로 저장하려고 합니다.

var floatNum1 = 1.; // 소수점 뒤에 숫자가 없으므로 1로 간주
var floatNum2 = 10.0; // 전체 숫자 표기법이며 10으로 간주

위의 예제는 정수로 변환됩니다.

지수 표기법

var floatNum = 3.125e7; // 31,250,000

부동소수점을 사용 시 주의 사항이 있습니다.
예를들면 0.1과 0.2를 더하면 0.3이 아닌 0.3000000000000000004를 반환합니다.
이런 반올림 에러 때문에 부동소수점 숫자를 평가하기가 어려우므로 사용에 주의가 필요합니다.
인지해 놓읍시다

숫자 범위

메모리 제한 때문에 자연계에 존재하는 모든 숫자를 나타낼 수 없습니다.
최소값 최대값은 Number객체를 이용하여 확인 할 수 있습니다.

alert(Number.MAX_VALUE);
alert(Number.MIN_VALUE);

이런 최대값 최소값을 벗어날 경우, 최대값은 특별한 값인 Infinity 최소값은 -Infinity로 변환됩니다.
이 값이 된다면 더 이상 계산에 사용 할 수 없습니다.
대단히 큰 숫자나 대단히 작은 숫자를 계산할 때는 반드시 체크합시다.

NaN

숫자형 값중 NaN(Not a Number)라는 특별한 값이 존재합니다.
이 값은 숫자를 반환할 것으로 의도한 조작이 실패했을 때 반환되는 값입니다.
ECMAScript에서는 숫자를 0으로 나누면 NaN을 반환하고 나머지 처리는 계속 수행합니다.
NaN에는 몇가지 특징이 있습니다.

  • NaN이 포함된 조작은 항상 NaN을 반환합니다. ex) NaN / 10 = NaN
  • NaN은 어떤 값과도 일치하지 않습니다. NaN끼리도 일치하지 않습니다. ex) NaN == NaN -> false
    이 때문에 ECMAScript는 isNaN() 함수를 따로 제공합니다.
    이 함수는 매개변수를 하나 받으면 ‘숫자가 아닌 값’인지 검사합니다.
    아래 예제를 봅시다
    alert(isNaN(NaN));     // true
    alert(isNaN(10));        // false - 10은 숫자
    alert(isNaN("10"));     // false - 숫자 10으로 변경가능
    alert(isNaN("blue")); // true - 숫자로 변경 불가능
    alert(isNaN(true));    // false - 숫자 1로 변경 가능
    

숫자 변환

숫자가 아닌 값을 변경하는 함수는 세가지가 있습니다

  • Number()
  • parseInf()
  • parseFloat()

Number()는 다양한 규칙을 사용하기 때문에 데이터 타입을 숫자로 변환하는 일은 혼란스럽습니다.
그런이유로 인해 보통 parseInt()를 사용합니다.

var num1 = Number("Hello world!"); //NaN
var num2 = Number(""); //0
var num3 = Number("000011"); //11
var num4 = Number(true); //1

var num1 = parseInt("1234blue"); //1234
var num2 = parseInt(""); //NaN
var num3 = parseInt("0xA"); //10 - hexadecimal
var num4 = parseInt(22.5); //22
var num5 = parseInt("70"); //70 - decimal
var num6 = parseInt("0xf"); //15 hexadecimal

var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN

var num1 = parseInt("10", 2); //2 - parsed as binary
var num2 = parseInt("10", 8); //8 - parsed as octal
var num3 = parseInt("10", 10); //10 - parsed as decimal
var num4 = parseInt("10", 16); //16 - parsed as hexadecimal

var num1 = parseFloat("1234blue"); //1234 - integer
var num2 = parseFloat("0xA"); //0
var num3 = parseFloat("22.5"); //22.5
var num4 = parseFloat("22.34.5"); //22.34
var num5 = parseFloat("0908.5"); //908.5
var num6 = parseFloat("3.125e7"); //31250000

문자열 타입

문자열은 16비트 유니코드 문자의 연속입니다.
큰따옴표(“)나 작은따옴표(‘)로 감싸서 표현합니다.
큰따옴표와 작은따옴표의 차이는 없으며, 따옴표의 짝을 맞추지 않을 경우 오류가 발생합니다.

문자 리터럴

리텉럴의미

\n

줄바꿈

\t
\b백스페이스
\r캐리지 리턴
\f폼 피드
\역슬래시()
\’작은 따옴표로 감싼 문자열 안에서 작은 따옴표 표시
\”큰 따옴표로 감싼 문자열 안에서 큰 따옴표 표시
\xnn16진수 코드 ‘nn’로 표시 ex)\x41 => A
\unnn16진수코드 nn으로 표현한 문자입니다. 16진수코드에 할당된 문자열이 표시됩니다.

이런 리터럴 문자는 한 문자로 취급됩니다.
이를테면 length프로퍼티로 길이를 얻을 때 리터럴 문자가 있을 경우, 문자열에는 \’로 2글자 들어가있지만 ‘로 취급되어 \’가 한글자로 카운트됩니다.

문자열의 성질

문자열은 불변입니다 즉 문자열이 만들어지면 그 값을 바꿀 수 없으며 변수에 저장한 문자열을 바꿀 경우 기존의 문자열을 파괴하고 새문자열을 채워야합니다.

문자열로 변환

toString() 메서들을 사용하여 다른 형식의 값을 문자열로 변경 할 수 있습니다.
toString() 메서드는 숫자, 불리언, 객체, 문자열 값에 존재하며 (문자열에도 있으며 단순히 자신을 복제하여 반환합니다) null과 undefined에는 존재하지 않습니다.

숫자의 경우 매개변수를 하나 쓸 수 있는데 진법에 관련된 반환을 선택 할 수 있습니다. 아래 예제를 보시겠습니다.

var num = 10;
console.log(num.toString()); //"10"
console.log(num.toString(2)); //"1010"
console.log(num.toString(8)); //"12"
console.log(num.toString(10)); //"10"
console.log(num.toString(16)); //"a"

위와같이 매개변수를 사용하여 숫자 10을 어떤 진법으로도 표현할 수 있습니다.

toString()메서드가 호출할 값이 null이나 undefined일 경우 타입에 관계없이 항상 문자열을 반환하는 String()을 사용해도 됩니다.
String() 함수는 다음규칙을 따릅니다.

- 값에 toString()메서드가 존재할 경우 이를 매개변수 없이 호출하여 그 결과를 반환합니다.
- 값이 null이라면 "null"을 반환합니다.
- 값이 undefined라면 "undefined"를 반환합니다.

toString()과 같지만 null과 undefined에 대한 문자열 반환 처리가 추가되어 있습니다.

객체 타입

ECMAScript에서 객체는 데이터와 기능의 집합입니다.
객체는 new 연산자 다음에 새로 만들 객체 타입의 이름을 써서 만듭니다.

var o = new Object();

다음과 같이 인스턴스를 생성하고 프로퍼티나 메서드를 추가하여 객체를 만들 수 있습니다.
괄호의 경우 없어도 되지만 권장하지 않으니 넣어줍시다.

Object의 인스턴스는 다음 프로퍼티와 메서드를 가집니다.

  • constructor : 해당 객체를 만드는 데 쓰인 함수. 위 예제의 Object() 함수가 생성자입니다.
  • hasOwnProperty(propertyName) : 해당 프로퍼티가 객체 인스턴스에 고유하여 프로토타입에서 상속하지 않음을 확인합니다. 프로퍼티 이름은 반드시 문자열이여야 합니다. o.hasOwnProperty(“name”)과 같은 형식으로 호출합니다.
  • isPrototypeOf(object) : 해당 객체가 다른 객체의 프로토타입인지 확인합니다.
  • propertyIsEnumerable( propertyName ) : 해당 프로퍼티를 for-in 문에서 나열할수 있는지 확인합니다.
  • toLocaleString() : 객체를 지역에 맞게 표현한 문자열을 반환합니다.
  • toString() : 객체를 문자열로 반환해 반환합니다.
  • valueOf() : 객체를 나타내는 문자열이나 숫자, 불리언을 반환합니다. toString()과 같은 값을 반환할 때가 많습니다.

프로토타입에 관련하여는 추후 포스트에서 다룰예정입니다. 우선은 머리가 아파지기 시작하니 이런게 있구나~ 하고 넘어갑시다.

마치며

변수와 각종 데이터 타입에 대해서 알아보았습니다.
자바스크립트 자체가 느슨한 언어인 만큼, 위에서 설명한 규칙을 예제와 함께참고 및 숙지하고 있어야 추후 개발 시 데이터를 다룰 때 발생하는 혼란스러움을 다소 방지할 수 있을 것입니다.
다음 포스트에서는 연산자에 대해서 알아보겠습니다.

이 포스트는 프론트엔드 개발자를 위한 자바스크립트(인사이트)에서 발췌한 내용이 포함되어 있습니다.
내용 전문이 아니기 때문에 자세하게 알고싶으신 분은 프론트엔드 개발자를 위한 자바스크립트(인사이트) 서적을 참고 하시길 바랍니다.