Skip to content

Latest commit

 

History

History
459 lines (315 loc) · 21.7 KB

03_js_data_type_operators.md

File metadata and controls

459 lines (315 loc) · 21.7 KB

03. 자바스크립트 데이터 타입과 연산자

인사이드 자바스크립트

3-1 기본 타입

  • 자바스크립트에서 기본 타입은 숫자, 문자열,불린값을 비롯해 nullundefined라는 타입이 있다. 그 자체가 하나의 값을 타나낸다.
  • typeof 연산자는 피연산자의 타입을 리턴한다.
  • 자바스크립트는 느슨한 타입 체크 언어다.
  • var라는 한 가지 키워드로만 변수를 선언한다. 따라서 변수에 어떤 형태의 데이터를 저장하느냐에 따라 해당 변수의 타입이 결정된다.

3-1-1 숫자

  • 자바스크립트는 하나의 숫자형만 존재한다. 모든 숫자를 64비트 부동 소수점 형태로 저장하기 때문이다. c언어의 double 타입과 유사하다.

  • 자바스크립트에서는 정수형이 따로 없고, 모든 숫자를 실수로 처리하므로 나눗셈 연산을 할 때는 주의해야 한다.

  • 나눗셈 결과의 정수 부분만을 구하고 싶다면, Math.floor() 자바스크립트 메서드를 사용하면 된다.

3-1-2 문자열

  • 문자열은 ', " 로 생성한다.
  • char 타입과 같이 문자 하나만을 별도로 나타내는 데이터 타입은 존재하지 않는다.
  • 주의해야 할 점은 한 번 정의된 문자열은 변하지 않는다는 것이다.
  • 자바스크립트에서는 한 번 생성된 문자열은 읽기만 가능하지 수정은 불가능하다.

3-1-3 불린값

  • 자바스크립트는 true와 false 값을 나타내는 불린 타입을 가진다.

3-1-4 null과 undefined

  • 이 두 타입은 모두 자바스크립트에서 '값이 비어있음'을 나타낸다.
  • 기본적으로 값이 할당되지 않은 변수는 undefined 타입이며, undefined 타입의 변수는 변수 자체의 값 또한 undefined이다.
  • 이처럼 자바스크립트에서는 undefined는 타입이자, 값을 타나낸다는 것에 주의하자
  • nullVar와 같이 null 타입 변수의 경우는 개발자가 명시적으로 값이 비어있음을 나타내는 데 사용한다.
  • 여기서 주의할 점은 null 타입 변수인 nullVar의 typeof 결과가 null이 아니라 object라는 것이다.
  • 때문에 다음 예제와 같이 자바스크립트에서는 null 타입 변수인지를 확인할 때 typeof 연산자를 사용하면 안 되고, 일치 연산자(===)를 사용해서 변수의 값을 직접 확인해야 한다.
var nullVar = null;

console.log(typeof nullVar === null);  //false
console.log(nullVar === null);         //true

3-2 자바스크립트 참조 타입(객체 타입)

자바스크립트에서 숫자, 문자열, 불린값, null, undefined 같은 기본 타입을 제외한 모든 값은 객체다. 따라서 배열, 함수, 정규표현식 등도 모두 결국 자바스크립트 객체로 표현된다.

자바스크립트에서 객체는 단순히 key:value 형태의 프로퍼티들을 저장하는 컨테이너로서, 컴퓨터 과학 분야에서 해시라는 자료구조화 상당히 유사하다. 자바스크립트에서 기본 타입은 하나의 값만을 가지는 데 비해, 참조 타입인 객체는 여러 개의 프로퍼티들을 포함할 수 있으며, 이러한 객체의 프로퍼티는 기본 타입의 값을 포함하거나, 다른 객체를 가리킬 수도 있다. 이러한 프로퍼티의 성질에 따라 객체의 프로퍼티는 함수로 포함할 수 있으며, 자바스크립트에서는 이러한 프로퍼티를 메서드라고 부른다.

