1. 종류

1.1 기본형 : number, string, boolean, null, undefined 1.2 참조형 : obejct, Array, Function, Date, RegExp 등 (ES6) Map, WeakMap, Set, WeakSet 등이 객체의 하위분류임.

1.3 기본형 vs 참조형?

  • 자바스크립트의 데이터타입에는 크게 두가지가 있다.
  • 기본형은 값이 담긴 주소값을 바로복제.
  • 참조형은 값이담긴 주솟값들로 이루어진 묶음을 가리키는 주소값을 복제.
  • 기본형은 불변성(Immunitability)을 가지게 된다.

 

2. 데이터 타입에 관한 배경지식

2.2 식별자와 변수

  • 변수와 식별자를 혼용해서 쓰지만, 이는 엄연히 다르다.

  • 변수란 변할 수 있는 수이다.
  • 식별자란 데이털르 식별하는데 사용하는 이름 즉 변수명이다.

 

3. 변수 선언과 데이터 할당.

3.1 변수 선언

// ex1) 변수 선언
var a;
  • 위를 해설하자면 변할 수 있는 데이터를 만든다, 이 데이터의 식별자는 a로 한다 이다.

  • 이해를 위해 간단하게 메모리에 대해 표현해보자

 

ex2) 표 간략화 메모리

주소 ... 1002 1003 1004 ...
데이터   이름: a
값:
     
  • ex1 과 같은 명령을 받은 컴퓨터는 메모리에 비어있는 공간 하나를 확보한다

 

3.2 데이터할당

  • 먼저 아래와 같은 코드가 있다고 가정해보자
 // ex3) 변수 선언과 할당
 var a; // 변수선언
 a = 'abc'; // 데이터 할당

 var a = 'abc' // 한문장으로 표현

ex4) 위 코드 데이터 할당내부 메모리 간략화

변수영역
주소 ... 1002 1003 1004 ...
데이터   이름: a
값: @5004
     
데이터 영역 주소 ... 5002 5003 5004 ...
데이터       'abc'  
  • 변수 영역에서 빈 공간 (@1003) 을 확보
  • 확보한 공간의 식별자를 a로 지정
  • 데이터 영역의 빈공간(@5004)에 문자열 'abc'를 지정
  • 변수 영역에서 a라는 식별자를 검색한다(@1003)
  • 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입한다.

 왜 변수 영역에 직접 값을 대입하지않고 주소를 한번더 대입할까? 자바스크립트는 숫자형 데이터에 64비트의 공간을 확보한다. 그러나 문자열은 특별히 정해진 규칙이 없다. 
 직접 값을 대입하게 된다면, 문자열이 변할때마다, '확보된 공간을 변환된 데이터 크기에 맞게 늘리는작업' 이 필요해진다. 그러나, 메모리 앞뒤로 이미 할당된 값이 있다면?? 굉장히 복잡해질 것이다. 이런 오류를 피하기 위해 자바스크립트는 변수와 데이터를 별도의 공간에 나누어 저장하는 것이다.

  •   a에 'abcdef' 라는 문자열을 재할당 해보자 
변수영역
주소 ... 1002 1003 1004 ...
데이터   이름: a
값: @5005
     
데이터 영역 주소 ... 5002 5003 5004 5005
데이터       'abc' 'abcdef'
  • 위와 같이 'abc'가 할당된 공간을 고치지 않고 새로운 주소에 'abcdef'라는 문자열을 다시 할당한다. @5004의 데이터는 더이상 참조되지 않는다면 gc가 일어날때 수집대상이 될 것이다.

 

4. 기본형 데이터와 참조형 데이터

4.1 불변값

  • 변수와 상수를 구분하는 성질은 '변경 가능성' 이다.
  • 변수와 상수를 구분짓는 변경가능성의 대상은 변수영역의 메모리 이다.
  • 반면 불변성(Immunitablility)를 구분할때의 변경가느성의 대상은 데이터 영역의 메모리이다.
  • number, string, bollean, null, undefined, Symbol은 모두 Immunitable 함.
