본문 바로가기
매일코딩/자바스크립트 개념

[자바스크립트 객체지향] 1 원시타입과 참조타입 정리

by 인생여희 2017. 6. 19.
반응형

원시타입과 참조타입


자바스크립트에서는 원시 타입(primitive type) 참조 타입(reference type)이라는 두 가지 자료형을 제공한다.

숫자, 불린값, null과 undefined는 원시 타입이다. 객체, 배열, 함수는 참조 타입이다.

원시 타입 데이터는 변수에 할당될 때 메모리 상에 고정된 크기로 저장되고 해당 변수가 원시 데이터 값을 보관한다.

참조 타입 데이터는 크기가 정해져 있지 않고 변수에 할당될 때 값이 직접 해당 변수에 저장될 수 없으며, 변수에는 데이터에 대한 참조만 저장된다. 참조는 참조 타입 데이터의 주소이지 해당 데이터의 값이 아니다.

원시 타입 변수 복사

각 변수 간에 원시 타입 데이터를 복사할 경우 데이터의 값이 복사된다. 다음 예제를 보자.

var x = 100;        // 원시 타입 데이터를 선언
var y = x;          // 값을 새 변수에 복사
x = 99;             // 'x'의 값을 변경
console.log(y);     // 100, 'y'의 값은 변경되지 않음

참조 타입 변수 복사

각 변수 간에 참조 타입 데이터를 복사할 경우 데이터의 참조가 복사된다. 다음 예제를 보자.

var x = {count: 100};   // 참조 타입 데이터를 선언
var y = x;              // 참조를 새 변수에 복사
x.count=99;             // 참조 타입 데이터를 변경
console.log(y.count);   // 99, 'x'와 'y'는 동일한 참조를 담고 있으며, 따라서 동일한 객체를 가리킴


참조:http://codingnuri.com/javascript-tutorial/javascript-primitive-types-and-reference-types.html


자바스크립트에서 데이터 대부분은 객체이거나 객체를 통해 접근하는 값이다. 자바스크립트는 함수조차 객체로 표현하며 덕분에 자바스크립트의 함수는 일급함수이다.

원시타입과 참조타입: 두 타입모두 객체를 통해서 접근하지만 서로 다르게 동작하므로 차이점을 익혀두는게 좋다.

 

타입이란?

자바스크립트에 클래스라는 개념은 엇지만 이를 대체할 타입이라는 개념이 존재하며 타입은 크게 두 종류로 구분한다.

1.원시타입: 단순한 데이터를 저장하는 원시타입

2.참조타입: 객체로 저장되고 메모리 상의 주소를 가리킨다.

 

원시타입은 스택에 저장하고 참조는 힙에 저장하여 원시타입과 참조 타입을 구분하고 있지만 자바스크립트는 그렇지 않다. 자바스크립트에서는 변수 객체의 스코프를 따라 변수를 추적한다. 원시타입의 원시값은 변수 객체에 저장되지만 참조타입에서 변수 객체에 저장되는 참조 값은 메모리에 있는 실제 객체를 가리키는 포인터이다.

 

원시타입종류

Boolean

Number

String

Null

Undefied

 

모든 원시타입에는 값을 표현하는 리터럴 형식이 있다. 리터럴 이란 코드에 직접 입력된 이름이나 가격처럼 변수에 저장되지 않은 값을 의미한다.

 

var name = "kim";

var count = 23;

var found = true;

 

원시 값을 변수에 할당하면 값이 변수로 복사된다.

 

var a = "red";

var b = a;    //red

 

a,b는 같은 값을 가지고 있지만 두 값은 완전히 별개의 값이며 b에 아무런 영향을 주지 않고 a의 값을 바꿀 수 있다. 이는 두 값이 각 값당 하나씩 할당된 서로 다른 영역에 저장되어 있기 때문이다.

원시 값을 가지고 있는 각 변수는 독립된 저장 공간을 사용하기 때문에 다른 변수의 값을 바꿔도 영향을 받지 않는다.

 

var a = 'red';

var b = a;

console.log(a); //red

console.log(b); //red

 

a = 'blue';

console.log(a) // blue;

console.log(b) // red;

 

원시타입 종류 확인

type of 연산자로 확인

type of 연산자를 변수에 사용하면 변수에 저장된 데이터의 타입을 문자열로 반환한다.

 

참고 null 인지 아닌지 판단할 때

console.log(value === null);

 

등호 두 개를 사용하면 비교를 수행하기 전에 형변환을 하기 때문에 문자 ‘5’ 5는 같다. 등호 세 개를 이용하면 비교하지 않고 바로 비교를 한다.

 

원시메소드

원시타입인 문자열 숫자 불리언에는 사실 메소드가 존재한다.

var name = 'kang';

var lastname = name.toLowerCase();

 