3-2-1 객체 생성

자바에서는 클래스를 정의하고, 클래스의 인스턴스를 생성하는 과정에서 객체가 만들어진다. 이에 비해 자바스크립트에서는 클래스라는 개념이 없고, 객체 리터럴이나 생성자 함수 등 별도의 생성 방식이 존재한다.

자바스크립트에서 객체를 생성하는 방법은 크게 세 가지가 있다. 하나는 기본 제공 Object() 객체 생성자 함수를 이용하는 방법, 그리고 객체 리터럴을 이용하는 방법, 다른 하나는 생성자 함수를 이용하는 방법이다.

3-2-1-1 Object() 생성자 함수 이용

var foo = new Object();

foo.name = 'foo';
foo.age = 30;
foo.gender = 'male';

console.log(typeof foo); //(출력값) object

3-2-1-2 객체 리터럴 방식 이용

객체 리터럴은 중괄호 ( { } )를 이용해서 객체를 생성한다. { } 안에 아무것도 적지 않은 경우는 빈 객체가 생성되며, 중괄호 안에 "프로퍼티 이름":"값" 형태로 표기하면, 해당 프로퍼티가 추가된 객체를 생성할 수 있다. 여기서 프로퍼티 이름은 문자열이나 숫자가 올 수 있다. 프로퍼티 값으로는 자바스크립트의 값을 나타내는 어떤 표현식도 올 수 있으며, 이 값이 함수일 경우 이러한 프로퍼티를 메서드라고 부른다.

var foo = {
  name : 'foo',
  age : 30,
  gender : 'male'
};

3-2-1-3 생성자 함수 이용

함수를 통해서도 객체를 생성할 수 있다. 이렇게 객체를 생성하는 함수를 생성자 함수라고 부른다. 뒤에서 자세히 살펴본다.

3-2-2 객체 프로퍼티 읽기/쓰기/갱신

  • 객체의 프로퍼티에 접근하려면 다음과 같이 두 가지 방법을 사용한다.

    • 대괄호([])표기법
    • 마침표(.) 표기법
  • 자바스크립트 객체의 프로퍼티에 값을 할당할 때, 프로퍼티가 이미 있을 경우는 해당 프로퍼티의 값이 갱신되지만, 객체의 해당 프로퍼티가 없을 경우에는 새로운 프로퍼티가 동적으로 생성된 후 값이 할당된다.

  • 프로퍼티 명이 'full-name'일 경우 '-'연산자가 있는 표현식이므로 대괄호 표기법만을 이용해서 foo['full-name'] 형태로 프로퍼티에 접근해야 한다. foo.full-name 표기법을 사용하는 경우, 엉뚱하게 NaN 값이 출력된다.

NaN(Not a Number) 값

자바스크립트에서 NaN(Not a Number)은 수치 연산을 해서 정상적인 값을 얻지 못할 때 출력되는 값이다.

3-2-3 for in 문과 객체 프로퍼티 출력

for in 문을 사용하면, 객체에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있다.

var prop;

for (prop in foo) {
  console.log(prop, foo[prop]);
}
name foo
age 30
gender male

3-2-4 객체 프로퍼티 삭제

자바스크립트에서는 객체의 프로퍼티를 delete 연산자를 이용해 즉시 삭제할 수 있다. 여기서 주의할 점은 delete 연산자는 객체의 프로퍼티를 삭제할 뿐, 객체 자체를 삭제하지는 못한다는 것이다.

delete foo.gender; //gender 프로퍼티 삭제

3-3 참조 타입의 특성

자바스크립트에서는 기본 타입인 숫자, 문자열, 불린값, null, undefined 5가지를 제외한 모든 값은 객체다. 배열이나 함수 또한 객체로 취급된다. 그리고 이러한 객체는 자바스크립트에서 참조타입이라고 부른다. 이것은 객체의 모든 연산이 실제 값이 아닌 참조값으로 처리되기 때문이다.