var a = 'abc';
a = a + 'def';

var b = 5;
var c = 5;
b = 7;

1~2번째 줄을보면 기존 'abc' 에 'def'를 더하지만 'abcdef'라는 새로운 데이터를 만들어 그 주소를 a의 변수에 저장한다.
즉 'abc'와 'abcdef'는 별도의 메모리에 독립적으로 존재하게 된다.

4.2 가변값
 
기본형 데이터는 모두 불변값 이지만, 참조형의 경우 기본적인 성질은 가변값이지만, 설정에 따라 변경 불가능한 경우도 있다.(Object.defineProperty, Object.freeze 등)

// ex 4-1) 참조형 데이터의 할당
var obj1 = {
 a: 1,
 b: 'bbb'
};

 

변수영역
주소 1001 1002 1003 1004 ...
데이터   이름: obj1
값: @5001
     
데이터 영역 주소 5001 5002 5003 5004 5005
데이터 @7103 ~ ?     1 'bbb'

 

객체 @5001의 변수영역
(Property)

주소 7103 7104 7105 7106 ...
데이터 이름: a
값: @5004
이름: b
값: @5005
     
  • 컴퓨터는 메모리의 빈공간 (@1002)에 obj1이름을 저장한다.
  • 임의의 데이터 저장공간 (@5001)에 데이터를 저장하려고보니, 여러개의 프로퍼티를 가진 데이터 그룹이다. 내부의 프로퍼티를 저장하기 위해 변수영역을 마련하고, 그 의 주소 (@7013 ~ ? ) 를 @5001에 저장한다.
  • @7103 및 @7104에 각각 a와 b 프로퍼티 이름을 저장.
  • 데이터영역에서 숫자1과 숫자 'bbb'를 검색 한 뒤, 그의 주소를 각각의 프로퍼티에 저장.

위의 순서로 볼때, 기본형 데이터와 참조형 데이터의 차이는 '객체의 Property 영역' 이 별도로 존재한다는 것이다. Property에는 언제나 다른값이 대입될 수 있으므로, 이는 'not immunitable' 한 값이다.

 

// ex 4-2) 참조형 데이터의 프로퍼티 값 할당
var obj1 = {
 a: 1,
 b: 'bbb'
};

obj1.a = 2;

 

변수영역
주소 1001 1002 1003 1004 ...  
데이터   이름: obj1
값: @5001 (안변함)
       
데이터 영역 주소 5001 5002 5003 5004 5005 5006
데이터 @7103 ~ ?     1 'bbb' 2

 

객체 @5001의 변수영역
(Property)

주소 7001 7002 7003 7004 ...
데이터 이름: a
값: @5006
이름: b
값: @5005
     

 위에서 알 수 있듯이, 참조형 데이터의 property 값을 재할당 할때는 property 변수영역이 가르키는 데이터영역의 주소만 바뀔분, 변수영역의 주소값(@5001)은 바뀌지 않는다.)

 

중첩객체(참조 in 참조) 일 경우 Flow를 살펴보자

// ex 4-3) 중첩된 참조형 객체의 프로퍼티 할당
var obj1 = {
 x: 1,
 arr: [3,4,5]
};
변수영역
주소 1001 1002 1003 1004 ...  
데이터   이름: obj1
값: @5001
       
데이터 영역 주소 5001 5002 5003 5004 5005 5006
데이터 @7103 ~ ? 3 1 @8104 ~ ? 4 5

 

객체 @5001의 변수영역
(Property)

주소 7103 7104 7105 7106 ...
데이터 이름: x
값: @5003
이름: arr
값: @5004
     

 

배열 @5004의 변수영역