원시 값에도 메소드가 존재하지만 원시 값 자체는 객체가 아니다. 자바스크립트의 원시 값은 다른 다른 언어와 유사한 경험을 주기 위해 마치 객체처럼 다룰 수 있게 되어있다.

 

참조타입

참조타입은 자바스크립트 객체를 나타내며 클래스가 없는 자바스크립트라는 언어에서 클래스와 가장 가까운 개념이다. 참조 값은 참조 타입의 인스턴스이며 객체와 같은 말이다. 객체는 순서가 없는 프로퍼티로 이루어져 있으며 프로퍼티는 이름과 값으로 구성되어 있다. 프로퍼티의 값이 함수 일 때 이 프로퍼티를 가르켜 메소드라고 부른다. 프로퍼티나 메소드를 다루려면 먼저 객체를 만들어야 한다.

 

객체 생성

객체를 만드는 것을 가리켜 인스턴스화 한다고 하는데, 자바스크립트에서 인스턴스화 방법은 두가지가 있다.


1. new 연산자와 생성자를 사용하는 것이다

생성자는 사실 new 연산자와 함께 사용하여 객체를 만들 수 있는 함수일 뿐이다. 관례상 자바스크립트에서 생성자의 이름은 첫 글자를 대문자로 시작하여 생성자가 아닌 다른 함수와 구분하고 있다.

참조 타입은 할당된 변수에 값을 직접 저장하지 않으므로 이 예제에서 object 변수에 저장된 값은 사실 객체 인스턴스가 아니라 객체가 있는 메모리상의 위치를 가리키는 포인터이다. 이것이 바로 원시 값과 객체의 가장큰 차이점인데, 원시값은 변수에 직접 값 자체가 저장된다. 객체를 변수에 할당하는 일은 사실 객체의 포인터를 할당하는 셈이다. 다시말해 어떤 변수를 다른 변수에 할당하면 두 변수는 모두 포인터의 복사본만 저장하고 있으므로 메모리상에서 똑같은 객체를 참조하게 된다.


) var object1 = new Object();

var object2 = object1;

 


객체 참조 제거

) var object1 = new Object();

object1 = null;

 

 

프로퍼티 추가 및 제거

자바스크립트의 특징 중 하나는 언제든 프로퍼티를 추가하고 삭제할 수 있다.

 

) var object1 = new Object();

var object2 = object1;

 

object1.hi = "hello";

console.log(object2.hi); //hello


object1object2는 같은 객체를 가리키고 있으므로 이 프로퍼티는 object2에서도 접근 할 수 있다.

 

내장타입 인스턴스화

 

Array 숫자 인텍스 값을 가진 순차 목록

Date 날짜와 시간

Error 실행 중 발생하는 에러

Function 함수

Object 일반적인 객체

RegExp 정규표현식

 

내장 참조 타입은 다음과 같이 new 연산자를 사용해 인스턴스로 만들 수 있다.

 

리터럴 형식

리터럴은 new 연산자와 객체의 생성자를 사용하여 명시적으로 객체를 만들지 않고도 참조 값을 만들 수 있는 문법이다.

 

객체 및 배열 리터럴

프로퍼티가 두 개 있는 객체 예)

var book = {name:"자바스크립트의 원리",

year: 2016

}

 

아래와 같다.


var book = new Object();

book.name = "객체지향";

book.year = 2014;


참고

객체 리터럴을 사용하면 실제로도 new Object()를 호출하지 않는다. 실제로 생성자를 호출하지 않지만 자바스크립트가 내부적으로 new Object()를 사용했을 때와 동일한 단계를 수행한다.

 

 

배열리터럴

var colors = ["red","blue","green"];

console.log(colors[0]); //red

 

이 코드는 다음과 같다.

 

var colors = new Array("red","blue","green")

console.log(colors[0])

 

함수리터럴

function reflect(value){

return value;

}

 

// 위코드는 다음과 같다.

var reflect = new Function ("value","return value");

 

이처럼 간단한 함수일때도 생성자를 사용하는 방법보다 리터럴을 사용하는 방법이 작성하기도 편하고 이해하기도 쉽다. 게다가 생성자 형태로 작성한 함수는 디버그하기 까다롭다. 자바스크립트 디버거는 생성자를 통해 작성된 함수를 인식하지 못하므로 이렇게 작성된 함수는 들여댜 볼 수 없다.

 

정규표현식 리터럴

var numbers = |\d+|g;

var numbers = new RegExp("||d", "g");


프로퍼티 접근

var array = [];

array.push(12345);

 

각괄호 표기법을 사용할 때는 다음과 같이 각괄호 안에 메소드 이름을 문자열로 입력한다.

 

var array = [];

array["push"](12345);

 

이 문법은 접근할 프로퍼티를 동적으로 정해야 할 때 유용하다.

 

var array = [];

var method = "push";

array[method](1234);

 