3-3-1 객체 비교

동등 연산자(==)를 사용하여 두 객체를 비교할 때도 객체의 프로퍼티값이 아닌 참조값을 비교한다는 것에 주의해야 한다.

3-3-2 참조에 의한 함수 호출 방식

기본 타입과 참조 타입의 경우는 함수 호출 방식도 다르다. 기본 타입의 경우는 값에 의한 호출(Call By Value) 방식으로 동작한다. 즉, 함수를 호출할 때 인자로 기본 타입의 값을 넘길 경우, 호출된 함수의 매개변수로 복사된 값이 전달된다. 때문에 함수 내부에서 매개변수를 이용해 값을 변경해도, 실제로 호출된 변수의 값이 변경되지 않는다.

이에 반해 객체와 같은 참조 타입의 경우 함수를 호출할 때 참조에 의한 호출(Call By Reference)방식으로 동작한다. 즉, 함수를 호출할 때 인자로 참조 타입인 객체를 전달할 경우, 객체의 프로퍼티값이 함수의 매개변수로 복사되지 않고, 인자로 넘긴 객체의 참조값이 그대로 함수 내부로 전달된다. 때문에 함수 내부에서 참조값을 이용해서 인자로 넘긴 실제 객체의 값을 변경할 수 있다.

var a = 100;
var objA = {value: 100};

function changeArg(num, obj) {
  num = 200;
  obj.value = 200;

  console.log(num);
  console.log(obj);
}

changeArg(a, objA);

console.log(a);
console.log(objA);
200
{ value: 200 }
100
{ value: 200 }

3-4 프로토타입

자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있다. 그리고 이것은 마치 객체지향의 상속 개념과 같이 부모 객체의 프로퍼티를 마치 자신의 것처럼 쓸 수 있는 것 같은 특징이 있다. 자바스크립트에서는 이러한 부모 객체를 프로토타입 객체라고 부른다.

var foo = {
  name: 'foo',
  age: 30
};

console.log(foo.toString()); //1
console.dir(foo);            //2
  • 1 : 1에서 리터럴 방식으로 foo 객체를 생성하고, 이 객체의 toString() 메서드를 출력한 것이다. 객체에 toString() 메서드가 없으므로 에러가 발생하야 하지만 그렇지 않고 정상적으로 실행될 수 있는 이유는 foo 객체의 프로토타입에 toString() 메서드가 이미 정의되어 있고, foo 객체가 상속처럼 toString() 메서드를 호출했기 때문이다.
  • 2 : 크롬 개발자 도구에서 객체를 출력해보면, __proto__ 프로퍼티가 있는 것을 확인할 수 있다. 이것이 foo객체의 부모인 프로토타입 객체를 가리킨다.

모든 객체의 프로토타입은 자바스크립트의 룰에 따라 객체를 생성할 때 결정된다. 이에 대해서는 프로토타입 체이닝을 학습할 때 자세히 알아본다. 우선 객체 리터럴 방식으로 생성된 객체의 경우 Object.prototype 객체가 프로토타입 객체가 된다는 것이 중요하다.

참고로 __proto__ 프로퍼티가 가리키는 객체가 Object.prototype 객체이며, toString(), valueOf() 등과 같은 모든 객체에서 호출 가능한 자바스크립트 기본 내장 메서드가 포함되어 있다. 그 결과 foo 객체는 자신의 프로토타입인 Object.prototype 객체에 포함된 다양한 메서드를 마치 자신의 프로퍼티인 것처럼 상속받아 사용할 수 있다.

3-5 배열

배열은 자바스크립트 객체의 특별한 형태다. 굳이 크기를 지정하지 않아도 되며, 어떤 위치에 어느 타입의 데이터를 저장하더라도 에러가 발생하지 않는다.

3-5-1 배열 리터럴

배열리터럴은 새로운 배열을 만드는 데 사용하는 표기법이다. 객체 리터럴이 중괄호( {} )를 이용한 표기법이었따면, 배열은 대괄호( [] )를 사용한다.