주소 8104 8105 8106 8107 ...
데이터 이름: 0
값: @5002
이름:1
값:@5005
이름:2
값:@5006
   
  • 위와 같은 메모리 구조를 가지면, 참조형 변수 obj1의 property x,arr의 변수가 데이터영역의 @5003,@5004를 가리킨다
  • x는 데이터를 바로 가리키므로 1이 저장된 @5003을 가리키나, arr은 배열(참조형) 변수를 가리키므로 데이터영역 내 @5004에는 주소값이 저장되어 있다.
  • 배열의 property 0,1,2를 가리키는 @8104 ~ ? 주소로 가보면 다시 데이터영역의 number형의 주소가 저장되있으며 이를 각각 가리키게된다. 

obj1.arr[0] 을 얻어올경우 다음과 같은 flow로 동작한다

@1002 -> @5001 ->(@7103 ~ ?) -> @5004 -> (@8104~?) -> @5002 -> 3반환

 

굉장히 복잡하지만 이해가 안되는 정도는 아니다.

 

obj.arr = 'str'; 

위와 같이 arr이라는 property에 'str'이 재할당 된다면 어떻게 될까?

변수영역
주소 1001 1002 1003 1004 ...    
데이터   이름: obj1
값: @5001
         
데이터 영역 주소 5001 5002 5003 5004 5005 5006 5007
데이터 @7103 ~ ? 3 1 @8104 ~ ? 4 5 'str'

 

객체 @5001의 변수영역
(Property)

주소 7103 7104 7105 7106 ...
데이터 이름: x
값: @5003
이름: arr
값: @5006
     

 

배열 @5004의 변수영역

주소 8104 8105 8106 8107 ...
데이터 이름: 0
값: @5002
이름:1
값:@5005
이름:2
값:@5006
   

 

위와같이 @7104 주소의 arr변수가 가리키는 값은 데이터 영역의 string으로 변할 것이고, 빨간색으로 써진 기존 arr변수들은 더이상 참조하는 변수가 없으므로 gc 수거대상이 될것이다.

 

5 불변객체

5.1 객체의 가변성 <-> 불변객체

 위와같은 refrence 객체의 가변성때문에, object가 Not Immutable 하게되어 문제가 된다. 객체를 Immunitable 하게 하는것은 React, Vue, Angular 등에서 가장 중요한 기초가 되는 개념이다.
 우선 객체의 가변성에 따른 문제점부터 살펴보자.

// Object가 none Immunitable 하여 생기는 문제
var user = {
 name: 'Jaenam',
 gender: 'male',
};

var changeName = fuction (user, newName) {
 var newUser = user;
 newUser.nam = newName;
 return newName;
}

var user2 = changeName(user, 'Jung');