참조타입 확인 

instanceof 연산자 사용

 

var items = [];

var object = {};

 

function reflect(value){

return value;

}

 

console.log(items instanceof Array); //true

console.log(object instanceof Object);

 

-자바스크립트에서 모든 참조 타입은 object를 상속하므로 사실 모든 객체는 object의 인스턴스다.

 

배열확인

var items = [];

console.log(Array.isArray(items)); //true

 

참고:explore8이하에서는 지원 안됨


원시래퍼타입

 

var name = "kim";

var firstChar = name.charAt(0);

console.log(firstChar) //"k"

 

이때 내부에서 일어나는 일은 다음과 같다.

 

var name = "kim";

var temp = new String(name);

var firstChar = name.charAt(0);

temp = null;

console.log(firstChar) //"k"

 

두 번째 줄에서 원시 문자열을 객체처럼 취급했기 때문에 자바스크립트 엔진은 charAt(0)이 정상 적으로 작동하도록 String의 인스턴스를 만든다. 이렇게 작성한 String 객체는 한 문장만 실행하고 곧 다시 파괴되는데 이 과정을 가리켜 오토박싱이라고 한다. 일반적인 객체를 다루듯 문자열에 프로퍼티를 추가해보면 이를 확인 할 수 있다.

 

var name = "kim";

name.last = "tong";

console.log(name.last); //undefind

 

평범한 객체를 다룰 때는 언제든 프로퍼티를 추가할 수 있으며 추가된 프로퍼티는 일부러 제거하지 않는 한 추가된 상태 그대로 있다. 원시 값에 프로퍼티를 추가하려고 하면 원시 래퍼 타입이 임시로 만들어 지고 이 객체에 프로퍼티가 추가된다. 하지만 임시로 만들어진 원시 래퍼타입은 곧 파괴 되기 때문에 프로퍼티가 사라진 것처럼 보인다.

 

//실제로 자바스크립트 엔진이 하는 일

var name = "kim";

var temp = new String(name);

temp.last = "tong";

temp = null;

 

var temp = new String(name);

console.log(temp.last); //undefind

temp = null;

 

var name = "kim";

var count = 10;

var found = false;

 

console.log(name instanceof String); //false

console.log(count instanceof Number); //false

console.log(found instanceof Boolean); //false

 

임시 객체는 값을 읽을 때 만들어지기 때문에 instanceof 연산자는 false를 반환한다. instanceof 연산자가 실제로는 아무런 값도 읽지 않기 때문에 임시 객체도 만들어지지 않고 따라서 원시 값은 원시 래퍼 타입의 인스턴스가 아니라는 결과가 반환되는 것이다. 원시 래퍼 타입을 명시적으로 사용해 값을 생성하는 방법도 있지만 이때는 다른 문제가 발생한다.

 

var name = new String("kim");

var count = new Number(10);

var found = new Boolean(false);

 

console.log(typeof name);

console.log(typeof count);

console.log(typeof found);

//보다시피 원시 래퍼타입의 인스턴스를 만들면 객체가 만들어지기 때문에 typeof연산자를 사용한 결과는 의도한 것과 다르게 나타난다.

 

 

요약

자바스크립트에는 클래스가 없는 대신 타입이 존재한다. 각 변수나 데이터에는 그에 해당하는 특수한 원시 타입 또는 참조 타입이 존재한다. 다섯 가지 원시 타입은 주어진 컨텍스트 내에서 변수 객체에 바로 저장되는 단순한 값을 의미 한다.

typeof 연산자를 사용하면 원시타입의 종류를 확인할 수 있다.

하지만 nullnull은 비교해야 한다.

참조 타입은 클래스가 없는 자바스크립트에서 클래스와 가장 가까운 개념이며 객체는 참조 타입의 인스턴스다. new 연산자나 리터럴 형식을 사용하면 새로운 객체를 생성할 수 있다. 프로퍼티와 메소드에 접근할 때는 보통 점 표기 법을 사용하는데 각괄호 표기법을 대신 사용할 수도 있다. 자바스크립트에서는 함수도 객체이며, 어떤 값이 함수인지는 typeof 연산자를 사용해 확인할 수 있다. instanaceof 연산자는 주어진 객체가 어떤 참조 타입의 인스턴스인지 확인할 때 사용한다.

 

자바스크립트에는 String, Number, Boolean이라는 세 종류의 원시 래퍼 타입이 있어 원시 값을 마치 참조 값처럼 다룰 수 있도록 해주지만, 자동으로 생성한 임시 객체는 문장 하나를 완료하자마자 곧 파괴 된다. 원시 래퍼 타입의 인스턴스를 명시적으로 만들수도 있지만 이 방법은 혼란을 이야기할 소지가 있어 권장하지 않는다.

 

도서 객체지향 자바스크립트의 원리 정리

반응형

댓글