var colorArr = ['black', 'blue', 'violet', 'white'];

3-5-2 배열의 요소 동적 생성

객체가 동적으로 프로퍼티를 추가할 수 있듯이, 배열도 동적으로 배열 원소를 추가할 수 있다. 특히, 자바스크립트 배열의 경우는 값을 순차적으로 넣을 필요 없이 아무 인덱스 위치에나 값을 동적으로 추가할 수 있다. 비어있는 곳은 빈 채로 있다.

  • 배열 또한 자바스크립트 객체이기 때문에 객체에서도 포함하지 않은 객체의 프로퍼티에 접근한 경우 undefined 값이 출력된것과 같이 배열의 경우도 값이 없는 원소에 접근할 경우 undefined가 출력된다.
  • 3개의 요소 값만을 할당 했지만, length가 8인 이유는 자바스크립트가 배열의 크기를 현재 배열의 인덱스 중 가장 큰 값을 기준으로 정하기 때문이다.
  • 값이 할당되지 않은 인덱스의 요소는 undefined 값을 기본으로 가진다.
var emptyArr = [];
console.log(emptyArr[0]);

emptyArr[0] = 100;
emptyArr[3] = 'eight';
emptyArr[7] = true;
console.log(emptyArr);
console.log(emptyArr.length);
undefined
[ 100, <2 empty items>, 'eight', <3 empty items>, true ]
8

3-5-3 배열의 length 프로퍼티

  • 모든 배열은 length 프로퍼티가 있다. 배열의 원소 개수를 나타내지만, 실제로 배열에 존재하는 원소 개수와 일치하는 것은 아니다.
  • length 프로퍼티는 배열 내에 가장 큰 인덱스에 1을 더한 값이다.
  • 배열의 length 프로퍼티는 코드를 통해 명시적으로 값을 변경할 수도 있다.
    • 초기에 length는 3이다.
    • length를 5로 변경하면, 할당되지 않은 3, 4번 인덱스는 undefined로 출력된다.
    • length를 2로 변경하면, length프로퍼티를 벗어나는 2번째 인덱스값인 2가 실제로 삭제된다. 때문에 undefined가 출력되는 것이다.
var arr = [0, 1, 2];
console.log(arr.length);

arr.length = 5;
console.log(arr);

arr.length = 2;
console.log(arr);
console.log(arr[2]);
3
[ 0, 1, 2, <2 empty items> ]
[ 0, 1 ]
undefined

배열 표준 메서드와 length 프로퍼티

자바스크립트는 배열에서 사용 가능한 다양한 표준 메서드를 제공한다. 이러한 배열 메서드는 length 프로퍼티를 기반으로 동작하고 있다. 예를 들어, push() 메서드는 인수로 넘어온 항목을 배열 끝에 추가하는 자바스크립트 표준 배열 메서드이다. 이 메서드는 배열의 현재 length 값의 위치에 새로운 원소 값을 추가한다.

  • 배열의 length 프로퍼티는 배열 메서드의 동작에 영향을 줄 수 있을만큼 중요한 프로퍼티이다.

3-5-4 배열과 객체

  • 배열도 객체가 모두 object기 때문에, typeof 연산자로 검증한 결과 값이 같다.
  • 배열은 length 프로퍼티가 존재하지만, 객체에는 존재하지 않는다. 객체이름.length로 접근하면 undefined가 출력된다.
  • 당연하지만 객체는 push()와 같은 표준 배열 메서드를 사용할 수 없다. 배영과 객체가 자신의 부모인 프로토타입 객체가 서로 다르기 때문이다.
  • 객체 리터럴 방식으로 생성한 객체의 경우 표준 메서드를 저장하고 있는 Object.prototype 객체가 프로토타입이다. 반면에 배열의 경우 Array.prototype 객체가 프로토타입이다.
  • Array.prototype 객체는 배열에서 사용할 push(), pop() 같은 표준 메서드를 포함하고 있고, Array.prototype 객체의 프로토타입은 Object.prototype이 된다.
  • 따라서, 배열은 Array.prototype 객체에 포함된 배열 표준 메서드와 Object.prototype의 표준 메서드들을 모두 사용할 수 있다.