if(user !== user2) {
 console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // Jung, Jung
console.log(user === user); //true

 위 예제코드에서 우리가 원하던것과 전혀 다르게 동작한다. 이유는 object type의 특성상 주소값을 복사하게 되서, user2도 기존의 user의 name property를 가리키게 되므로, user의 네임까지 변경시켜버린다.

우리는 아래처럼 deep copy를 통해 immunitable을 보장 할 수있다.

// Object가 none Immunitable 하여 생기는 문제
var user = {
 name: 'Jaenam',
 gender: 'male',
};

var copyObject = function(target) {
 var result = {};
 for(var prop in target) {
  result[prop] = target[prop];
 }
 return result;
}

var user2 = copyObject(user);
user2.name = 'Jung';

if(user !== user2) {
 console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // Jaenam, Jung
console.log(user === user); //false

 

6 undefined 와 null

  •  자바스크립트에서 없음 을 나타내는 값이 두개가있다
  • undefined와 null 이다.

6.1 undefined

  • undefined는 사용자가 지정할 수 도있지만, JS엔진이 자동부여 할 때 도있다.
  • 엔진이 자동으로 부여하는 경우는 다음과 같다
    1. 값을 대입하지 않은 변수, 즉 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근
    2. 객체 내부의 존재하지 않는 프로퍼티에 접근하려할때
    3. return 문이 없거나 호출되지 않는 함수의 실행결과
var a;
console.log(a); //(1) undefined 값을 대입하지 않은 변수에 접근

var obj = { a:1 };
console.log(obj.b); // (2) 존재하지 않는 props 에 접근

var func = function() {};
var c = func();
console.log(c); //(3) 명시적인 반환값이 없는 함수에 반환값

 

  • 주의 할점은 '비어있는 요소' 와 'undefined를 할당한 요소'는 출력결과가 다른걸 유의 해야한다.
var arr1 = [undefined, 1];
var arr2 = [];
arr[2] = 1;

arr1.forEach(function (v,i) {console.log(v,i)}); // undefined 0 / 1 1
arr2.forEach(function (v,i) {console.log(v,i)}); // 1 1

// 엔진에 의해 할당된 undefined 같은경우, 아예 없는 값으로 취급이된다. 메서드의 순환 대상에서 제외 된다는 것이다.
  • 값이 지정되지 않은 인덱스는 '아직은 존재하지 않는 프로퍼티'에 지나지 않는다.
  • 사용자가 지정한 undefined는 그 자체로의 값이다. (순회시 하나의 값으로 취급)
  • 가장 중요한것은 undefined를 직접 할당하지 않도록 주의해야한다. 
  • 비어있음을 명시적으로 표현하고싶다면 null을 삽입하도록 하자.
  • 이렇다면 undefined는 오직 '값을 대입하지 않은 변수에 접근하고자 할때 자바스크립트 엔진이 반환해주는 값' 으로만 존재할것이다

 

var n = null;
console.log(typeof n); //object (주의) 이것은 자바스크립트의 근본적 버그이다.

console.log(n == undefined); // true
console.log(n == null); // true

console.log(n === undefined); // false
console.log(n === null); // true

 

 

* 위 내용은 책 <Core javascript> - 정재남 저 - 를 개인공부를 위해 정리한 포스트입니다.

List

 

Add

Remove

Get

Contains

Data  Structure

ArrayList

 O(1)

O(n)

O(1)

O(n)

Array

LinkedList

 O(1)

O(1)

O(n)

O(n)

Linked List

CopyonWriteArrayList

 O(n)

O(n)

O(1)

O(n)

Array

Stack

O(1)
(PUSH)

O(1)
(POP)

O(1)
(Peek)

O(n)
(Search)

Vector 기반

 

Set

 

Add

Contains

Next

Data Structure

HashSet

O(1)

O(1)

O(h/n)

Hash Table

LinkedHashSet

O(1)

O(1)

O(1)

Hash Table + Linked List

EnumSet

O(1)

O(1)

O(1)

Bit Vector

TreeSet

O(log n)

O(log n)

O(log n)

Red-black tree

CopyonWriteArraySet

O(n)

O(n)

O(1)

Array

ConcurrentSkipList

O(log n)

O(log n)

O(1)

Skip List

 

Queue

 

Offer

Peak

Poll

Size

Data Structure

PriorityQueue

O(log n )

O(1)

O(log n)

O(1)

Priority Heap

LinkedList

 O(1)

O(1)

O(1)

O(1)

Array

ArrayDequeue

 O(1)

O(1)

O(1)

O(1)

Linked List

ConcurrentLinkedQueue

 O(1)

O(1)

O(1)

O(n)

Linked List

ArrayBlockingQueue

 O(1)

O(1)

O(1)

O(1)

Array

PriorirityBlockingQueue

O(log n)

O(1)

O(log n)

O(1)

Priority Heap

SynchronousQueue

O(1)

O(1)

O(1)

O(1)

None!

DelayQueue

O(log n)

O(1)

O(log n)

O(1)

Priority Heap

LinkedBlockingQueue

O(1)

O(1)

O(1)

O(1)

Linked List

 

Map

 

Get

ContainsKey

Next

Data Structure

HashMap

O(1)

O(1)

O(h / n)

Hash Table

LinkedHashMap

O(1)

O(1)

O(1)

Hash Table + Linked List

IdentityHashMap

O(1)

O(1)

O(h / n)

Array

WeakHashMap

O(1)

O(1)

O(h / n)

Hash Table

EnumMap

O(1)

O(1)

O(1)

Array

TreeMap

O(log n)

O(log n)

O(log n)

Red-black tree

ConcurrentHashMap

O(1)

O(1)

O(h / n)

Hash Tables

ConcurrentSkipListMap

O(log n)

O(log n)

O(1)

Skip List

 

 

정렬 알고리즘 비교

정렬 이름 공간복잡도 시간복잡도
최악 최선 평균 최악
Bubble Sort O(1) O(n) O(n2) O(n2)
Heapsort O(1) O(n log n) O(n log n) O(n log n)
Insertion Sort O(1) O(n) O(n2) O(n2)
Mergesort O(n) O(n log n) O(n log n) O(n log n)
Quicksort O(log n) O(n log n) O(n log n) O(n2)
Selection Sort O(1) O(n2) O(n2) O(n2)
Shell Sort O(1) O(n) O(n log n2) O(n log n2)
Smooth Sort O(1) O(n) O(n log n) O(n log n)

 

자료구조별 비교

 

자료구조이름 평균 경우 최악의경우
Search Insert Delete Search Insert Delete
Array O(n) N/A N/A O(n) N/A N/A
ArrayList O(log n) O(n) O(n) O(log n) O(n) O(n)
Linked List O(n) O(1) O(1) O(n) O(1) O(1)
Doubly Linked List O(n) O(1) O(1) O(n) O(1) O(1)
Stack O(n) O(1) O(1) O(n) O(1) O(1)
Hash table O(1) O(1) O(1) O(n) O(n) O(n)
Binary Search Tree O(log n) O(log n) O(log n) O(n) O(n) O(n)
B-Tree O(log n) O(log n) O(log n) O(log n) O(log n) O(log n)
Red-Black tree O(log n) O(log n) O(log n) O(log n) O(log n) O(log n)
AVL Tree O(log n) O(log n) O(log n) O(log n) O(log n) O(log n)

 

 

참고 Big O 그래프

 

public class ExComparator {
	public static void main(String[] args) {
		Pair[] arr = new Pair[10];
		List<Pair> list = new ArrayList<Pair>();
		
		for(int i=0; i<10; i++) {
			int a = (int)(Math.random()*10);
			int b = (int)(Math.random()*10);
			arr[i] = new Pair(a, a+b);
			list.add(arr[i]);
		}
		
		// 정석 Comparator 객체사용 (With array)
		// 오른쪽객체가 왼쪽으로올경우 오름차순
		// 반대는 내림차순
		Arrays.sort(arr, new Comparator<Pair>() {
			@Override
			public int compare(Pair o1, Pair o2) {
				return o2.min - o1.min;
			}
		});
		
		System.out.println("원본");
		System.out.println(list.toString());
		System.out.println();
		
		//2가지 항목비교
		Collections.sort(list, new Comparator<Pair>() {
			public int compare(Pair o1, Pair o2) {
				int first = o2.min - o1.min;
				int second = o2.max - o1.max;
				return first != 0? first : second;
			}
		});
		System.out.println("2개항목비교");
		System.out.println(list.toString());
		System.out.println();
		
		//람다사용 With list (Collections)
		Collections.sort(list, (o1, o2) -> o1.min - o2.min);
		System.out.println("람다로 한개만비교");
		System.out.println(list.toString());
		System.out.println();
		
		
		//Stream 사용
		List<?> sorted = list.stream()
			.sorted((o1,o2) -> o2.min - o1.min)
			.collect(Collectors.toList());
		System.out.println("Stream 사용");
		System.out.println(sorted.toString());
		System.out.println();
		
	}
}

class Pair {
	int min;
	int max;
	
	Pair(int min, int max) {
		this.min = min;
		this.max = max;
	}
	
	@Override
	public String toString() {
		return String.format("[%d, %d]", min,max);
	}
}

+ Recent posts