3-5-5 배열의 프로퍼티 동적 생성

  • 배열도 자바스크립트 객체이므로, 인덱스 숫자인 배열 원소 이외에도 객체처럼 동적으로 프로퍼티를 추가할 수 있다.
  • 배열의 length 프로퍼티는 배열 원소의 가장 큰 인덱스가 변했을 경우에만 변경된다.

3-5-6 배열의 프로퍼티 열거

  • 객체는 for in 문으로 프로퍼티를 열거한다고 앞에서 배웠다.
  • 배열도 객체이므로 for in 문을 사용해서 배열 내의 모든 프로퍼티를 열거할 수 있지만, 이렇게 되면 불필요한 프로퍼티가 출력될 수 있으므로 되도록 for 문을 사용하는 것이 좋다.

3-5-7 배열 요소 삭제

  • 배열도 객체이므로, 배열 요소나 프로퍼티를 삭제하는 데 delete 연산자를 사용할 수 있다.
  • delete 연산자로 배열 요소를 삭제하면, 해당 요소의 값을 undefined로 설정할 뿐 원소 자체를 삭제하지는 않는다.
  • 때문에 보통 배열에서 요소들을 완전히 삭제할 경우 자바스크립트에서는 splice() 배열 메서드를 사용한다.

splice() 배열 메서드

splice(start, deleCount, item...)

  • start - 배열에서 시작 위치
  • deleteCount - start에서 지정한 시작 위치부터 삭제할 요소의 수
  • item - 삭제할 위치에 추가할 요소
var arr = ['zero', 'one', 'two', 'three'];

arr.splice(2, 1);
console.log(arr);
console.log(arr.length);
[ 'zero', 'one', 'three' ]
3
  • 배열 내 2번쨰 위치부터 1개 요소를 삭제했다. delete 연산자와는 다르게 배열 요소를 완전히 없애게 된다. 따라서 배열 요소 개수도 3개가 됐다.

3-5-8 Array() 생성자 함수

배열은 일반적으로 배열 리터럴로 생성하지만, 배열 리터럴도 결국 자바스크립트 기본 제공 Array() 생성자 함수로 배열을 생성하는 과정을 단순화시킨 것이다. 생성자 함수로 배열과 같은 객체를 생성할 때는 반드시 new 연산자를 같이 써야한다는 것을 기억하자

  • 호출할 때 인자가 1개이고, 숫자일 경우 : 호출된 인자를 length로 갖는 빈 배열 생성
  • 그외의 경우 : 호출된 인자를 요소로 갖는 배열 생성
var foo = new Array(3);
console.log(foo);
console.log(foo.length);

var bar = new Array(1, 2, 3);
console.log(bar);
console.log(bar.length);
[ <3 empty items> ]
3
[ 1, 2, 3 ]
3

3-5-9 유사 배열 객체

배열의 length 프로퍼티는 배열의 동작에 있어서 중요한 프로퍼티이다. 일반 객체에 length라는 프로퍼티가 있으면 어떻게 될까? 자바스크립트에서는 이렇게 length 프로퍼티를 가진 객체를 유사 배열 객체 라고 부른다.

아래 코드에서 유사 배열 객체 obj는 당연히 배열이 아니므로 바로 push() 메서드를 호출할 경우 error가 발생한다. 유사배열 객체의 경우 apply() 메서드를 사용하면 객체지만 표준 배열 메서드를 활용하는 것이 가능하다. 실제로 결과값을 보면 obj 객체의 '1' 프로퍼티에 'baz'값이 추가되고, length 값은 2로 증가한 것을 확인할 수 있다. 이 부분은 뒤에서 call과 apply 메서드를 이용한 명시적인 this 바인딩을 배우면서 자세히 알아본다.

실제로 자바스크립트 arguments 객체나 jQuery 객체가 유사 배열 객체 형태로 되어 있으므로 이러한 성질을 잘 기억하자

var arr = ['bar'];
var obj = {
  name: 'foo',
  length: 1
};

arr.push('baz');
console.log(arr);

//obj.push('baz');  //Error

Array.prototype.push.apply(obj, ['baz']);
console.log(obj);
[ 'bar', 'baz' ]
{ '1': 'baz', name: 'foo', length: 2 }

3-6 기본 타입과 표준 메서드

자바스크립트는 숫자, 문자열, 불린값에 대해 각 타입별로 호출 가능한 표준 메서드를 정의하고 있다. 하지만 기본 타입의 경우는 객체가 아닌데 어떻게 메서드를 호출할 수 있을까?

아래의 예제와 같이 기본 타입의 값들에 대해서 객체 형태로 메서드를 호출할 경우, 이들 기본값은 메서드 처리 순간에 객체로 변환된 다음 각 타입별 표준 메서드(다음 예제의 경우 toExponential() 이나 charAt())를 호출하게 된다. 그리고 메서드 호출이 끝나면 다시 기본값으로 복귀하게 된다.

var num = 0.5;
console.log(num.toExponential(1));

console.log("test".charAt(2));
5.0e-1
s
  • toExponential()는 표준 숫자형 메서드로 숫자를 지수 형태의 문자열로 변환한다.
  • 표준 문자열 메서드 charAt()은 문자열에서 인자로 받은 위치에 있는 문자를 반환한다.
  • 이렇게 숫자와 문자열 등은 기본 타입이지만, 이들을 위해 정의된 표준 메서드들을 객체처럼 호출할 수 있다.

3-7 연산자

자바스크립트 연산자의 대부분은 다른 언어와 유사하다. 몇 가지 주의해야 할 연산자들에 대해서 알아본다.

3-7-1 + 연산자

+ 연산자는 더하기 연산과 문자열 연결 연산을 수행한다.

3-7-2 typeof 연산자

typeof 연산자는 피연산자의 타입을 문자열 형태로 리턴한다. null과 배열이 'object', 함수는 'function'이라는 점에 유의해야 한다.

return
기본타입 숫자 'number'
기본타입 문자열 'string'
기본타입 불린값 'boolean'
기본타입 null 'object'
기본타입 undefined 'undefined'
참조타입 객체 'object'
참조타입 배열 'object'
참조타입 함수 'function'

3-7-3 == 동등 연산자와 === 일치 연산자

자바스크립트에서는 두 값이 동일한지를 확인하는 데, 두 연산자를 모두 사용할 수 있다. 두 연산자의 차이는 == 연산자는 비교하려는 피연산자의 타입이 다를 경우에 타입 변환을 거친 다음 비교한다. 반면에 === 연산자는 피연산자의 타입이 다를 경우에 타입을 변경하지 않고 바로 비교한다.

== 연산자의 비교는 타입 변환에 따른 잘못된 결과를 얻을 수 있으므로 대부분의 자바스크립트 코딩 가이드에서는 == 연산자로 비교하는 것을 추천하지 않는다. jQuery 코딩 가이드 라인에서도 가급적 === 연산자로 비교하기를 권하고 있다.

console.log(1 == '1');
console.log(1 === '1');
true
false

3-7-4 !! 연산자

  • !!의 역할은 피연산자를 불린값으로 변환하는 것이다.
  • 객체는 값이 비어있는 빈 객체라도 true로 변환되는 것을 주의해야 한다.
console.log(!!0);
console.log(!!1);
console.log(!!'string');
console.log(!!'');
console.log(!!true);
console.log(!!false);
console.log(!!null);
console.log(!!undefined);
console.log(!!{});
console.log(!![1, 2, 3]);
false
true
true
false
true
false
false
false
true
true