Java 자바 프로그래밍: <켄트 벡의 구현패턴> 데이터 오브젝트 DTO, VO

 
 
<켄트 벡의 구현패턴> 서적 참조
데이터 오브젝트 DTO, VO
 
 
프레젠테이션 Layer
비즈니스 데이터
퍼시스턴스 Layer
사용자
UI
비즈니스 객체
영속객체
 
 
B.O
DAO(Data Access Object
 
--DTO->
 
파일 IO
 
분석 -> 설계 -> 구현 -> 테스트 -> 분석 (일반적인 최근의 방식) 애자일 방법론.
분석 -> 설계 -> 구현 -> 테스트 (폭포수형, Top Down방식)
애자일 소프트웨어 개발 선언.
애자일 소프트웨어 개발 선언
 
우리는 소프트웨어를 개발하고, 또 다른 사람의 개발을
도와주면서 소프트웨어 개발의 더 나은 방법들을 찾아가고
있다. 이 작업을 통해 우리는 다음을 가치 있게 여기게 되었다:
 
공정과 도구보다 개인과 상호작용을
포괄적인 문서보다 작동하는 소프트웨어를
계약 협상보다 고객과의 협력을
계획을 따르기보다 변화에 대응하기를
 
가치 있게 여긴다. 이 말은, 왼쪽에 있는 것들도 가치가 있지만,
우리는 오른쪽에 있는 것들에 더 높은 가치를 둔다는 것이다.
 
 

트리형 클래스 설계는 변화에 대응하기 어려웠다. 때문에 Look up 구조(중앙에 하나에서 모든걸처리) injection 구조가 생겼다.
패키지명은 도메인의 역순.
double Double로 쓴다. int Integer로 쓴다. 만들면, 0이 아니라 null 값을 가진다. 이런 값들은 식별키를 가진다.
기본 클래스의 변수 선언 -> getter /setter -> 해쉬코드와 equals를 만든다. -> toString 만든다.
FoodStore 기준으로 코딩 설명.
Lng, Lat를 그냥 받지 말고 Location 이라는 클래스를 하나 만들어서 구현. 왜냐하면 위도와 경도는 떨어지지 않는 변수이기 때문에.
상위 클래스에서 상속 같은거 하지 않고 Location 이라는 클래스를 하나 생성.
# 해쉬코드 공부할 것.
코딩을 할 때 가능하면 상위 타입을 쓰면 쓸수록 코드는 유연해진다. ArrayList 쓰지 않고 List를 사용한다.
인젝션 설계. UI쪽에선 인터페이스만 보도록 설계한다. 실제로 구현된 것은 참조하지 않는다.
UI쪽도 인터페이스로 뺄 수 있지 않았을까? UI따로 안드로이드 UI따로 이런식으로....
 
(if ~ else를 쓰지 않는다 -> HashMap를 사용
while 루프 없앤다)
UI의 가장 큰 특징은 루프에요.
public class FoodStoreUI
private FoodStoreService service; // FoodStore interface
private Scanner scanner;
public FoodStoreUI (FoodStoreService service){
this.service = service;
}
코딩을 하다가 중복되는 코드가 있으면 abstract class(추상클래스)로 빼준다.
doJob(); 은 예외처리가 되어있지. 문제가 생기면 반드시 내게 메시지를 던져주기로 되어있지.
첫 번째 비즈니스 오브젝트에서 인터페이스를 빼서 설계하는 방법을 보여주고 싶었고, 코딩을 하면서 추상클래스로 언제 빼는지를 알려주고 싶었다.
패키지명.원하는기능메소드명
String name = “org.thinker.fs.SearchNearStoreUI”
Class clz = Class.forName(name);
Task object = (Task)clz.newInstance();
다운캐스팅은 인터페이스와 추상클래스에서만 사용하도록.
자바의 동적로딩
클래스를 실시간으로 동적으로 컴파일 해서 사용할 수 있도록.
파일을 로딩할 때, properity를 사용할 거에요. 원리는 InputStream이랑 같아요. 잘라내는 것 밖에 차이점이 없어요
Map은 딕셔너리에요. 어떠한 키로 객체를 찾는거에요. 가장 많이 쓰는게 해쉬맵이에요.
소스코드를 보면 인터페이스를 얼마나 효과적으로 쓰는가를 보면 알 수 있어요
좋은 코드의 기준. 한 번 만들어 놓고 바꾸지 않으면 좋은코드에요.
엄밀하게 말하자면, 인터페이스를 활용하는 방식이 접근 제한이라고 할 수 있다.
예를 들어, 아이폰의 OS를 만들고 아이팟에서는 전화기능에 관한 기능을 인터페이스에서 삭제한다.
함수로 만드는 경우와 객체로 만드는 경우의 기준? Math.random();이 있고 new Random();이 있다.
데이터를 유지하는 경우에는 객체로 만든다. 데이터를 유지하지 않는 경우 함수로 설계하는 경우가 대부분. 함수는 side effect가 없다.
디자인 패턴에서는 각각의 UI기능을 뺀 것을 worker라고 부르고, 이를 총괄하는 것을 worker handler라고 부른다.
동적로딩의 이유. 안드로이드, Servlet. 설정파일을 만들기 위해.
equals hashcode를 예전에 오버라이딩 한 적이 있다.
# 내일 이걸 이용해서 모든 프로그램을 완성시키는 것이 과제. (오늘~내일)
싱글턴 Singleton 패턴. 이런 설계를 더 편하게 하려고 사람들이 고안해낸 설계패턴
객체생성을 막는 패턴. 객체가 하나 밖에 없다. 언제 어디서나 동일한 객체를 사용한다.
객체를 여러개를 만들다 보면 데이터가 똑같은 데이터가 아닐 수 있다.
객체를 만들 때, 데이터 때문에 만드는 경우도 있지만, 메모리 때문에 만드는 경우가 있다. 객체를 하나만 만들면 메모리가 절약된다.
클래스명 Singleton
1. 생성자를 private으로 만든다.
2. 클래스 내부에 private static Singleton instance = new Singleton(); 으로 객체를 만들어준다.
3. public static 으로 getter를 만든다.
4. 호출시, Singleton.getter 호출
메모리 공부. 구분되어 있다.
class영역 메모리
객체 영역 메모리
int, String, double, 이런 것들은 imutable 이라고 한다. 한 번 만들면 값을 바꿀 수가 없다.
또 다른 방법. 인터페이스에는 상수가 있습니다.
FoodStore instance = new FoodStoreDAOImpl();
위의 코드를 인터페이스에 선언하면, 하나의 객체만 계속 쓸 수 있다. 이 패턴은 권장사항은 아니다.
이 전체 패턴은 headfirst design 패턴 책에 보면 전략패턴으로 나온다. 중급개발자끼리는 이 패턴 전략패턴으로 구현했어요 라고 하면 이야기가 끝나요. 전략패턴에 대해 찾아보세요.
# 오늘 과제. 오늘 코딩 리뷰. 동적로딩을 활용해서 계산기를 제작. UI만 제작. 사칙연산 기능 분리. store.txt파일 만들었던 것처럼 파일만 수정하면 동작할 수 있도록.
인터페이스 잡고. 짜요. 짜다가 겹쳐, 그럼 추상클래스로 빼.
# 오늘 과제2. 파워포인트 조별 과제. 내용. 자바의 자료구조. 자바의 자료구조는 무엇무엇이 있고 특징이 있고, 장단점이 있다. 똑같은 자료구조인데 구현된 자료구조는 특징이 다를 수 있어요. 이를테면, List라는 자료구조가 있는데 ArrayList LinkedList는 각자 특징이 다르다. 이번 발표를 못하면 다음주 내내 시달릴 것이니 준비 단단히 할 것!
Iterator names = prop.keySet().iterator();
while(names.hasNext()){
String key = (String)names.next();
String value = (String)prop.get(key);
System.out.println(key +":" + value);
Task obj = (Task)Class.forName(value).newInstance();
obj.setService(service);
taskMap.put(key, obj);
}
return taskMap;
// Iterator는 자바의 반복자. (반복자는 외부반복자와 내부반복자로 나뉘는데, 자바는 외부반복자만 존재) 개체의 요소들을 출력할 때, 기존의 인덱스 값을 이용한 호출이 불편하다고 생각해서 생긴 편리한 방식이다.

하지만, 주의 사항이 있다. Iterator는 지시하고자 하는 대상과 대상의 사이를 가리키지만 인덱스 호출방식은 그 대상을 직접 지시한다.
Iterator의 경우 hasNext( ) 메소드를 이용해서 다음 요소가 있는지 확인을 해야하는데 확장된 for 루프문(foreach)은 이런 과정을 우리가 수동으로 체크하지 않아도 되도록 만들어놨기 때문에 단순 리스트 출력은 이것을 사용하는 것이 편하다.
 
2014-10-19 <Java Script> 4, 5, 10, 11 요약

 
<Java Script for Web Developer> 교재
 
1. 자바스크립트란?
 웹 페이지와 상호작용하도록 디자인된 스크립트 언어.
  - 스크립트 언어란?
 소스 코드를 컴파일(Compile)하지 않고도 실행할 수 있는 프로그래밍 언어. 일반적으로 컴파일 언어보다 퍼포먼스가 낮지만, JIT 방식(반복되는 부분은 한 번은 미리 컴파일)으로 성능을 개선한 자바스크립트나, 액션스크립트 등이 있다.
   예) 그루비, 자바스크립트, 펄, 루비, 파이썬, PHP
2. 자바스크립트의 기능.
 ECMAScript 핵심기능 제공
 (특징: 정수와 부동소수점 구분 없음. 리턴타입 명시필요 없음.오버로딩 불가.  단, arguments.length == 1 처럼 흉내는 낼 수 있다.)
 문서 객체 모델(DOM). 웹 페이지 콘텐츠를 조작하는 메소드와 인터페이스 제공
 브라우저 객체 모델(BOM). 브라우저와 상호작용하는 메소드와 인터페이스 제공.
 
4장 변수와 스코프, 메모리
4.1 원시 값과 참조 값
  • 자바스크립트의 변수는 느슨한 타입이다. 값과 데이터 타입은 스크립스 실행 중에 바뀔 수 있다.
  • 원시값: 단순한 데이터. '값으로' 접근한다. 문자열도 '원시값'임을 주의. (타 언어에서는 참조값)
  • 참조값: 객체를 가리키는 리모컨. 자바스크립트는 메모리 공간을 직접 조작하는 일이 불가능. 객체가 아니라 '참조'를 조작. 
  • Undefined는 선언만 되고 초기화 되지 않은 변수이다. typeof - Undefined
  • Null은 변수에 할당된 변수이다. typeof  - Object
  • NaN
동적프로퍼티 (property n. 속성)
var person = new Object();
person.name = "Nicholas";
alert(person.name); // "Nicholas"
  • 참조값에는 . 으로 값(프로퍼티) 추가가 가능.
  • 원시값은 진짜 값이 복사되고 참조값은 리모컨이 복사된다.
  • 매개변수(parameter)는 오직 원시 값으로만 전달. 참조 값은 Heap의 메모리 주소 값을 보낸다. 때문에, 다음과 같은 상황이 벌어진다.
function setName(obj) {
 obj.name = "Nicholas"
 obj = new Object();
 obj.name = "Greg"
}
var person = new Object();
setName(person)
alert(person.name); // "Nicholas"
  • obj는 단지 리모컨을 담는 그릇으로 새로운 리모컨이 들어가게 된다. 만일 참조상태였다면, person에 새로운 객체가 담겼을 것이다.
  • 타입판별: 원시값 typeof 참조값 instanceof
 
4.2 실행 컨텍스트와 스코프
  • 실행 컨텍스트 execution context를 컨텍스트라고 부른다. 변수 접근 여부나 행동을 규정.
  • 실행 컨텍스트 = 전역 컨텍스트 + 함수 컨텍스트,
  • 전역 컨텍스트: 전역 컨텍스트에 있는 변수와 함수에만 접근할 수 있다. 웹브라우저에서 전역 컨텍스트를 window라고 부른다.
  • 함수 컨텍스트: 해당 스코프의 변수, 스코프가 속해있는 컨텍스트에 있는 변수, 전역 컨텍스트에 있는 변수에 모두 접근 가능. (해당 스코프가 속해있지 않는 컨텍스트의 로컬변수에는 접근 불가)
  • 모든 변수는 스코프라고 부르기도 하는 컨텍스트에 존재. 컨텍스트는 변수의 존재기간, 접근성 등을 결정.
  • 스코프 체인: 실행 컨텍스트에 진입할 때 마다 생성, 변수와 함수 검색에 쓰임.
  • 실행 컨텍스트는 변수에 할당된 메모리를 언제 해제할 수 있는지 판단하는데 도움이 된다.
 
4.2 가비지 콜렉션
  • 자바스크립트는 자동으로 가비지 컬렉션을 수행.
  • 표시하고 지우기: 컨텍스트 내외부를 표시하여 외부일 경우 제거.
  • 참조카운팅: 참조되는 횟수를 기준으로 추적. 순환참조라는 심각한 문제가 발생.
  • 인터넷 익스플로어 8버전은 객체중 일부가 네이티브 자바스크립트 객체가 아니다. BOM과 DOM의 객체들이 C++의 COM(구성 요소 객체 모델 Component Object Model)로 구현되었다. COM 객체는 가비지 컬렉션에 참조카운팅 방식을 사용. 때문에 반드시 이를 해결해야 한다.
var element = document.getElementById("some_element");
var myObject = new Object ();
myObject.element = element;
element.someObject = myObject; // 참조 카운팅의 순환오류 발생
 
// 전부 사용한 이 후
myObject.element = null;
element.someObject = null;
// 변수에 null을 할당하면 순환오류를 해결할 수 있다.
  • 이를 Dereference(참조제거)라고 한다.  Dereference는 메모리 관리에도 쓰이는 데 전역 변수 및 전역 객체의 프로퍼티에 null을 할당하면 성능이 올라간다.
  • null을 할당하는 순간 메모리가 회수 되는 것은 아니다. 다음 가비지 컬렉션 사이클 때 메모리가 회수된다.
  • 익스플로어 9버전은 BOM과 DOM객체가 Native JavaScript 객체임.
 
5장 참조 타입
5.1 Object 타입
  • 객체 리터럴 표기법 (Json 표기법)
var person = {}; // new Object();와 동일
var person = {
 name: "Nicholas",
 age: 29,
 7: None
}
alert(person["name"]; // "Nicholas"
alert(person.name); // "Nicholas"
person["first name"] = "Nicholas"
// 프로퍼티 이름에 공백이 있기에 .(점) 방식으로는 접근 불가.
 
5.2 Array 타입
var colors = new Array(3);
var colors = Array(3); // new 생략가능
var colors = ["red", "blue", "green"] // 배열 리터럴 표기
  • .length 프로퍼티는 읽기 전용이 아니다. 배열 길이가 바뀌면서 데이터를 제거하나거 빈 슬롯을 추가
colors.length = 2;
alert(colors[2]); // undefined
  • 배열의 최대 길이 4,294,967,295. 이 길이를 넘기면 에러발생.
if (value instanceof Array) {
 // 배일일 때 실행하는 코드
}
if (Array.isArray(value) {
 // 배일일 때 실행하는 코드
 // IE9 이상 지원 문법
}
  • 자바스크립트의 배열은 스택과 큐메소드 사용가능
  • 스택: Last In First Out 방식  큐: First In First Out 방식.
.pop() 마지막 데이터 반환 .push() 마지막에 데이터 추가 .shift() 맨 앞 데이터 반환 .unshift() 맨 앞 데이터 추가.
  • reverse() 배열 순서 변경 sort() 문자열 기준 오름차순 정렬. (1, 10, 2, 3, 4) 비교함수가 필요
function compare(value1, value2) {
 if (value1 < value2) {
   return -1;
 } else if (value1 > value2){
   return 1;
 } else {
  return 0;
 }
}
var values = [ 0, 5, 1, 10, 15 ];
values.sort(compare);
alert(values); // 0, 1, 5, 10, 15
  • splice 메소드
colors.splice(0,2, "red", "green")  // 처음 2개 삭제
colors.splice(2,0, "red", "green")  // 인덱스2부터 red와 green을 삽입
colors.splice(2,1, "red", "green")  // 인덱스2부터 1개의 데이터를 삭제후 그 자리에 red와 green을 삽입
splice는 삭제한 배열을 반환
  • 반복메소드 every(), filter(), forEach(), map(), some()
  • 콜백함수?
 
5.3 Date 타입
  • 기본적인 사용법은 java와 동일, 세부 내용은 158p 참조
 
5.4 RegExp 타입
  • 정규표현식의 지원. 입력된 값의 유효성을 체크한다. (ex. 비밀번호 자릿수, 대소문자, 특수문자 등)
var regExpName = /정규표현식/[Flag]
Flag - g 전역, i 대소문자 구분없음, m 행이 바뀌어도 찾음
// bat이나 cat중 처음 나온 것에 일치, 대소문자 구분 없음
var pattern1 = /[bc]at/i;
// pattern1과 동일
var pattern2 = new RegExp("[bc]at", "i");
  • 리터럴 패턴? 문자열?
 
5.5 Function 타입
  • 자바스크립트에서는 함수도 객체다.
  • 함수 지정이 호출보다 아래줄에 있어도 호출된다. (실행 컨텍스트에 우선순위 부여)
  • 변수라고 해서 new 함수 표현식 하지 말 것. 함수 선언할 것. 에러 나는 경우 있다.
  • 함수를 파라미터로 받아서 다른 함수를 리턴할 수 있다.
  • 재귀 함수 쓸 때, .callee 사용하면 함수 이름에 의존하는 약점을 극복할 수 있다.
  • call()과 apply()로 this를 바꿀 수 있다.
 
5.6 원시 래퍼 타입
5.7 내장된 싱글톤 객체
  • Global (ex. encodeURI(), 6decodeURIComponent(), eval() )
  • Math는 싱글톤 객체.
5.8 요약
 
10장 DOM
 기본적으로 웹문서는 HTML과 XML과 같은 마크업 언어로 작성된 문서로 익스플로러나 Firefox 같은 웹 브라우저는 이렇게 HTML이나 XML 같은 마크업 언어로 작성된 문서들을 여러분이 쉽게 이해할 수 있도록 바꾸는 작업을 수행합니다. 그래서 여러분들을 이러한 브라우저를 통해 문자열에서부터 그림, 테이블 등을 볼 수 있게 되는 것입니다.
 그리고 이러한 해석 과정에서 HTML 페이지를 하나의 트리(Tree) 형태의 모델로 저장하는데 이를 DOM(Document Object Model)이라고 합니다.
 DOM은 HTML 문서를 하나의 트리(Tree) 형태로 나타낼 수 있는데 트리는 노드(node)들로 구성됩니다. 여기서 노드(node)란 DOM 트리에 존재하는 요소(Element), 속성(Attribute), 텍스트(Text), HTML 문서 전체를 나타내는 Document 등을 노드라고 합니다.

 
10.1 노드의 계층 구조
  • DOM은 HTML과 XML문서에 대한 API. 플랫폼과 언어에 독립적인 페이지 표현 및 조작 방법.
  • p376 그림 10-1,

10.2 DOM 다루기
  • DOM조작은 자바스크립트에서 가장 느린 작업. 특히나 NodeList 객체는 '살아있는' 것으로 간주해서 접근할 때 마다 다시 쿼리한다. 최소화 하는 편이 좋다.
10.3 요약
 
11장 DOM 확장
11.1 선택자 API
11.2 요소 간 이동
11.3 HTML5
11.4 전용 확장
11.5 요약
 
2014-10-19 <Java Script for Web Developer> 1~6 요약본

 
1장. 자바스크립트란 무엇인가
1995년 처음 등장할 때 주요 목적은 서버 언어에서 담당하던 입력 유효성을 검사하기 위해서였다.
자바스크립트는 완전히 익히려면 자바스크립트의 성격과 역사, 한계에 대해 이해해야 한다.
1.1 간추린 역사
넷스케이프의 브랜든 아이흐가 처음엔 Mocha, 나중에 LiveScript라고 불린 스크립트 언어를 개발했는데 넷스케이프 내비게이터 2에서 브라우저와 서버(서버쪽은 LiveWire) 모두에서 사용하려는 것이었으며, 출시하기 직전 자바의 인기에 편승하기 위해 자바스크립트로 이름을 바꾸었다.
IE 3에선 저작권 문제를 피하기 위해 JScript라고 이름지었다. 이는 자바스크립트가 하나의 언어로 본격적으로 개발되기 시작한 의미 있는 날이다.
1997년 자바스크립트 1.1이 ECMA에 제안되었다. ECMA는 TC39 위원회에서 “문법과 의미를 표준화하여 일반적인 목적에 쓸 수 있고 플랫폼을 가리지 않으며 제조사에 중립인 스크립트 언어”를 만들기로 했으며, 1998년 ISO와 IEC에서도 ECMAScript를 표준(ISO/IEC-16262)으로 받아들였다.
1.2 자바스크립트 구현
자바스크립트 구현은 다음 세 가지로 나뉜다.
  • 코어 (ECMAScript)
  • 문서 객체 모델 (DOM:Document Object Model)
  • 브라우저 객체 모델 (BOM:Browser Object Model)
1.2.1 ECMAScript
ECMAScript ‘판’
ECMA-262의 최근판은 2009년에 만들어진 5판이며, 6판은 현재 2014년 12월 예정이다.
ECMA-262 3판이야말로 표준에 대한 첫 번째 진짜 업데이트이며, 진정한 프로그래밍 언어로 간주하는 이유다. ECMAScript 3.1이 ECMA-262 5판이라는 이름으로 2009년 12월 3일 공식 발표되었다.
웹 브라우저의 ECMAScript 지원
넷스케이프 내비게이터 4.06의 자바스크립트 1.3 버전이 ECMA-262 초판과 완전히 호환되었으며, 2008년부터 주요 웹 브라우저 모두 ECMA-262 3판을 준수하였다.
IE 8은 5판을 구현한 최초의 브라우저였으며 IE 9은 5판을 완전히 지원한다. 곧이어 파이어폭스 4도.
1.2.2 문서 객체 모델(DOM)
DOM은 XML을 HTML에서 사용할 수 있도록 확장한 API이며, 전체 페이지를 노드의 계층 구조로 변환한다. HTML(XML) 페이지의 부분을 데이터를 포함하는 다양한 타입의 트리 노드로 만들고 이를 통해 문서의 콘텐츠와 구조를 자유롭게 수정할 수 있다.
DOM이 필요한 이유
브라우저별로 다른 DHTML을 지원하면서 개발자들은 새로고침 없이 콘텐츠의 모양을 바꿀 수 있게 되었으나 브라우저 별로 HTML 페이지를 만들어야 하는 재앙이 발생했다. W3C에서 DOM 관련 작업을 시작했고 레벨 1,2,3가 차례대로 나왔다. 레벨 0는 W3C 작업 이전에 IE 4.0과 넷스케이프 내비게이터 4.0이 지원했던 DHTML을 말한다.
1.2.3 브라우저 객체 모델(BOM)
브라우저 창에 접근하고 조작할 수 있게 하는 인터페이스이며, 브라우저에 표시된 페이지와는 별개의 컨텍스트에서 브라우저와 상호작용할 수 있다.
표준이 없어 자주 문제를 일으켰으나, HTML5는 BOM을 공식 명세의 일부로 표준화하고 있어 개선되고 있다.
1.3 자바스크립트 버전
넷스케이프 소스코드가 모질라 프로젝트로 오픈소스로 공개될 때 자바스크립트 버전은 1.3이었다.
1.4 요약
자바스크립트는 웹페이지와 상호작용하도록 디자인된 스크립트 언어이며, 핵심 기능을 담당하는 ECMAScript(ECMA-262에서 정의), 웹 페이지 콘텐츠를 조작하는 DOM, 브라우저와 상호작용하는 BOM으로 구현된다.
주요 웹 브라우저들의 ECMAScript 3에 대한 지원은 일반적으로 좋은 편이며 ECMAScript 5에 대한 지원은 나아지고 있지만, DOM 지원은 편차가 심하다. BOM은 최근에야 HTML5에서 표준화되고 있으므로 일부 외에는 각기 다르다.
요약자 후기
관련 글들
 
 
2장. HTML 속의 자바스크립트
2.1 <script> 요소
자바스크립트를 HTML 페이지에 삽입하는 일차적인 방법이며, async, charset, defer, language, src, type의 여섯가지 속성이 있다. 현재 language는 페기되었고, charset 값은 무시된다. type 속성은 아직 습관적으로, 또는 브라우저 호환성을 위해 “text/javascript” 라 표기하곤 하나, 기본값이라서 생략 가능하다.
<script> 요소 안의 인라인 자바 스크립트 코드는 위에서부터 차례로 해석되며 코드 전체를 해석하기 전에는 페이지의 나머지 콘텐츠를 불러오지도 않고 표시하지도 않는다.
인라인 자바스크립트 코드에서 문자열 “”는“/” 문자를 \로 이스케이프해야 한다.
자바스크립트를 외부 파일에서 불러오려면 파일의 URL을 속성값으로 src 속성을 사용한다. 외부 파일의 코드를 내려받고 해석하는 동안 페이지 처리가 멈춘다.
<script type="text/javascript" src="example.js"></script>
중요<script>와 </script> 태그 사이에 스크립트 코드가 있고 src 속성도 사용했다면 브라우저는 스크립트 파일을 내려받아 실행하며 인라인 코드는 무시합니다.
신뢰할 수 있는 외부 도메인의 코드를 마치 페이지의 원래 일부였던 것처럼 불러와서 해석할 수 있다.
<script type="text/javascript" src="http://www.somewhere.com/afile.js">; </script>
2.1.1 태그 위치
전통적으로 <script> 요소는 외부 파일에 참조를 한곳에 관리하기 위해 페이지의 <head> 요소 안에 쓰는 것이 일반적이었다. 그러나, 최신 웹 앱에선 페이지 렌더링 시간의 지연을 막기 위해 <body> 요소 안에, 페이지 콘텐츠 마지막에 -</body> 태그 바로 앞에 - 쓴다.
2.1.2 스크립트 처리 지연(defer 속성)
defer 속성을 설정하면 브라우저는 즉시 코드를 내려받지만 실행은 페이지 전체를 파싱한 후에 한다. 그러나, 지연시킨 스크립트가 항상 순서대로 실행되지는 않으므로 <script> 요소를 하나만 쓰는 것이 최선이다. 그러나, 여러 브라우저 지원 문제 때문에 스크립트는 페이지 맨 마지막에 놓는 것이 최상이다.
2.1.3 비동기 스크립트(async 속성)
스크립트를 모두 내려받을 때까지 기다릴 필요없이 페이지 렌더링을 시작해도 좋으며, 앞선 스크립트 파일을 기다리지 않고 위의 스크립트 파일을 받아도 좋다고 명시하는 것이다. 스크립트가 순서대로 실행된다는 보장이 없어 여러 스크립트 파일 사이에 의존성이 있으면 안되며, DOM을 조작하는 스크립트는 비동기적으로 불러오지 않는 것이 좋다.
2.1.4 XHTML에서 바뀐 점
XHTML에서는 < 기호 다음 공백문자가 있으면 문법 에러가 발생하는데, <를 HTML 엔티티 &lt;로 변경하거나, CDATA 섹션으로 감싸줄 수 있다. 브라우저가 CDATA 섹션을 지원하지 않으면 CDATA 마크업 앞에 자바스크립트 주석 기호를 써야 한다.
2.2 인라인 코드와 외부 파일(src 속성)
외부 파일을 쓸 때 이점.
  • 관리가 쉽다.
  • 캐싱으로 페이지 불러오는 시간이 짧아진다.
  • 외부 파일 불러오는 문법이 HTML과 XHTML 모두 똑같으므로, 위의 편법을 쓰지 않아도 된다.
2.3 문서 모드
IE 5.5는 쿽스와 표준의 두 가지 문서모드 개념을 처음 도입했다. 두 모드의 주요 차이는 콘텐츠 렌더링과 관련된 것이지만 자바스크립트에도 영향이 있다. 다른 브라우저 들도 이를 도입함에 따라 '거의 표준 모드'라는 엄격하지 않은 표준 모드가 등장했다. 이미지 주변의 공백과 테이블 이미지 등에서 차이가 크다.
쿼크 모드는 브라우저 사이의 일관성을 전혀 기대할 수 없으므로 독타입을 이용하여 표준 모드로 사용한다. 표준 모드와 '거의 표준' 모드는 차이를 느낄 수 없기 때문에 일반적으로 '표준 모드'라는 용어는 쿽스 모드를 제외한 둘 모두를 말한다.
2.4 <noscript> 요소
<noscript>는 브라우저가 자바스크립트를 지원하지 않거나 지원이 꺼져 있을 때 대체 콘텐츠를 제공하며<script> 요소를 제외한 모든 HTML 요소를 사용할 수 있다. 브라우저에서 스크립트를 사용할 수 있을 때는 <noscript> 요소의 콘텐츠는 결코 표시되지 않습니다.
 
 
3장. 언어의 기초
3.1 문법
대소문자 구분
변수, 함수 이름, 연산자 모두 대소문자를 구분한다.
식별자(Identifiers)
'식별자'란 변수, 함수, 프로퍼티, 함수 매개변수의 이름이다. 식별자는 한 개 이상의 문자로 표기하며, 첫 번째 문자는 반드시 글자나 밑줄(_), 달러기호($) 중 하나이다.
ECMAScript는 관습적으로 카멜 케이스로 쓴다. 카멜 케이스란 첫번째글자는 소문자로 쓰고 단어가 바뀔 때는 바뀐 단어의 첫 글자를 대문자로 쓰는 표기법이다. 반드시 써야하는 것은 아니지만 ECMAScript 내장 함수와 객체가 카멜 케이스로 표기되어 있어서 따르길 권한다.
  • 키워드와 예약어 및 true, false, null은 식별자로 사용할 수 없다.
주석(comments)
ECMAScript는 한 줄 주석과 블록 주석 모두 C언어 스타일로 표기한다.
// 한줄 주석
/*
  • 블록 주석은 /*로 시작하고,
  • 그 반대 */로 끝난다. */
두번 째와 세 번째 줄에있는 *는 가독성을 위해 추가한 것이며 기업 애플리케이션에서 선호한다.
스트릭트 모드(Strict Mode)
ECMAScript 5에서 도입하였는데, 안전하지 않는 동작에서는 에러를 반환하도록 한다.
전체 스크립트에 스트릭트 모드를 적용하려면 다음 문장을 스크립트 최상단에 추가한다.
"use strict";
함수 단 하나만 적용하려면 다음 선언(pragma)을 함수 본문 맨 앞에 추가한다.
function doSomething(){
    "use strict";
    // 함수 본문
}
IE 10+, 파이어폭스 4+, 사파리 5.1+, 오페자 12+, 크롬에서 지원한다.
문장(Statements)
ECMAScript에서 각 문장은 세미콜론으로 종료한다. 꼭 써야하는 것은 아니지만 여분의 공백 제거, 압축 시 문법 에러, 성능 향상 등의 이유로 세미콜론으로 종료해라.
C 언어 스타일 문법을 써서 여러 문장을 코드 블록으로 합칠 수 있다. {로 시작하여 }로 끝난다. 실행한는 문장이 하나뿐이더라도 에러의 원인이 되기도 하므로 코드블록을 써라.
3.2 키워드와 예약어
ECMAScript의 키워드와 예약어는 식별자 이름이나 프로퍼티 이름으로 사용하지 마라.
3.3 변수
ECMAScript는 느슨한 변수타입을 사용하므로, 변수에 어떠한 타입의 데이터라도 저장할 수 있다. 모든 변수는 단순히 값에 대한 이름 붙은 플레이스홀더일 뿐이다.
변수를 정의 할 때에는 var 연산자 다음에 변수 이름을 쓴다. var는 키워드이며, 변수 이름은 식별자이다. 변수를 초기화하지 않으면 특별한 값 undefined 가 할당되며, 다음과 같이 변수 선언과 동시에 값을 할당할 수 있다.
var message = "h1";
var 연산자는 변수를 로컬 스코프에서 정의한다. 함수 안에서 var 키워드를 써서 변수를 정의하면 해당 변수는 함수를 종료하는 즉시 파괴된다.
var 연산자를 생략하면 변수를 전역으로 정의할 수 있으며, 함수를 호출하는 즉시 변수가 정의되며, 함수 외부에서도 이 변수에 접근할 수 있다. 그러나 이런 패턴은 피해라.
변수를 여러 개 선언하려면 쉼표로 구분하여 같은 문장에서 선언하고 초기화할 수 있다. 변수 사이에 줄바꿈과 들여쓰기로 읽기 쉽게 한다:
var message = "h1",
    found = false,
    age = 29;
3.4 데이터 타입
ECMAScript에는 Undefined, Null, Boolean, 숫자, 문자열의 다섯가지 기본적인 데이터 타입(원시 primitive 데이터 타입)이 있으며, 이름-값 쌍의 순서없는 목록 즉, 객체라는 복잡한 데이터 타입도 있다. 이 여섯 가지의 데이터 타입은 동적이어서 한 가지 데이터 타입이 여러 특성을 가질 수 있다.
typeof 연산자(Operator)
typeof 연산자를 통해 데이터 타입을 알 수 있으며, 값(변수)에 typeof 연산자를 적용하면 다음 문자열 중 하나를 반환한다.
  • 정의되지 않은 변수 : "undefined"
  • 불리언 : "boolean"
  • 문자열 : "string"
  • 숫자 : "number"
  • 함수를 제외한 객체 또는 null : "object"
  • 함수 : "function"
undefined 타입
기본적으로 초기화하지 않는 변수에는 항상 undefined 값이 할당된다. 그러나, 변수를 항상 초기화하는 습관을 갖으면 typeof에서 undefined를 반환했을 때 해당 변수가 초기화되지 않은 것인지, 정의되지 않은 것인지 바로 알 수 있다.
Null 타입
Null 타입의 값은 특별한 값인 null이다. null은 빈 객체를 가리키는 포인터이므로 null에 typeof를 호출하면 object를 반환하며, 객체를 사용해야 하지만 해당 객체를 이용할 수 없을 때 null을 사용하여 해당 변수가 객체를 자리키는지 명시적으로 확인할 수 있다.
불리언 타입
불리언 타입은 ECMAScript 에서 가장 많이 쓰이는 데이터 타입 중 하나이며 true와 false 두 가지 리터럴 값만 가진다. 숫자 타입과 달라, ture는 1이 아니며, false는 0이 아니다.
Boolean() 함수는 어떤 타입의 데이터에서도 호출할 수 있고 항상 불리언 값을 반환한다.
데이터 타입
true 값
false 값
불리언
ture
false
문자열
비어 있지 않은 문자열 모두
" "(빈 문자열)
숫자
0이 아닌 모든 숫자, 무한대 포함
0, NaN
객체
모든 객체
null
Undefined
해당없음
undefined
if 문 같은 제어문은 타입을 자동으로 불리언으로 바꾸므로 위 표의 변환 규칙을 반드시 이해해야한다.
숫자 타입
기본적인 숫자 리터럴 형식은 10진법이다. 정수는 8진수 리터럴, 16진수 리터럴도 가능하지만 실제 계산시에는 항상 10진수로 변환하여 계산한다.
부동소수점 숫자
부등소수점 숫자를 표현하려면 반드시 소수점이 있어야 하며, 소수점 뒤에 숫자를 쓴다. .1도 가능하지만 권장하지 않는다.
부동소수점 숫자는 정수보다 메모리를 두 배로 소모하므로 소수점 뒤에 숫자가 없다면 정수로 변환된다.
대단히 크거나 작은 부동소수점 숫자를 표현할 때는 'e- 표기법(지수 표기법)'을 쓴다. 기본적으로 소수점 뒤에 0이 6개 이상 있는 모든 부동소수점 숫자를 지수 표기법으로 변환한다.
숫자 범위
메모리 제한 때문에 모든 숫자를 표현할 수 없다. ECMAScript로 표현할 수 있는 최소값은 브라우저마다 다르지만 보통 5e-324이다. 최대값은 보통 1.7976931348623157e+308이다. 이 범위를 벗어나면 자동으로 (-)Infinity로 변환된다.
NaN(Not a Number)
숫자를 반환할 것으로 의도한 조작이 실패했을 때 반환하는 특별한 값이며, 에러를 반환하는 것은 아니다.
NaN이 포함된 모든 조작은 항상 NaN을 반환하며, 심지어 NaN끼리도 서로 일치하지 않는다. isNaN() 함수는 해당 값이 '숫자가 아닌 값'인지 검사한다. 문자열 "10"이나 불리언 값은 숫자도 바꿀 수 있다.
숫자 변환
숫자가 아닌 값을 바꾸는 함수는 어떤 데이터 타입에도 쓸 수 있는 Number(), 문자열을 숫자로 바꾸는 parseInt()와 parseFlaot() 함수 세 가지이다.
Number()함수로 문자열을 숫자로 바꿀 때는 여러 규칙을 기억해야 한다.
정수 형태의 문자열을 숫자로 바꿀 때 보통 parseInt()을 사용하며, var num = parseInt("10", 10)의 형태로 사용한다.
parseFlaot() 함수는 두 번째 소수점과 같은 잘못된 부동소수점 숫자를 만날 때까지 파싱을 계속하여, 그 이후 문자열은 무시한다. 리딩제로는 항상 무시한다. 또한, 항상 10진수 기준으로 파싱하기 때문에 16진수는 항상 0을 반환한다.
문자열 타입
문자열 데이터 타입은 16비트 유니코드 문자의 연속이다. 문자열은 큰따옴표나 작은따옴표로 감싸서 표현한다. PHP에서는 큰따옴표와 작은따옴표를 다르게 해석하지만 ECMAScript는 완전히 똑같게 해석한다. 그러나 짝은 맞아야 한다.
문자 리터럴
문자열의 성질
ECMAScript에서 문자열은 불변(immutable)이다. 즉, 문자열이 만들어지면 그 값을 바꿀 수 없다. 변수에 저장된 문자열을 바꾸려면 기존의 문자열을 파괴하고 다음과 같이 해당 변수에 새 문자열을 채워야 한다.
var lang = "Java";
lang = lang + "Script";
문자열로 변환
값을 문자열로 바꾸는 방법은 거의 모든 값에 존재하는 toString() 메서드를 사용하는 것과 호출할 값이 null이나 undefined일 가능성이 있을 경우 String() 함수를 사용하는 두 가지 방법이 있다.
객체 타입
객체는 데이터와 기능의 집합이다. 객체는 new 연산자 다음에 새로 만들 객체 타입의 이름을 써서 만든다.
var o = new Object();
Object 타입은 이 타입에서 파생하는 모든 객체의 원형이기 때문에 Object 타입의 인스턴스는 Object 타입의 프로퍼티와 메서드를 전부 상속한다.
3.5 연산자(OPERATORS)
단항 연산자(Unary Operators)
단 하나의 값에만 적용되는 연산자이며, 가장 단순한 연산자이다.
증감 연산자
C 언어에서 차용한 것이며, 피연산자의 앞에 쓸 수도 있고 뒤에 쓸 수도 있다. ++를 피연산자 앞에 쓰면 피연산자에 1을 더하며, --를 쓰면 피연산자에서 1을 뺀다.
증감 연산자를 변수 앞에 쓰면 변수의 값을 바꾼 다음 문장을 계산한다. 변수 뒤에 쓰면 문장을 계산한 다음에 적용되는 중요한 차이가 있다.
단항 플러스와 단항 마이너스
비트 연산자(Bitwise Operators)
가이드에서 언급한 대로 건너뜀
불리언 연산자
불리언 연산자에는 NOT과 AND, OR 세가지가 있다.
논리 NOT
논리 NOT 연산자는 느낌표!로 표시하며 모든 값에 적용할 수 있다. 피연사자를 불리언 값으로 변환한 다음 그 결과를 부정하며, 다음과 같이 동작한다.
피연산자
반환값
객체
false
빈 문자열
true
비어있지 않은 문자열
false
숫자 0
true
0이 아닌 숫자(Infnity 포함)
false
null
true
NaN
true
undefined
true
논리 NOT 연산자를 연달아 두 개 쓰면 Boolean() 함수를 쓴 것과 같은 효과가 있다.
논리 AND
앰퍼샌드 2개&&로 나타내며 값 두 개에 적용한다. 피연산자가 불리언 값이 아니어도 사용할 수 있으며, 그 동작은 약간 복잡하다;;
논리 OR
파이프 두개||로 표현한다. 피연산자가 불리언 값이 아니라도 사용할 수 있으며, 그 동작은 약간 복잡하다;;
다음과 같이 그 행동을 이용해서 변수에 null이나 undefined가 저장되지 않게 할 수 있다:
var myObject = preferredObject || backupObject;
곱셈 관련 연산자(Multiplicative Operators)
곱셈, 나눗셈, 나머지의 세가지 곱셈 관련 연산자가 있다.
곱셈
아스테리스크*를 써서 나타내며 두 숫자를 곱하는 데 쓰인다.
나눗셈
슬래시/ 기호로 표현하며, 첫 번째 피연산자를 두 번째 피연산자로 나눈다.
나머지(Modulus)
퍼센트 기호%로 나타내며 나눗셈을 적용하고 나머지를 반환한다.
덧셈 관련 연산자
덧셈
피연산자 중 하나가 문자열이라면 다음 규칙을 따르며, 아래 예제와 같은 흔한 실수를 피해야 한다.
  • 피연산자가 모두 문자열이라면 두 번째 문자열을 첫 번째 문자열에 합한다.
  • 피연사자 중 하나가 문자열이라면 다른 피연산자를 문자열로 변환하고 두 문자열을 합친다.
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
alert(message);     // "The sum of 5 + 10 is 510"
이를 피하기 위해서는 (num1 + num2)와 같이 괄호로 감싸 괄호 안을 먼저 계산한 후에 그 결과를 문자열에 합쳐야 한다.
뺄셈
관계 연산자(Relational Operators)
관계 연산자에는 미만<과 초과>, 이하<=와 이상>= 연산자가 있다. 두 값을 비교하여 불리언 값을 반환한다.
피연산자 중 하나가 숫자라면 다른 피연산자를 숫자로 변환한 후 비교하며, 하나가 불리언이라면 숫자로 바꾼 후 비교한다.
피연산자가 모두 문자열이면 서로 대응하는 문자의 문자 코드를 비교하는데, 알파벳의 대문자 전체가 소문자의 문자 코드보다 작기 때문에 대소문자를 전부 통일한 다음 비교하는 등의 주의가 필요하다.
NaN과 비교는 항상 false를 반환한다.
동일 연산자(Equality Operators)
ECMAScript에서는 연산자를 두 벌로 분리해서 '동일' '비동일' 연산자는 비교 전에 타입을 변환하며, '일치' '불일치' 연산자는 타입 변환 없이 비교하는 것으로 정했다.
동일, 비동일(Equal and Not Equal)
동일 연산자는 ==로 표시하며 동일하면 true를 반환한다. 비동일 연산자는 !=로 나타내며 동일하지 않으면 true를 반환한다. 피연산자를 비교하기 전에 변환하며, 이를 종종 '타입 강제(type coercion)'라 부른다.
  • null과 undefined는 동일하며, 이 둘은 다른 값으로 변환하여 평가하지 않는다.
  • 피연산자 중 하나가 NaN이라면 동일 연산자는 false를, 비동일 연산자는 true를 반환한다. 피연산자가 모두 NaN이라도 동일 연산자는 항상 false를 반환한다. NaN은 NaN과 같지 않다.
  • 피연산자가 모두 객체라면 객체끼리 비교하는 것이 아니라 객체에 대한 참조를 비교한다.
일치, 불일치(Identically Equal and Not Identically Equal)
일치 연산자는 ===로 나타내며 피연산자의 타입을 변환하지 않아도 같을때에만 true를 반환한다. 불일치 연산자는 !==로 나타내며 피연산자의 타입을 변환하지 않는 상태에서 일치하지 않을 때에만 true를 반환한다.
null과 undefined는 비슷한 값이므로 null == undefined는 true를, null === undefined는 false를 반환한다.
동일/비동일 연산자보다는 일치/불일치 연산자를 써라!
3항 연산자(Conditional Operator)
variable = boolean_expression ? true_value : false_value;
boolean_expression이 true면 변수 variable에 true_value를 저장하며, false면 false_value가 저장된다.
var max = (num1 > num2) ? num1 : num2;
위 예제에서는 max에 num1과 num2 중 큰 값이 저장된다.
할당 연산자(Assignment Operators)
단순한 할당은 =로 나타내며 단순히 값을 변수에 할당한다. 다음과 같이 복합 할당을 적용하여 줄여 쓸 수 있으나, 성능이 좋아지는 것은 아니다.
num = num + 10;
num += 10;      // 복합 할당으로 위와 같다.
쉼표 연산자
쉼표(,) 를 사용해 여러문장을 한 문장으로 합칠 때 쓴다.
3.6 문장(STATEMENTS)
ECMA-262에는 몇가지 문장이 정의되어 있는데 이를 '제어문: flow-control statements'이라 부르기도 한다. ECMAScript 대부분이 문장을 통해 정의되며 일반적으로 키워드와 연결되어 있다.
if 문
if (condition) statement1 else statement2
대부분은 언어에서 가장 많이 쓰이는 제어문이며, 조건에 해당하는 것이 불리언 값이 아니면 Boolean() 함수를 호출하여 불리언 값으로 바꾼다. 실행 코드는 한 줄의 코드라도 코드 블록으로 사용하라. if문을 연이어 쓸 수도 있다.
do-while 문
do {
    statement
} while (expression);
do-while 문은 평가전 루프이며, 이는 루프의 종료 조건을 평가하기 전에 루프 본문을 실행한다는 뜻이다. 루프 본문을 적어도 한번은 실행한 후 빠져나가야 하는 상황에서 주로 사용한다.
while 문
while(expression) statement
while문은 평가 후 루프이며, 이는 루프 본문을 실행하기 전에 종료 조건을 평가한다는 뜻이다.
for 문
for (initialization; expression; post-loop-expression) statement
for 문은 평가후 루프인데, 루프에 들어가기 전에 변수를 초기화(initialization)할 수 있으며 루프 후 코드(post-loop-expression)도 지정할 수 있다. 조건 표현식이 true일 때만 실행하므로, while 문과 같이 루프 본문의 코드를 실행하지 않을 때도 있다. 루프 본문을 실행하면 루프 후 코드 역시 실행한다.
while 루프로 실행할 수 없는 일은 for 루프로도 불가능하다. for 루프는 단순히 루프 제어와 관련된 코드를 한곳에 모았을 뿐이다.
for 루프에서 반복을 결정하는 변수(i:iteration)를 반드시 for 루프의 변수 초기화 부분에서 var 키워드로 초기화해야 하는 건 아니다. for 루프 밖에서 초기화해도 된다. 또한, ECMAScript에는 블록 레벨 변수가 존재하지 않아 루프 안에서 변수를 선언하더라도 밖에서 이 변수에 접근할 수 있다.
옵션인 초기화, 조건 표현식, 루프 후 코드를 모두 생략하여 무한루프를 생성할 수도 있으며, 조건 표현식 하나만 명시하면 while 루프처럼 동작한다.
for-in 문
for (property in expression) statement
for-in 문은 엄격한 반복문이다. for-in 문은 객체의 프로퍼티를 나열하는데 사용한다.
문장 레이블
label: statement
문장에 레이블을 붙였다가 나중에 사용가능하며, 일반적으로 중첩된 루프에서 사용한다.
break 문과 continue 문
break 문과 continue 문을 통해 루프 내부의 코드 실행을 세밀히 조절할 수 있다. break 문은 즉시 루프에서 빠져나가 루프 다음 문장을 실행하는 반면, continue 문은 즉시 루프를 빠져나가지만 루프 실행은 지속된다.
break 문과 continue 문을 문자 레이블과 함께 사용하면 코드의 특정 위치로 이동할 수 있다.
루프는 전체적인 성능에 영향을 미치며, 개발자의 의도를 파악하기 어렵게 만들어 디버그나 유지 보수에도 문제가 생길 수 있으니 continue 문은 사용하지 마라.
with 문
with (expression) statement;
with 문은 코드의 스코프를 특정 객체에 고정한다. 원래 의도는 특정 객체를 코드에서 매우 자주 참조할 때 편리하자는 것이었다.
with 문 내부의 변수는 우선 지역 변수로 간주한다. 지역 변수에서 찾을 수 없다면 with 문과 함께 쓴 객체의 프로퍼티 중에서 같은 이름으로 검색하여, 해당 이름을 프로퍼티로 평가한다.
스트릭트 모드에서는 with 문을 금지하며 문법 에러로 간주한다. with 문은 성능에 악영향이 있으며 디버그도 힘들어, 배포할 최종 코드에 with 문을 쓰지 마라.
switch 문
switch (expression) {
    case value: statement
        break;
    case value: statement
        break;
    case value: statement
        break;
    case value: statement
        break;
    default: statement
}
if 문과 관련이 깊으며 C언어 기반의 문법과 매우 비슷하다. switch 문의 각 case는 '표현식이 value와 일치하면 statement를 실행하라'는 의미이다. break 키워드를 코드 실행을 멈추고 switch 문을 빠져나가라는 의미이며, 쓰지 않으면 다음 case를 계속 평가한다. default 키워드는 case 중 value로 평가되는 것이 없을 때 실행할 문장이다. 즉, else 문과 같은 구실을 한다.
case 문마다 break 문을 넣어서 다음 case까지 진행하지 않게 하라. 만약 다음 case 문까지 진행하기 해야 한다면, 주석(/* falls through */ 등)을 달아서 의도적으로 break 문을 생략했으며 실수가 아님을 분명히 한다.
ECMAScript의 switch 문은 모든 데이터 타입에서 동작하는 고유한 특징이 있어 문자열과 객체에서도 사용할 수 있으며, 값이 상수일 필요가 없으며 변수나 표현식도 쓸 수 있다.
switch 문은 일치 연산자(===)로 값을 비교하므로 타입 변환이 일어나지 않는다.
3.7 함수
함수는 문장을 캡슐화하여, 언제 어디서든 실행할 수 있게 하므로 모든 언어의 핵심이다. function 키워드로 정의하며 그 뒤에 매개변수와 함수 본문을 순서대로 쓴다.
function functionName(arg0, arg1, ... , argN) {
    statements
}
함수는 꼭 값을 반환하지 않아도 된다. 모든 함수는 return 문 뒤에 반환값을 써서 값을 반환할 수 있다. return 문 뒤의 코드는 결코 실행되지 않는다.
return 문 뒤에 반환값을 쓰지 않아도 되며, 이 때 함수는 return 문을 만나는 즉시 실행을 멈추고 undefined 값을 반환한다.
함수는 항상 값을 반환하거나 항상 반환하지 않게 만들어라. 즉, 반환에 일관성이 있어야 한다. 그렇지 않으면 디버그하기 어려울 수 있다.
스트릭트 모드에서의 함수 제한
  • 함수 이름과 매개변수 이름에 eval이나 arguments는 쓸 수 없다.
  • 서로 다른 매개변수에 결코 같은 이름을 쓸 수 없다.
매개변수의 이해
ECMAScript 함수는 매개변수 숫자를 따지지 않으며 데이터 타입도 체크하지 않는다.
함수는 arguments라는 객체를 하나 갖는데, 이 객체를 통해 매개변수의 값에 접근할 수 있다. arguments 객체는 각 매개변수를 대괄호 표기법, 첫 번째 매개변수는 arguments[0], 두 번째는 arguments[1] 형태로 접근하며 매개변수 개수를 length 프로퍼티를 통해 알 수 있다는 면에서 배열처럼 동작하기는 하지만 Array의 인스턴스는 아니다.
ECMAScript의 매개변수는 모두 값으로 넘겨야 한다. 매개변수를 참조 형식으로 전달할 수는 없다.
오버로딩 없음
ECMAScript에서는 같은 이름으로 함수를 여러 번 정의하면 마지막 함수가 해당 이름을 소유한다.
함수에 넘긴 매개변수의 타입과 숫자를 체크해서 그에 맞게 반응하는 방법으로 오버로딩을 흉내낼 수 있다.
 
 
4장. 변수와 스코프, 메모리
자바스크립트 변수는 느슨한 타입을 취하여, 변수의 이름만 그대로이고, 값과 데이타 타입은 스크립트 실행 중에도 바뀔 수 있다.
4.1 원시 값과 참조 값
ECMAScript의 변수는 원시 값과 참조 값(Primitive And Reference Values) 두가지 타입의 데이터를 저장할 수 있다.
원시 값은 단순한 데이터이며, Undefined, Null, 불리언, 숫자, 문자열이다. 변수에 저장된 실제 값을 조작하기 때문에 '값으로' 접근한다고 한다. 원시 값은 고정된 크기를 가지며 스택 메모리에 저장된다.
참조 값은 여러 값으로 구성되는 객체이자 메모리에 저장된 객체이며, 힙 메모리에 저장된다. 객체를 조작할 때는 객체 자체가 아닌 해당 객에 대한 '참조'를 조작하기 때문에 '참조로 접근한다'고 한다.
동적 프로퍼티
참조 값을 다룰 때는 언제든 프로퍼티와 메서드를 추가하거나 바꾸고 삭제할 수 있으며, 객체를 파괴하거나 프로퍼티를 제거하기 전까지는 접근할 수 있다. 원시 값에는 프로퍼티가 없으며, 참조 값만이 동적으로 프로퍼티를 추가할 수 있다.
값 복사
원시 값은 다른 변수로 복사할 때 저장된 값을 새로 생성한 다음 새로운 변수에 복사하여 두 변수를 완전히 분리한다. 참조 값을 변수에서 다른 변수로 복사하면, 힙(heap: 브라우저가 쓰는 메모리)에 저장된 객체를 가리키는 포인터 값을 복사하므로 두 변수는 정확히 같은 객체를 가리킨다. 따라서 한쪽을 조작하면 다른 쪽에도 반영된다.
매개변수 전달(Argument Passing)
ECMAScript의 함수 매개변수는 모두 값으로 전달된다. 원시 값이던 참조 값이던 함수 매개변수는 지역 변수에 복사되어 실행되며 함수 내에서만 동작하고 외부에 반영되지 않는다. 객체의 경우에도 외부 객체에 프로퍼티만 추가될 뿐이며, 생성된 지역 객체는 함수가 실행을 마치는 즉시 파괴된다. 함수 매개변수는 지역 변수와 다를 것이 없다고 생각하라.
타입 판별
typeof 연산자는 변수가 문자열이나 숫자, 불리언, undefined라면 정확한 타입을 알 수 있다. 값이 객체이거나 null이면 "object"를 반환한다.
instanceof 연산자는 변수가 주어진 참조 타입의 인스턴트일 때 true를 반환하기 때문에, 어떤 타입의 객체인지 판별할 때 도움이 된다. 원시 값은 항상 false를 반환다.
요약: typeof 연산자는 값의 원시 타입을 판별하며 instanceof 연산자는 값의 참조 타입을 판별한다.
4.2 실행 컨텍스트와 스코프
실행 컨텍스트(execution context:EC)는 짧게 '컨텍스트'라고 부르며, 비할 바 없이 중요한 개념이다. 변수나 함수의 실행 컨텍스트는 다른 데이터에 접근할 수 있는지, 어떻게 행동하는지를 규정한다. 각 실행 컨텍스트에는 변수 객체(variable object:VO)가 연결되어 있으며 해당 컨텍스트에서 정의된 모든 변수와 함수는 이 객체에 존재한다. 이 객체를 코드에서 접근할 수는 없지만 이면에서 데이터를 다룰 때 이 객체를 이용한다.
가장 바깥쪽에 존재하는 실행 컨텍스트는 전역 컨텍스트이다. 웹 브라우저에서는 이 컨텍스트를 windows라고 부르며, 전역 변수와 함수는 모두 window 객체의 프로퍼티 및 메서드로 생성도니다.실행 컨텍스트는 포함된 코드가 모두 실행될 때 파괴되는데, 이때 컨텍스트 내부에서 정의된 변수와 함수도 함께 파괴된다. 전역 컨텍스트는 애플리케이션이 종료될 때, 예를 들어 웹 페이지에서 나가거나 브라우저를 닫을 때까지 유지된다.
함수를 호출하면 자체의 실행 컨택스트가 생성된다. 코드 실행이 함수로 들어갈 때마다 함수의 컨텍스트가 컨텍스트 스택에 쌓인다. 함수 실행이 끝나면 해당 컨텍스트를 꺼내고 컨트롤을 이전 컨텍스트에 반환한다.
컨텍스트에서 코드를 실행하면 변수 객체에 '스코프 체인(scope chain)'이 만들어진다. 스코프 체인의 목적은 실행 컨텍스트가 접근할 수 잇는 모든 변수와 함수에 순서를 정의하는 것이다.스코프 체인의 앞쪽은 항상 코드가 실행되는 컨텍스트의 변수 객체이다. 컨텍스트가 함수라면 '활성화 객체(activation object)'를 변수 객체로 사용한다. 활성화 객체는 항상 arguments 변수 단 하나로 시작한다(이 변수는 전역 컨텍스트에는 존재하지 않는다). 변수 객체의 다음 순서는 부모 컨텍스트이며 그 다음에는 부모의 부모 컨텍스트이다. 이런 식으로 스코프 체인의 마지막인 전역 컨텍스트에 도달할 때까지 계속한다. 식별자를 찾을 때는 스코프 체인 순서를 따라가며 검색하며, 찾을 수 없다면 일반적으로 에러가 발생한다.
내부 컨텍스트는 스코프 체인을 통해 외부 컨텍스트 전체에 접근할 수 있지만 외부 컨텍스트는 내부 컨텍스트에 대해 전혀 알 수 없다.
스코프 체인 확장
Scope Chain Augmentation 실행 컨텍스트에는 전역 컨텍스트와 함수 컨텍스트 두 가지 타입만 있지만(eval()은 세 번째 타입이 있다) 스코프 체인을 확장할 수 있는 방법도 있다.
try-catch 문의 catch 블록과 with 문은 모두 스코프 체인 앞 부분에 임시로 변수 객체를 만들며 코드 실행이 끝나면 사라진다. with 문에서는 해당 객체가 스코프 체인에 추가되며 catch 문에서는 에러 객체를 선언하는 변수 객체가 생성된다.
자바스크립트에는 블록 레벨 스코프가 없다
No Block-Level Scopes 블록 레벨 스코프를 지원하는 언어에서는 for문의 초기화 부분에서 선언한 변수가 오직 for문의 컨텍스트 안에서만 존재한다. 그러나 자바스크립트에서는 for문에서 선언한 i변수가 루프 실행이 끝난 후에도 존재한다.
변수 선언
var를 사용해 선언한 변수는 자동으로 가까운 컨텍스트에 추가된다. 함수 내부에서는 함수의 로컬 컨텍스트가 가장 가까운 컨텍스트이며 with 문 내부에서는 함수 컨텍스트가 가장 가까운 컨텍스트이다. 변수를 선언하지 않은 채(함수 내부에서 var 키워드가 생략된 채) 초기화하면 해당 변수는 자동으로 전역 컨텍스트에 추가된다.(외부에서 접근할 수 있게 된다)
항상 변수를 선언한 다음 초기화하라. 스트릭트 모드에서는 변수를 선언하지 않고 초기화하려 하면 에러를 낸다.
식별자 검색
컨텍스트 안에서 식별자를 참조하려면 검색부터 해야 하고, 스코프 체인을 따라 검색을 계속하여 전역 컨텍스트의 변수 객체에 도달할 때까지 계속한다. 식별자를 찾지 못하면 정의되지 않은 것으로 판단한다.
이러한 검색 과정 때문에 식별자가 로컬 컨텍스트에 정의되어 있으면 부모 컨텍스트에 같은 이름의 식별자가 있다 해도 참조할 수 없다.
4.3 가비지 콜렉션
자바스크립트는 실행 환경에서 코드 실행 중에 메모리를 관리한다는 의미에서 가비지 콜렉션(garbage collection) 언어이다. 필요한 메모리를 자동으로 할당하고 더 이상 사용하지 않는 메모리는 자동으로 회수하므로 직접 메모리를 관리하지 않아도 된다.
더 이상 사용하지 않는 변수를 식별하는 기준은 브라우저마다 다르지만 보통 구 가지 방법을 채용한다.
표시하고 지우기(Mark-and-Sweep)
가장 널리 쓰인다.
참조 카운팅(Reference Counting)
널리 쓰이지는 않지만, 이 방식의 주안점은 각 값이 얼마나 참조되었는지 추적한다는 것이다.
참조 카운팅 방법은 넷스케이프 내비게이터 3.0에서 처음 사용되었으나 즉시 순환 참조라는 심각한 문제가 뱔견되었다. 버전 4.0에서 참조 카운팅 방식을 버렸다.
IE 8과 그 이전 버전에서는 BOM과 DOM의 객체들이 참조 카운 방식을 이용하는 C++의 COM 객체로 구현되었다. 이 경우 순환 참조 문제를 해결하려면 해당 객체들에 null을 할당하여 연결을 끊어야 한다. IE 9에서는 BOM과 DOM 객체를 진정한 자바스크립트 객체로 만들어 이 상황을 다소 완화했다.
성능
가비지 컬렉터는 주기적으로 실행되며 메모리 내에 할당된 변수가 많다면 상당한 비용이 드는 작업이므로 실행 타이밍이 중요하다. IE는 가비지 컬렉터를 할당 숫자 기준으로 너무 자주 실행하여 성능 문제를 일으키는 것으로 악명이 높다.
메모리 관리
일반적으로는 가비지 컬렉션 환경에서는 개발자가 메모리 관리를 신경쓰지 않아도 되지만, 웹 브라우저에서 사용할 수 있는 메모리는 일반적인 테스크톱 애플리케이션의 가용 메모리에 비해 매우 적다.
페이지 성능을 올리기 위해 메모리 사용을 최적화하는 가장 좋은 방법은 코드 실행에 필요한 데이터만 유지하는 것이다. 필요없어진 데이터에는 null을 할당하여 참조를 제거(dereference)하는 편이 좋다. 수동으로 참조 제거해야 할 대상은 주로 전역 변수 및 전역 객체의 프로퍼티이다. 지역 변수는 컨텍스트를 빠져나가는 순간 자동으로 참조가 제거된다.
값의 컨텍스트를 없애기 위해서 변수에서 참조를 제거하면 다음 가비지 콜렉션을 실행할 때 해당 메모리가 회수된다.
 
5장. 참조 타입
참조 값(객체)이란 특정 '참조 타입'의 인스턴스이다. ECMAScript에서 참조 타입은 데이터와 기능을 그룹으로 묶는 구조이며, 객체가 가져야 할 프로퍼티와 메서드를 정의한다는 점 때문에 '객체 정의'라 불리기도 한다.
객체를 생성할 때는 new 연산자 뒤에 객체를 생성하는 함수인 '생성자'를 쓴다.
var person = new Object(); // Object()는 생성자이며 네이티브 참조 타입
5.1 Object 타입
Object의 인스턴스를 명시적으로 생성하는 두 가지 방법. 첫 번째는 new 연산자와 Object() 생성자를 함께 쓴다:
var person = new Object();
person.name = "Nolboo";
person.age = 19;
다른 방법은 여러 가지 프로퍼티를 쉽게 정의할 수 있는 '객체 리터럴' 표기법:
var person = {
    name : "Nolboo",
    age : 19
};
왼쪽 중괄호({ 기호)는 할당 연산자(=) 다음에 값이 나올 것으로 예상되는 '표현식 컨텍스트'에 있으므로 표현식의 시작으로 간주하며, 객체 리터럴의 시작이다.
var person = {}; // new Object()와 같이 기본 프로퍼티와 메서드만 가진 객체
객체 리터럴 표기법은 프로퍼티를 여러 개 쓸 때 가독성을 확보하는 용도로만 쓰길 권한다.
객체 리터럴 표기법을 사용해 객체를 생성할 때는 Object 생성자를 호출하지 않는다. 파이어폭스 2까지는 호출했지만 3부터는 바뀌었다.
옵션 매개변수를 많이 쓸 때 유용하다. 이름 붙은 매개변수가 더 편리하지만, 옵션 매개변수의 숫자가 많아지면 관리하기 어렵다. 가장 좋은 방법은 필수적인 매개변수에는 이름을 붙이고 나머지 옵션 매개변수는 객체 리터럴로 받는 방법이다.
객체 프로퍼티는 보통 '점 표기법'을 써서 접근하지만 '대괄호 표기법'을 쓸 수도 있다. 대괄호 표기법은 변수를 써서 프로퍼티에 접근할 수 있으며, 프로퍼티 이름에 문법 에러 문자가 있거나 키워드 및 예약어에 해당하는 프로퍼티 이름에도 접근할 수 있다.
5.2 Array 타입
데이터의 순서 있는 목록이며, 배열 슬롯에 어떤 타입의 데이터라도 넣을 수 있으며, 데이터를 추가하면 자동으로 커진다.
배열을 만드는 두 가지 방법. 첫 번째는 Array 생성자를 쓴다:
var colors = new Array)();
숫자 하나만 넘기면 숫자 길이만큼의 배열이 만들어지나, 숫자가 아닌 매개변수를 넘기면 해당 데이터 하나만 가진 배열이 생성된다.
var colors = new Array(3);          // 데이터가 3개 있는 배열을 만든다
var names = new Array("Nolboo");    // 문자열 "Nolboo"만 있는 배열을 만든다
Array 생성자를 쓸 때는 new 연산자를 생략할 수 있다.
두 번째는 대괄호 안에 데이터를 쉼표로 구분하는 '배열 리터럴' 표기법이다:
var colors = ["red", "blue", "green"];  // 문자열이 3개 있는 배열을 만든다
var names = [];                         // 빈 배열을 만든다
length 프로퍼티는 배열에 저장된 데이터의 개수이며 항상 0 이상의 값을 반환한다. 흥미로운 것은 읽기 전용이 아니라서 값을 바꾸면 배열 길이가 그것에 맞게 바뀌면서 데이터를 제거하거나 빈 슬롯을 추가한다.
배열에는 최대 4,294,967,295개의 데이터를 담을 수 있다. 그 이상의 데이터를 담으려 하면 예외가 발생하여 오래 실행되는 스크립트 에러가 발생할 수 있다.
배열 감지
전역 스코프가 하나뿐인 단순한 웹 페이지에서는 instanceof 연산자를 쓴다. 웹 페이지에 프레임이 여러 개 있을 경우의 문제를 우회하기 위해 Array.isArray() 메서드를 사용하여 실행 컨텍스트와 무관하게 주어진 값이 배열인지를 알기 위한 것이다.
변환 메서드
toLocaleString(), toString(), valueOf() 메서드가 있다. toString()과 valueOf()는 쉼표로 분리된 문자열의 형태로 같은 값을 반환한다.
toLocaleString()을 배열에서 호출하면 각 값에서 toLocaleString()을 호출해서 문자열 값을 얻는다는 점이 나머지 두 메서드와 다른 점이다.
join() 메서드로 문자열 구분자를 지정할 수 있다. 매개변수를 쓰지 않거나 undefined를 쓰면 구분자로 쉼표를 사용한다.
배열에서 join(), toLocaleString(), toString(), valueOf() 메서드를 호출했을 때 null이나 undefined인 데이터는 빈 문자열로 표시된다.
스택 메서드
push()와 pop() 메서드는 배열의 기본 메서드이면서 배열을 스택처럼 동작하게 한다. 스택은 'LIFO: last-in-first-out' 구조이며, 마지막에 추가된 데이터가 제일 먼저 삭제된다. 스택에서 데이터 '삽입(push)'과 '제거(pop)'는 스택의 맨 위 단 한 지점에서만 발생한다.
push() 메서드의 매개변수 숫자는 제한이 없으며 받은 매개변수를 그대로 배열에 추가한 후 늘어난 배열 길이를 반환한다. pop() 메서드는 반대로 배열의 마지막 데이터를 제거하고 length 프로퍼티를 줄여서 반환한다.
큐 메서드
큐는 데이터 입출력을 'FIFO: first-in-first-out'로 제한하는 데이터 구조이다. 목록 마지막에 데이터를 추가하며 목록 맨 앞에서 데이터를 꺼낸다. shift() 메서드는 배열의 첫 번째 데이터를 꺼내서 반환하며 배열 길이는 1만큼 줄어든다.
unshift() 메서드는 shift()와 반대로 동작하며, 매개변수로 넘겨받은 데이터를 배열의 처음에 추가하며 늘어난 배열 길이를 반환한다.
정렬 메서드
배열 순서를 직접 조작하는 메서드는 reverse()와 sort() 두 가지이다. reverse() 메서드는 단순히 배열에 저장된 데이터 순서를 뒤집는다. sort() 메서드는 데이터를 정순, 즉 가장 작은 값이 첫 번째에 오고 가장 큰 값이 마지막에 오도록 정렬한다. 이를 위해 이면에서 String() 함수를 호출해 데이터를 문자열로 변환한 후에 이를 비교하여 순서를 판단한다. 숫자만으로 이루어진 배열에서 똑같이 동작하는 단점이 있다. 이럴 때는 '비교함수'를 넘겨서 순서를 조절한다.
sort() 메서드의 매개변수로 쓸 수 있는 비교 함수 예제:
function compare(value1, value2) {
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
        return 1;
    } else {
        return 0;
    }
}
reverse()와 sort()는 모두 자신을 호출한 배열에 대한 참조를 반환하므로, array.sort(compare).reverse() 와 같이 체인 형태로 쓸 수 있다.
숫자 타임이나 Date 객체처럼 숫자형 값을 반환하는 객체에서의 비교함수는 두 값을 빼기만 하면 된다.
조작 메서드
concat() 메서드는 현재 배열을 복사한 후 메서드의 매개변수를 새 배열 마지막에 추가하여 반환한다.
slice() 메서드는 매개변수를 하나만 넘기면 해당 인덱스에서 끝까지 모든 데이터를 가져오고, 매개변수를 두 개 넘기면 첫 번째 매개변수에 해당하는 인덱스부터 두 번째 매개변수에 해당하는 인덱스의 바로 앞까지 가져온다. 원래 배열은 전혀 건드리지 않는다.
매개변수를 음수로 넘기면 배열 길이 해당 값을 더한 숫자를 대신 사용한다. 예로, 길이가 5인 배열에서 slice(-2, -1)를 호출한 결과는 slice(3, 4)를 호출한 결과와 같다. 두 번째 매개변수가 첫 번째 매개변수보다 작으면 빈 배열을 반환한다.
splice() 메서드의 주요 목적은 배열 중간에 데이터를 삽입하는 것이며, 세 가지 방법으로 사용된다.
  • 삭제 - 첫 번째 매개변수(인덱스)부터 두 번째 매개변수(개수)만큼 삭제한다.
  • 삽입 - 삽입할 위치, 0(아무것도 삭제하지 않는다), 삽입할 데이터 순서로 3개 이상의 매개변수를 넘긴다.
  • 대체 - 삽입과 삭제를 조합한다. splice(2, 1, "red", "green")은 인덱스 2의 데이터를 삭제한 다음 문자열 "red"와 "green"을 인덱스 2에 삽입한다.
splice() 메서드는 항상 원래 배열에서 삭제한 데이터의 배열을 반환한다. 삭제한 것이 없다면 빈 배열을 반환한다.
위치 메서드
indexOf()와 lastIndexOf() 메서드에서 첫 번째 매개변수는 검색할 데이터이고, 두 번째 매개변수는 검색을 시작할 인덱스이다. indexOf() 메서드는 배열의 처음(인덱스 0)에서 검색을 시작하여 마지막까지 검색하고, lastIndexOf() 메서드는 배열의 마지막에서 검색을 시작하여 처음까지 검색한다. 두 메서드는 찾아낸 데이터의 인덱스를 반환하며, 찾지 못하면 -1을 반환한다. === 연산자로 비교해서 일치하는(타입까지 일치하는) 데이터를 검색한다.
var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4));
alert(numbers.lastIndexOf(4));
alert(numbers.indexOf(4, 4));
alert(numbers.lastIndexOf(4, 4));
var person = { name: "Nolboo" };
var people = [{ name: "Nolboo" }];
var morePeople = [person];
alert(people.indexOf(person));
alert(morePeople.indexOf(person));
세번째 결과부터 잘 이해가 안됨;;
반복 메서드
반복 메서드는 배열의 각 데이터에서 실행할 함수와 함수를 실행할 스코프 객체를 매개변수로 받는다. 콜백함수는 모두 데이터, 데이터의 인덱스, 배열 자체의 세 가지 매개변수를 받는다.
  • every() - 반환값이 전부 true이면 true를 반환한다.
  • filter() - 반환값이 true인 데이터를 새 배열에 저장하여 반환한다.
  • forEach() - 반환값이 없으며, 해당 배열에 for 문을 실행한 것과 같다.
  • map() - 결과를 새 배열에 저장하여 반환한다.
  • some() - 반환값 중 하나라도 true이면 true를 반환한다.
감소 메서드
reduce()와 reduceRight()는 배열을 순회하며 콜백함수를 실행하고 값을 하나 만들어 반환한다. reduce() 메서는 배열의 첫 번째 데이터에서 시작하여 마지막까지, reduceRight()는 배열의 마지막 데이터에서 시작하여 첫 번째까지 진행한다.
첫 번째 매개변수는 각 데이터에서 실행할 콜백 함수이고, 두 번째 매개변수는 감소 작을 시작할 초기값이다. 콜백함수가 넘겨받는 매개변수는 이전 값, 현재 값, 현재 값의 인덱스, 현재 배열 네 가지이다. 콜백함수가 반환하는 값은 자동으로 다음 데이터에서 실행하는 콜백 함수의 첫 번째 매개변수가 된다.
5.3 Date 타입
Date 타입은 1970년1월1일 자정부터의 밀리초 숫자로 저장하며, 285,616년 전후의 날짜까지를 정확히 표현할 수 있다.
날짜 객체를 생성할 때는 new 연산자 다음에 Date 생성자를 쓰며, 매개변수를 넘기지 않으면 현재 날짜와 시간이 저장된다.
var now = new Date();
밀리초 매개변수의 메서드는 Date.parse()와 Date.UTC()가 있다.
Date.parse() 메서드는 날짜 문자열을 받고 밀리초로 변환을 시도한다.
  • 월/일/년(6/13/2004)
  • 월이름 일, 년(January 12, 2004)
  • 요일 월이름 일 년 시:분:초 타임존(Tue May 25 2004 00:00:00 GMT-0700)
  • ISO 8601 확장형식 YYYY-MM-DDTHH:mm:ss.sssZ(2004-05-25T00:00:00) 이 형식은 ECMAScript 5 호환 브라우저에서만 지원된다.
올바른 날짜 형식이 아닐 때는 NaN을 반환한다.
Date 생성자는 (Date.parse() 메서드 없이) 문자열을 넘겨받으면 이면에서 Date.parse()를 호출한다.
Date.UTC()의 매개변수는 해당 시각의 년, 월 인덱스(0이 1월), 일(1~31), 시(0~23), 분, 초, 밀리초이다. 필수는 년, 월 인덱스 2개이며, 일을 생략하면 1일로 간주하며, 다른 매개변수는 모두 0으로 간주한다.
Date 생성자에 Date.UTC() 형식의 매개변수를 넘기면 이면에서 Date.UTC()를 호출하지만 날짜와 시간을 GMT가 아닌 지역 시간을 사용한다.
ECMAScript 5에서는 현재 시각을 밀리초로 반환하는 now() 메서드가 추가되었다. 코드의 실행시간을 측정하는 프로파일링 작업을 쉽게 할 수 있다.
상속된 메서드
Date 타입 역시 toLocaleString(), toString(), valueOf() 메서드를 오버라이드하나, 조금 다른 값을 반환하며 브라우저마다 반환 형식이 상당한 차이가 있어 디버그 목적으로나 쓸만하지 사용자에게 표시하기에는 적당하지 않다.
valueOf() 메서드가 반환하는 값에는 문자열이 전혀 들어있지 않은 밀리초 표현을 쓴다. 이를 통해 날짜 순서를 쉽게 비교할 수 있다.
날짜 표시 메서드
toDateString(), toTimeString(), toLocaleDateString(), toLocaleTimeString(), toUTCString 등이 있으나 반환하는 문자열이 브라우저에 따라 크게 달라 사용자 인터페이스에 일관된 날짜 형식을 쓰고 싶다면 그대로 사용할 수는 없다.
날짜/시간 부속 메서드
날짜의 특정 부분을 가져오거나 설정하는 데 쓰인다. 표 참조
5.4 RegExp 타입
var expression = /pattern/flags;
패턴 부분에는 정규 표현식을 나타내는 식을 쓰며, 문자 클래스, 수량자, 그룹, 룩어헤드, 역참조 등이 포함된다. 플래그를 통해 어떻게 동작할지 나타내며, 세 가지가 있다.
  • g - 전역모드. 지정하면 문자열에서 패턴을 찾는 즉시 종료하지 않고 문자열 전체에서 동작한다.
  • i - 대소문자 비구분 모드.
  • m - 여러 줄 모드. 테스트의 줄 끝에 도달해도 멈추지 않고 계속 패턴을 찾는다.
다음 '메타문자'를 패턴에 쓸 때는 반드시 역슬래시로 이스케이프해야 한다.
( [ { \ ^ $ | } ] ) ? * + .
정규 표현식 리터럴이나 RegExp 생성자를 사용하여 정규 표현식을 생성할 수 있다. RegExp 생성자의 매개변수는 "패턴이 될 문자열"과 옵션인 "플래그를 나타내는 문자열"이며, RegExp 생서자에 정규 표현식 리터럴을 넘기면 안 된다. RegExp 생성자에 메타 문자를 쓸 때는 반드시 이중으로 이스케이프해야 한다.
ECMAScript 3판에서 리터럴로 생성한 정규 표현식은 항상 같은 RegExp 인스턴스를 공유하지만 RegExp 생성자는 호출할 때마다 새로운 인스턴스를 생성한다. ECMAScript 5에서는 리터럴로 정규 표현식을 생성할 때도 RegExp 생성자를 호출하게끔 명확히 정했다.
정규 표현식 인스턴스 프로퍼티
RegExp 인스턴스에는 다음 프로퍼티가 있으며 각 프로퍼티는 패턴에 대한 정보를 포함한다.
  • global - g 플래그 설정 여부 불리언 값.
  • ignoreCase - i 플래그 설정 여부 불리언 값.
  • lastIndex - 패턴 매칭의 시작 위치를 나타내는 정수 값이며, 항상 0에서 시작한다.
  • multiline - m 플래그 설정 여부 불리언 값.
  • source - 정규 표현식을 생성한 문자열. 항상 리터럴 형식으로 반환하되 여닫는 /문자는 포함되지 않는다. 생성자를 통해 생성되었더라도 리터럴 형식으로 반환한다.
정규 표현식 인스턴스 메서드
가장 많이 쓰는 메서드는 그룹을 캡처할 의도로 만들어진 exec() 메서드이며, 패턴을 테스트할 문자열을 매개변수로 받고 패턴에 일치하는 문자열 배열을 반환한다. 일치하는 부분을 찾을 수 없을 때는 null을 반환한다. 반환하는 배열은 Array의 인스턴스인 동시에 일치 위치를 나타내는 index 프로퍼티, exec() 메서드에 넘긴 문자열인 input 프로퍼티가 추가된다. exec() 메서드가 반환하는 첫 번째 데이터는 패턴에 일치하는 부분 전체이며, 다른 데이터는 표현식에서 캡처한 부분이다. 캡처 그룹이 없다면 반환하는 배열에는 데이터가 단 하나만 존재한다.
exec() 메서드는 g 플래그가 설정되어 있더라도 한 번에 한 가지 매치에 관한 정보만 반환한다. g 플래그가 설정되어 있지 않으면 exec()를 같은 문자열에 여러 번 호출하더라도 첫 번째 매치에 대한 정보만 반환한다. 패턴에 g 플래그가 설정되어 있으면 exec()를 호출할 때마다 문자열 안쪽으로 더 깊숙이 들어가며 검색한다.
test() 메서드는 문자열이 패턴에 일치할 때는 true를 반환하고 그렇지 않으면 false를 반환한다. if문에서 자주 사용한다.
객체 프로토타입에서 상속한 메서드 toLocaleString()과 toString()은 정규 표현식을 어떻게 생성했는지에 관계없이 리터럴 표현을 반환한다. valueOf() 메서드는 정규 표현식 자체를 반환한다.
RegExp 생성자 프로퍼티
정식 이름과 짧은 이름이 있는데 오페라는 짧은 이름을 지원하지 않는다. 다음 표는 RegExp 생성자의 프로퍼티이다.
정식이음
짧은 이름
설명
input
$_
마지막으로 테스트한 텍스트
lastMatch
$&
마지막으로 일치한 문자열
lastParen
$+
마지막으로 일치한 캡처 그룹
leftContext
$'
input 텍스트에서 lastMatch 앞에 있는 문자열
multiline
$*
모든 정규 표현식이 다중 행 모드를 사용해야 하는지 표현하는 불리언 값
RightContext
$'
input 텍스트에서 lastMatch 다음에 오는 문자열
짧은 이름은 반드시 대괄호 표기법을 써야한다.
정규 표현식 생성자에는 캡처 그룹을 아홉 개까지 지정할 수 있는 프로퍼티도 있으며, RegExp.$1 형식으로 쓰면 첫 번째 캡처 그룹을 나타내고, RegExp.$9은 아홉 번째 캡처 그룹을 나타낸다. exec()나 test()를 호출할 때마다 자동으로 값이 설정된다.
패턴의 한계
ECMAScript의 정규 표현식은 완전히 개발된 상태이지만 펄 같은 언어에서 가능한 고급 정규 표현식 기능에는 미치지 못한다. 다음 기능은 ECMAScript 정규 표현식에서 지원하지 않는 기능이다. 자세한 정보는 Regular-Expressions.info - Regex Tutorial, Examples and Reference - Regexp Patterns를 참고한다.
  • 테스트의 처음과 마지막에 일치하는 \A와 \Z
  • 룩비하인드
  • 병합 클래스
  • 최소 그룹(atomic group)
  • 유니코드 지원(한 번에 한 문자를 찾는 기능은 지원한다.)
  • 이름 붙은 캡처 그룹
  • s(한 줄 모드), x(공백 무시 모드) 플래그
  • 조건문
  • 정규 표현식 주석
5.5 Function 타입
모든 함수는 function 타입의 인스턴스이며 프로퍼티와 메서드가 있으며, 함수 이름은 단순히 함수 객체를 가리키는 포인터이다.
보통 함수 선언 문법(함구 표현식)을 통해 정의한다.
fuction sum (num1, num2) {
    return num1 + num2;
}
함수 선언은 다음 함수 표현식과 거의 정확히 일치한다.
var sum = function (num1, num2) {
    return num1 + num2;
};
이 코드는 변수 sum을 정의하면서 함수로 초기화하였다. 함수 표현식에서 function 키워드 다음에 함수 이름이 없는 점에 주목한다. 변수 sum으로 함수를 참조하므로 함수 이름은 필요치 않다. 또한 표현식 마지막에 다른 변수 초기화 문장과 마찬가지로 세미콜론을 쓴 점도 눈여겨 본다.
함수를 정의하는 마지막 방법은 Function 생성자를 이용하는 방법이다. Function 생성자에 넘기는 매개변수 숫자에는 제한이 없다. 매개변수 중 마지막은 함수 바디로 간주하며 그 이전에 있는 매개변수는 함수의 매개변수로 전달된다.
var sum = new Function("num1", "num2", "return num1 + num2") // 권장하지 않음.
오버로딩 없음(다시 설명합니다)
함수 이름이 단순한 포인터임을 이해하면 ECMAScript에서 함수 오버로딩이 불가능한 이유도 이해할 수 있다.
함수 선언 vs 함수 표현식
자바스크립트 엔진이 실행 컨텍스트에 데이터를 불러올 때 중요한 차이가 하나 있다. 함수 선언은 어떤 코드도 실행하기 전에 이미 모든 실행 컨텍스트에 접근하고 실행할 수 있지만, 함수 표현식은 코드 실행이 해당 줄까지 진행하기 전에는 사용할 수 없다.
alert(sum(10,10));
function sum(num1, num2) {
    return num1 + num2;
}
이 코드는 아무 에러 없이 실행되는데, 코드를 실행하기 전에 '함수 선언 호이스팅'을 통해 함수 선언을 읽고 실행 컨텍스트에 추가하기 때문이다. 자바스크립트 엔진은 코드를 평가할 때 제일 먼저 함수 선언을 찾은 다음 이들을 맨 위로 올린다. 즉 함수 선언이 소스코드에서 해당 함수를 실행하는 부분보다 뒤에 있어도 자바스크립트 엔진이 함수 선언을 '끌어올린다(hoist)'.
alert(sum(10,10));
var sum = function (num1, num2) {
    return num1 + num2;
};
위의 코드는 에러를 내는데, 함수가 함수 선언이 아니라 초기화 문장의 일부이기 때문이다. 코드 첫 줄에서 '예기치 못한 식별자(unexpected identifier)'에러를 낸다. 이런 차이를 제외하면 함수를 이름으로 호출할 때 두 문법 사이에 다른 차이는 없다.
함수 표현식을 쓰면서도 함수 선언처럼 보이게, 즉 var sum = function sum() {}처럼 쓸 수 있다.
값처럼 쓰는 함수
ECMAScript에서 함수 이름은 단지 변수일 뿐이므로 함수도 다른 값이 올 수 있는 곳이라면 어디든 올 수 있으며, 함수를 다른 함수에 매개변수로 넘기거나, 함수가 실행 결과로 다른 함수를 반환하는 일이 가능하다.
함수의 내부 구조
함수 내부에는 arguments, this라는 특별한 객체가 있다. arguments 객체는 배열과 비슷한 객체이며 함수에 전달된 매개변수를 모두 포함한다.
this는 함수가 실행 중인 컨텍스트 객체에 대한 참조이다. 함수를 웹 페이지의 전역 스코프에서 호출했다면 this 객체는 window를 가리킨다.
caller 프로퍼티에는 해당 함수를 호출한 함수에 대한 참조를 저장하며 전역 스코프에서 호출했다면 null이 저장된다.
함수의 프로퍼티와 메서드
모든 함수에 공통인 프로퍼티는 length와 prototype이다. length 프로퍼티는 함수가 넘겨받을 것으로 예상하는 이름 붙은 매개변수의 숫자이다.
prototype 프로퍼티는 모든 참조 타입의 인스턴스 메서드가 존재하는 곳이다. 즉 toString()이나 valueOf() 같은 메서드는 prototype에 존재하며 객체 인스턴스는 이에 접근한다. prototype 프로퍼티는 개발자 자신만의 참조 타입과 상속을 정의할 때 매우 중요하며, 열거할 수 없는 프로퍼티이므로 for-in 문에 나타나지 않는다.
apply()와 call() 메서드는 소유자인 함수를 호출하면서 this를 넘기는데, 결과적으로 함수 내부에서 this 객체의 값을 바꾸는 것이나 마찬가지이다. apply() 메서드는 매개변수로 소유자 함수에 넘길 this와 매개변수 배열을 받는다. 두 번째 매개변수는 Array의 인스턴스일 수도 있고 arguments 객체일 수도 있다. call 메서드는 매개변수를 전달하는 방식이 다르다. this가 첫 번째 매개변수인 것은 같지만, 반드시 매개변수를 각각 나열해야 한다. arguments 객체를 그대로 전달해도 되거나 데이터가 배열 형태로 준비되어 있다면 apply()가 나을 것이고, 그렇지 않다면 call90이 나을 것이다.
ECMAScript 5판에서 정의된 bind()는 새 함수 인스턴스를 만드는데 그 this는 bind()에 전달된 값이다.
5.6 원시 래퍼 타입
Boolean, Number, String은 원시 값을 편리하게 조작하기 위해 디자인된 참조타입이다. 원시 값을 읽을 때마다 이에 해당하는 래퍼 타입이 이면에서 생성되므로 메서드를 사용할 수 있다.
참조 타입과 원시 래퍼 타입의 주요 차이는 그 생명 주기이다. new 연산자를 사용해 참조 타입의 인스턴스를 만들면 스코프를 벗어날 때까지 메모리에 존재하지만, 자동으로 생성된 원시 래퍼 타입은 코드의 해당 행을 벗어나는 즉시 파괴된다. 따라서 원시 래퍼 타입에는 런타임에 프로퍼티나 메서드를 추가할 수 없다.
Object 생성자에 문자열을 넘기면 String의 인스턴스가 생성되며 숫자를 넘기면 Number의 인스턴스가, 불리언을 넘기면 Boolean의 인스턴스가 생성된다. 염두에 둘 점은 new를 사용해 원시 래퍼 생성자를 호출한 것과 같은 이름의 형 변환 함수를 호출한 결과는 다르다는 것이다.
불리언 타입
원시 불리언 값과 Boolean 객체를 반드시 구분할 수 있어야 하며 Boolean 객체는 절대 쓰지 마라.
Number 타입
toFixed() 메서드는 지정한 만큼의 정확도로 소수점을 찍은 문자열을 반환하며, 매개변수로 지정한 자리 수보다 크다면 반올림한다.
일반적으로 소수점 이하 20자리까지 지원한다.
toExponential() 메서드는 숫자를 지수 표기법 문자열로 반환한다.
toPrecision() 메서드는 숫자에 따라 지수 표기법이나 소수점 표기법으로 선택하여 반환한다. 숫자 표현에 사용할 총 자리 수를 매개변수로 받는다(지수 부분은 받지 않는다)
일반적으로 1부터 21 사이의 자리 수를 넘길 수 있다.
String 타입
문자열을 나타내는 객체이며 String 생성자를 쓴다.
var stingObject = new String("hello world");
글자 메서드
charAt()와 charCodeAt()는 원하는 문자의 인덱스를 매개변수로 받는다. charAt()은 한 글자의 문자열로 반환하고, charCodeAt()는 해당하는 문자의 문자코드를 반환한다.
문자열 조작 메서드
concat() 메서드는 문자열을 병합한다. + 연산자가 더 자주 쓰이며 더 빨리 동작한다.
slice(), substr(), substring() 메서드는 문자열 일부로 새 문자열을 만든다. 어디서부터 가져올 것인가를 첫 번째 매개변수로, 어디까지(직전)가 두 번째이다. substr()의 두 번째 매개변수는 문자 몇 개를 가져올지이다. 세 가지 모두 두 번째 매개변수를 생략하면 열 전체 길이가 기본 값이다.
var = stringValue = "hello world";
alert(stringValue.slice(3));        // "lo world"
alert(stringValue.substring(3));    // "lo world"
alert(stringValue.substr(3));       // "lo world"
alert(stringValue.slice(3, 7));     // "lo w"
alert(stringValue.substring(3, 7)); // "lo w"
alert(stringValue.substr(3, 7));    // "lo worl"
slice()는 음수 매개변수를 받으면 전체 문자열 길이에 해당 매개변수를 더한 값을 사용한다. substr()은 첫 번째 매개변수에 음수를 받으면 전체 문자열 길이에 해당 매개변수를 더한 값을 사용한다. 두 번째 매개변수가 음수이면 0을 사용한다. substring()은 음수 매개변수를 모두 0으로 바꾼다.
문자열 위치 메서드
indexOf()와 lastIndex()는 문자열의 위치를 찾으면 위치를 반환하며 찾지 못했을 때는 -1을 반환한다. indexOf()는 문자열 처음에서, lastIndexOf()는 문자열 마지막에서 검색을 시작한다. 두 번째 매개변수는 옵션이며, 검색을 시작할 인덱스이다.
trim() 메서드
문자열을 복사한 후 앞뒤 공백을 모두 제거한 결과를 반환한다.
대소문자 메서드
toLowerCase(), toLocaleLowerCase(), toUpperCase(), toLocaleUpperCase() 네 가지. 일부 언어에서는 대소문자 변환에 따른 특별한 규칙이 필요하며 이 때문에 지역 메서드가 필요하다. 일반적으로 작성한 코드가 어느 지역에서 실행될지 모른다면 지역 메서드를 쓰는 편이 안전한다.
문자열 패턴 매칭 메서드
String 타입에서 문자열 내에서 패턴 매칭하는 메서드 중 가장 많이 쓰이는 것은 match()이다. RegExp 객체의 exec() 메서드와 같은 결과를 반환한다. 매개변수로 정규 표현식 리터럴이나 RegExp 객체를 하나 받는다.
search() 메서드는 패턴에 일치하는 첫 번째 문자열 인덱스를 반환하며 찾지 못했을 때는 -1을 반환한다. 항상 문자열의 처음에서 검색을 시작한다.
replace()는 문자열 일부를 바꾼다. 첫 번째 매개변수를 RegExp 객체 또는 문자열(단, 이 문자열을은 정규표현식으로 변환되지 않는다)이고, 두 번째 매개변수는 문자열 또는 문자열을 반환하는 함수이다. 일치하는 문자열 전체를 바꾸려면 정규 표현식에 g 플래그를 써서 넘긴다.
두 번째 매개변수에 문자열을 쓸 대 정규 표현식에서 얻은 정보를 다양한 방법으로 응용하는 특수문자가 있다.
특수문자
대응 문자열
$$
$
$&
패턴에 일치하는 문자열 전체. RegExp.lastMatch와 같다.
$'
일치하는 문자열 앞의 텍스트. RegExp.rightContext와 같다.
$'
일치하는 문자열 다음의 텍스트. RegExp.leftContext와 같다.
$n
'n'번째 캡처 그룹이며 'n'은 0부터 9사이.
$nn
'nn'번째 캡처 그룹이며 'nn'은 00부터 99사이.
replace()의 두 번째 매개변수에는 함수도 쓸 수 있다. 일치하는 것이 하나뿐일 때 콜백함수는 자동으로 매개변수를 세 개 받는다. 일치하는 문자열, 해당 문자열의 위치, 전체 문자열. 일치하는 것이 여럿일 때는 이들 모두가 매개변수로 전달되며 그다음에는 매치한 위치, 마지막으로 원래 문자열이 전달된다. 콜백함수는 반드시 문자열을 반환해야 하며 이 문자열로 일치한 문자열을 대체합니다.
htmlEscape() 함수는 HTML에서 사용할 수 있도록 특수문자를 이스케이프한다. HTML에서 그대로 쓸 수 없는 <, >, &, " 문자를 이스케이프하는 가장 쉬운 방법은 정규 표현식으로 해당 문자를 검색한 다음에 HTML 엔티티를 반환하는 함수를 쓰는 것이다.
split() 메서드는 텍스트를 구분자를 기준으로 분리해서 배열에 담아 반환한다. 구분자에는 문자열과 RegExp 객체를 쓸 수 있는데 문자열을 정규 표현식으로 간주하지는 않는다. 두 번째 매개변수(옵션)는 반환받을 배열의 크기를 지정하는 숫자이다.
split()과 정규 표현식의 캡처 그룹의 브라우저 간 비호환성 문제는 스티브 레비슨의 자바스크립트 split 버그가 마침내 수정되었다을 읽어본다.
localeCompare() 메서드
문자열 두 개를 비교한 후 -1, 0, 양수(대부분 1)를 반환한다. 메서드를 호출한 텍스트가:
  • 매개변수로 넘긴 문자열보다 알파벳 순서상 뒤에 있다면 : -1
  • 매개변수 문자열과 일치하면 : 0
  • 매개변수로 넘긴 문자열보다 알파벳 순서상 앞에 있다면 : 양수(대부분 1이지만 브라우저에 따라 값이 다룰 수 있어 추상화한 함수를 만드는 편이 좋다)
fromCharCode() 메서드
String 생성자에서 문자 코드를 받아 이를 문자열로 변환하는 메서드.
HTML 메서드
자바스크립트에서 동적으로 HTML 형식을 생성하기 위한 메서드이나 시맨틱 마크업을 해치므로 거의 사용하지 않는다.
5.7 내장된 싱글톤 객체
Global, Math. 싱글톤(singleton)이란 인스턴스를 한 개만 만들도록 하는 객체. Object, Array, String 등은 인스턴스를 여럿 만들어 사용하지만 Math 객체는 인스턴스를 만들지 않고 메서드의 네임스페이스 용도로만 사용한다.
Global 객체
Global 객체는 명시적으로 접근할 수 없다는 점에서 ECMAScript에서 가장 독특한 객체이다. ECMA-262는 Global 객체를 소유자가 없는 모든 프로퍼티와 메서드를 담는 객체로 정의한다. 사실 전역 변수나 전역 함수라는 것은 존재하지 않는다. 전역에서 정의한 변수와 함수는 모두 Global 객체의 프로퍼티가 된다.
URI 인코딩 메서드
브라우저에 전달한 URI를 인코드하는 메서드. 특별한 UTF-8 인코딩을 써서 URI에 사용할 수 없는 문자를 브라우저가 인식하고 이해할 수 있는 문자로 바꾼다.
encodeURI() 메서드는 전체 URI를, encodeURIComponent()는 URI 일부분만 조작한다. encodeURI()는 :이나 /, ?, #처럼 URI 일부분으로 쓰이는 특수문자는 인코드하지 않지만 encodeURIComponent()는 비표준 문자를 모두 인코드하며, URI 마지막에 추가할 문자열에만 사용할 수 있다.
일반적으로 베이스 URI 뒤에 추가할 쿼리스트링을 인코드하는 경우가 많으므로 encodeURIComponent()를 자주 쓰게 된다.
decodeURI()와 decodeURIComponent()는 반대.
위 네 가지 URI 메서드는 ECMA-232 3판에서 폐기한 escape(), unescape() 메서드를 대체한다. 배포할 코드에 ASCII 문자만 변환하는 escape()나 enscape()를 쓰지 마라.
eval() 메서드
ECMAScript에서 가장 강력한 메서드이다. ECMAScript 인터프리터 자체인 듯 동작하며 매개변수로 문자열 하나 받는데 이 문자열은 실행할 수 있는 ECMAScript 코드여야 한다.
다음 두 개의 문장은 같다.
eval("alert('hi')");
alert("hi");
인터프리터가 eval()을 만나면 매개변수를 실제 ECMAScript 문자으로 해석하여 eval()이 있던 위치에 삽입한다. eval()이 실행하는 코드는 eval()을 호출한 실행 컨텍스트의 일부분으로 간주되며 해당 컨텍스트와 같은 스코프 체인을 가진다.
eval() 내부에서 정의한 변수나 함수는 끌어올림의 대상이 아니다. 코드 파싱 단계에서는 문자열이다. 변수나 함수로 정의되는 시점은 eval()이 실행되는 시점이다.
스트릭트 모드에서는 eval() 내부에서 정의한 변수나 함수에 접근할 수 없으며, eval에 값을 할당할 수 없다.
문자열을 코드로 변환하는 기능은 대단히 강력하지만 대단히 위험하기도 하다. eval()을 쓸 때는 항상 주의해야 하며, 사용자가 입력한 데이터에 eval()을 쓸 때는 특히 더 조심해야 한다. 악의적인 사용자가 당신의 사이트나 애플리케이션 보안을 해치는 값을 입력할 수 있기 때문이다.(코드 주입)
Global 객체의 프로퍼티
undefined, NaN, Infinity, Object, Array, Function, Boolean, String, Number, Date, RegExp, Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError 등이 있으며, ECMAScript 5판에서는 undefined, NaN, Infinity에 값을 할당할 수 없음을 명확히 했다. 이들에 값을 할당하려 하면 스트릭트 모드가 아닐 때에도 에러가 난다.
Widnow 객체
ECMA-262에서는 Global 객체에 직접 접근할 수 없도록 했지만, 웹 브라우저에서는 window 객체를 통해 Global 객체에 접근할 수 있다. 전역 스코프에서 선연한 변수와 함수는 모두 window 객체의 프로퍼티가 된다.
var color = "red";
function sayColor(){
    alert(window.color);
}
window.sayColor();  // "red"
Math 객체
수학 공식과 각종 상수를 Math 객체에 저장한다. 필요한 계산이 Math 객체에 구현되어 있다면 직접 만들기보다 빠르다.
Math 객체의 프로퍼티
프로퍼티
설명
Math.E
자연로그의 밑수인 e의 값
Math.LN10
10의 자연로그
Math.LN2
2의 자연로그
Math.LOG2E
e의 밑수가 2인 로그(base 2)
Math.LOG10E
e의 밑수가 10인 로그(base 10)
Math.PI
파이값
Math.SQRT1_2
1/2의 제곱근
Math.SQRT2
2의 제곱근
min()과 max() 메서드
min()과 max() 메서드는 한 그룹의 숫자 중에서 가장 작은 숫자와 가장 큰 숫자를 찾는다. 매개변수 숫자에 제한이 없다.
배열 데이터 중에서 최대값이나 최소값을 찾을 때는 apply() 메서드를 쓸 수 있다.
var values = [1, 2, 3, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);
이 테크닉의 요점은 apply()의 첫 번째 매개변수로 Math 객체를 넘겨서 this가 정확히 설정되도록 하는 것이다. 이렇게 하면 두 번째 매개변수로 배열을 넣었을 때 올바르게 동작한다.
반올림 메서드
Math.ceil()은 올림, Math.floor()는 내림, Math.round()는 반올림이다.
random() 메서드
0과 1 사이의 난수를 반환하되 0이나 1을 반환하지는 않는다.
number = Math.floor(Math.random() * total_number_of_choices + first_possible_number)
경우의 수를 세는 것보다 범위만 제공하여 그 사이의 난수를 반환하는 함수를 만드는 편이 편리하다.
function selecForm(lowerValue, upperValue) {
    var choices = upperValue - lowerValue + 1;
    return Math.floor(Math.random() * choices + lowerValue);
}
var num = selectForm(2,10);
alert(num); // 2 10사이의 난수. 2 10을 포함
var colors = ["red", "green", "blue", "yellow", "black", "purple", "brown"];
var color = colors[selectFrom(0, colors.length-1)];
기타 메서드
메서드
반환값
Math.abs(num)
num 절대값
Math.exp(num)
Math.E의 num제곱
Math.log(num)
num의 자연로그
Math.pow(num, power)
num의 power제곱
Math.sqrt(num)
num의 제곱근
Math.acos(x)
x의 아크코사인
Math.asin(x)
x의 아크사인
Math.atan(x)
x의 아크탄젠트
Math.atan2(y, x)
y/x의 아크탄젠트
 
 
6장. 객체 지향 프로그래밍
객체지향 언어는 일반적으로 클래스를 통해 같은 프로퍼티와 메서드를 가지는 객체를 여러 개 만든다는 특징이 있지만, ECMAScript에는 클래스라는 개념이 없다.
ECMA-262의 객체 정의는 "프로퍼티의 순서 없는 컬렉션이며 각 프로퍼티는 원시값이나 객체, 함수를 포함한다"이며, 특별한 순서가 없는 값의 배열이란 의미이다. ECMAScript 객체는 해시 테이블이며, 이름-값 쌍의 그룹이며 각 값은 데이터나 함수가 될 수 있다.
모든 객체는 참조 타입을 바탕으로 생성된다.
6.1 객체에 대한 이해
객체를 만드는 가장 단순한 방법은 Object의 인스턴스를 만들고 프로퍼티와 메서드를 추가하는 것이다.
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function() {
    alert(this.name);
};
초기에는 위의 패턴을 자주 사용했으나 몇 년이 지나면서 객체 리터럴 패턴을 더 많이 쓴다:
var person = {
    name: "Nicholas",
    age: 29,
    job: "Software Engineer",
sayName: function() {
        alert(this.name);
    }
};
프로퍼티 타입
ECMA-262 5판에서는 프로퍼티의 특징을 내부적으로만 유효한 속성에 따라 설명하며, 속성이 자바스크립트 엔진 내부에서 구현하므로 자바스크립트에서 직접적으로 접근할 수 없다. [[]]로 감싸서 내부 속성임을 나타낸다.
데이터 프로퍼티
  • [[Configurable]] - 삭제/변경/변환. 기본값은 true.
  • [[Enumerable]] - for-in 루프에서 반환. 기본값은 true.
  • [[Writable]] - 값 변경. 기본값은 true.
  • [[Value]] - 실제 데이터 값. 기본값은 undefined
Object.defineProperty() 메서드를 써서 속성 값을 바꿀 수 있다. Object.defineProperty()를 여러 번 호출할 수 있지만, 일단 Configurable을 false로 지정하면 제한이 생긴다. 프로퍼티 값을 따로 명시하지 않는다면 기본 값은 false이다.
접근자 프로퍼티
  • [[Configurable]]
  • [[Enumerable]]
  • [[Get]] - 프로퍼티를 읽을 때 호출할 함수. 기본 값은 undefined.
  • [[Set]] - 프로퍼티를 바꿀 때 호출할 함수. 기본 값은 undefined.
접근자 포로퍼티는 일반적으로 프로퍼티의 값을 바꿨을 때 해당 프로퍼티만 바뀌는 게 아니라 부수적인 절차가 필요한 경우에 사용한다.
getter 함수만 지정하면 해당 프로퍼티는 읽기 전용이 되고, 수정 시도는 모두 무시되거나 스트릭트 모드에선 에러가 발생한다. setter만 지정된 프로퍼티는 읽으려 하면 undefined를 반환하며 스트릭트 모드에선 에러가 발생한다.
다중 프로퍼티 정의
프로퍼티 속성 읽기
Object.getOwnPropertyDescriptor() 메서드로 프로퍼티의 서술자 프로퍼티를 읽을 수 있다.
 
 
자바스크립트 객체 상세
자바스크립트의 - 가장 자주 사용되고 가장 기본적인 - 핵심 데이터 타입은 객체 데이터 타입이다. 자바스크립트는 한 개의 복잡한 데이터 타입인 객체 데이터 타입이 있으며, 5개의 단순한 데이터 타입이 있다: 숫자, 문자열, 불린, undefined, null. 단순한 (원시적인) 데이터 타입은 불변 즉, 변경할 수 없으나, 객체는 변경할 수 있다.
객체란 무엇인가
객체는 이름-값 쌍으로 저장되는 원시 데이터(때때로 참조 데이터 타입)의 순서 없는 목록이다. 목록의 각 항목은 프로퍼티라고 불리며(함수는 메서드로 불린다), 각 프로퍼티의 이름은 유일해야 하고, 하나의 문자열 또는 숫자가 될 수 있다.
간단한 객체:
var myFirstObject = {firstName: "Richard", favoriteAuthor: "Conrad"};
반복하면: 객체를 이름-값 쌍으로 저장된 목록 안에 항목과 프로퍼티를 포함하는 목록으로 생각하라. 위의 예제의 프로퍼티 이름은 firstName과 favoriteAuthor이다. 각각의 값은 "Richard"와 "Conrad"이다.
프로퍼티 이름은 문자열이나 숫자가 될 수 있으나, 프로퍼티 이름이 하나의 숫자라면 대괄호 표기법으로 접근되어야 한다. 대괄호 표기법은 나중에 더 자세히. 프로퍼티 이름이 숫자로 된 객체의 예제:
var ageGroup = {30: "Children", 100:"Very Old"};
console.log(ageGroup.30) // 에러가 발생한다.
// "Children" 값을 얻기 위해서는 프로퍼티 30의 값은 다음과 같이 접근해야 한다.
console.log(ageGroup["30"]); // Children
//프로퍼티 이름에 숫자를 사용하길 피하는 것이 가장 좋다.
자바스크립트 개발자로서 여러분은 주로 데이터를 저장하고 여러분 자신의 커스텀 메서드와 함수를 만들기 위해, 매우 자주 객체 데이터 타입을 사용할 것이다.
참조 데이터 타입과 원시 데이터 타입
참조 데이터 타입과 원시 데이터 타입의 주요 차이점 중 하나는 참조 데이터 타입의 값은 변수에 직접 저장되지 않고, 참조로 저장되며, 원시 데이터 타입은 값으로 저장된다는 것이다. 예로:
    // 원시 데이터 타입 문자열은 값으로 저장된다.
    var person = "Kobe";
    var anotherPerson = person; // anotherPerson = person의 값
    person = "Bryant"; // person의 값이 바뀌었다.
console.log(anotherPerson); // Kobe
    console.log(person); // Bryant
"Bryant"로 person을 변경했을지라도, anotherPerson 변수는 person이 가졌던 값을 그대로 유지하는 것을 주목할 필요가 있다.
위에서 예시한 값으로 저장되는 원시 데이터와 참조로 저장되는 객체를 비교하라:
    var person = {name: "Kobe"};
    var anotherPerson = person;
    person.name = "Bryant";
console.log(anotherPerson.name); // Bryant
    console.log(person.name); // Bryant
이 예제에선, person 객체를 anotherPerson으로 복사하였다. 그러나 person의 값이 실제 값이 아닌 참조로 저장되었기 때문에 person.name 프로퍼티를 "Bryant"로 변경하면 anotherPerson이 변경된다. person 프로퍼티 값의 실제 사본을 저장하지 않고 참조만 하기 때문이다.
객체 데이터 프로퍼티는 속성(attribute)이 있다
각 데이터 프로퍼티(데이터를 저장하는 객체 프로퍼티)는 이름-값 쌍과 (기본값이 true인) 세 가지 속성이 있다:
  • Configurable Attribute: 프로퍼티가 삭제되거나 변경될 수 있는지를 지정한다.
  • Enumerable: 프로퍼티가 for/in 루프에서 반환될 수 있는지를 지정한다.
  • Writable: 프로퍼티가 변경될 수 있는지를 지정한다.
ECMAScript 5는 위의 데이터 프로퍼티와 함께 접근자 프로퍼티를 명시하고 있음을 주목하라. 접근자 프로퍼티는 함수(getter와 setter)이다. 2월 15일에 이미 예정된 포스트에서 ECMAScript 5를 더 배울 것이다.
객체 만들기
객체를 만드는 두 가지 일반적인 방법이 있다:
1. 객체 리터럴
객체를 만드는 가장 일반적이고 가장 쉬운 방법은 객체 리터럴로 만드는 것이다:
// 객체 리터럴을 사용해서 빈 객체를 초기화시킨다.
var myBooks = {};
// 객체 리터럴을 사용해서 4개의 항목을 가진 객체
var mango = {
color: "yellow",
shape: "round",
sweetness: 8,
howSweetAmI: function () {
console.log("Hmm Hmm Good");
}
}
2. 객체 생성자(constructor)
두 번째 가장 일반적인 방법은 객체 생성자로 만드는 것이다. 생성자는 새 객체를 초기화하는 함수이며, 생성자를 호출하기 위해 새 키워드를 사용한다.
var mango =  new Object ();
mango.color = "yellow";
mango.shape= "round";
mango.sweetness = 8;
mango.howSweetAmI = function () {
console.log("Hmm Hmm Good");
}
객체의 프로퍼티 이름으로 "for"와 같은 몇몇 예약어를 사용할 수 있지만, 피하는 것이 현명하다.
객체는 숫자, 배열과 심지어 다른 객체를 포함하는 모든 데이터 타입을 수용할 수 있다.
객체를 만드는 실용적인 패턴
데이터를 저장하기 위해 여러분의 앱에서 한 번만 사용될 수도 있는 간단한 객체를 위해서, 위의 두 가지 방법으로 객체를 만드는데 충분하다.
과일과 각 과일에 대한 상세를 보여주는 앱을 상상해보라. 모든 과일은 다음과 같은 프로퍼티를 가진다: color, shape, sweetness, cost와 showName 함수. 새로운 과일 객체를 만들려고 할 때마다 다음 코드를 적는 것은 매우 지루하고 비생산적이다.
var mangoFruit = {
color: "yellow",
sweetness: 8,
fruitName: "Mango",
nativeToLand: ["South America", "Central America"],
showName: function () {
console.log("This is " + this.fruitName);
},
nativeTo: function () {
this.nativeToLand.forEach(function (eachCountry)  {
            console.log("Grown in:" + eachCountry);
        });
}
}
10개의 과일이 있다면, 같은 코드를 10번 추가해야 할 것이다. nativeTo 함수를 변경해야 한다면? 10개의 다른 장소에서 변경해야 한다. Now extrapolate this to adding objects for members on a website and suddenly you realized the manner in which we have created objects so far is not ideal objects that will have instances, particularly when developing large applications.
이런 반복적인 문제를 해결하기 위해, 소프트웨어 엔지니어들은 앱을 더 효율적이고 능률적으로 개발하기 위해 패턴(반복적이고 일상적인 작업을 위한 해법)을 발명했다.
객체를 만들기 위한 두 가지 일반적인 패턴이 있다. 여러분이 자바스크립트 제대로 배우기 과정을 하고 있다면 코드 아카데미의 레슨에서 첫 번째 패턴이 자주 사용되는 것을 본 적이 있을 것이다:
1. 객체 만들기 생성자 패턴
function Fruit (theColor, theSweetness, theFruitName, theNativeToLand) {
this.color = theColor;
    this.sweetness = theSweetness;
    this.fruitName = theFruitName;
    this.nativeToLand = theNativeToLand;
this.showName = function () {
        console.log("This is a " + this.fruitName);
    }
this.nativeTo = function () {
    this.nativeToLand.forEach(function (eachCountry)  {
       console.log("Grown in:" + eachCountry);
        });
    }
}
이 패턴을 적절히 사용하여, 모든 종류의 과일을 만드는 것은 매우 쉽다. 이를테면:
var mangoFruit = new Fruit ("Yellow", 8, "Mango", ["South America", "Central America", "West Africa"]);
mangoFruit.showName(); // Mango
mangoFruit.nativeTo();
// Grown in:South America
// Grown in:Central America
// Grown in:West Africa
var pineappleFruit = new Fruit ("Brown", 5, "Pineapple", ["United States"]);
pineappleFruit.showName(); // Pineapple
fruitName 함수를 변경해야 한다면, 한 곳에서만 하면 된다. 패턴은 한 개의 과일 함수와 상속을 이용해서 모든 과일의 모든 기능성과 특징을 캡슐화한다.
주의사항:
  • 상속 프로퍼티는 객체의 프로토타입 프로퍼티에 정의된다. 예로:
someObject.prototype.firstName = "rich";
  • 자신의 프로퍼티는 객체 그 자체에 직접 정의된다, 예로:
// 먼저 객체를 만든다:
var aMango = new Fruit ();
// 이제 aMango 객체에 직접 mangoSpice 프로퍼티를 정의한다.
// aMango 객체에 직접 mangoSpice 프로퍼티를 정의했기 때문에 상속된 프로퍼티가 아닌 aMango 자신의 프로퍼티이다.
aMango.mangoSpice = "some value";
  • 객체의 프로퍼티에 접근하기 위해서, object.property를 사용한다. 예로:
console.log(aMango.mangoSpice); // "some value"
  • 객체의 매서드를 적용하려면(invoke), object.method()를 사용한다. 예로:
// 먼저 메서드를 추가한다.
aMango.printStuff = function () {return "Printing";}
// 이제 printStuff 메서드를 적용할 수 있다:
aMango.printStuff ();
2. 객체 만들기 프로토타입 패턴
function Fruit () {
}
Fruit.prototype.color = "Yellow";
Fruit.prototype.sweetness = 7;
Fruit.prototype.fruitName = "Generic Fruit";
Fruit.prototype.nativeToLand = "USA";
Fruit.prototype.showName = function () {
console.log("This is a " + this.fruitName);
}
Fruit.prototype.nativeTo = function () {
            console.log("Grown in:" + this.nativeToLand);
}
그리고 아래는 이 프로토타입 패턴에 Fruit () 생성자를 호출하는 방법이다:
var mangoFruit = new Fruit ();
mangoFruit.showName(); //
mangoFruit.nativeTo();
// This is a Generic Fruit
// Grown in:USA
추가 읽기
이 두 가지 패턴의 완전한 논의와 각각의 동작법과 단점에 대한 철저한 설명을 위해, Professional JavaScript for Web Developers의 6장을 읽어라. 여러분은 자카스가 어떤 것을 최고로 추천하는지 배울 수 있을 것이다.(힌트: 위의 두 가지 다 아니다.)
객체 프로퍼티 접근하는 법
객체의 프로퍼티에 접근하는 두 가지 주요 방법은 점 표기법과 대괄호 표기법이다.
1. 점 표기법
// 지금까지의 예제에서 점 표기법을 사용해왔다. 여기 또 하나의 예제가 있다:
var book = {title: "Ways to Go", pages: 280, bookMark1:"Page 20"};
// 점 표기법을 사용해서 book 객체의 프로퍼티에 접근하려면, 이렇게 한다:
console.log (book.title); // Ways to Go
console.log (book.pages); // 280
2. 대괄호 표기법
// 대괄호 표기법으로 book 객체의 프로퍼티에 접근하려면, 이렇게 한다:
console.log (book["title"]); //Ways to Go
console.log (book["pages"]); // 280
//혹은, 변수로 프로퍼티 이름을 가질 수도 있다:
var bookTitle = "title";
console.log (book[bookTitle]); // Ways to Go
console.log (book["bookMark" + 1]); // Page 20
존재하지 않는 객체의 프로퍼티에 접근하면 undefined 결과가 나올 것이다.
고유와 상속 프로퍼티
객체는 상속 프로퍼티와 고유 프로퍼티를 가진다. 고유 프로퍼티는 객체에 정의되는 프로퍼티이고, 상속 프로퍼티는 프로토타입 객체로부터 상속된다.
객체에 프로퍼티(상속이던 고유이던)가 존재하는지를 알아내려면 연산자를 사용한다:
// schoolName이란 프로퍼티를 가진 새로운 school 객체를 만든다.
var school = {schoolName:"MIT"};
// schoolName school 객체의 고유 프로퍼티이므로 true를 출력한다.
console.log("schoolName" in school);  // true
// school 객체에 schoolType 프로퍼티가 정의되지 않았고, Object.prototype 프로토타입 객체로부터 schoolType 프로퍼티를 상속하지 않았기 때문에 false를 출력한다.
console.log("schoolType" in school);  // false
// school 객체가 Object.prototype으로부터 toString 메서드를 상속받았기 때문에 true를 출력한다.
console.log("toString" in school);  // true
hasOwnProperty
객체가 특정 프로퍼티를 고유 프로퍼티 중 하나로 가졌는지 알아내려면 hasOwnProperty 메서드를 사용한다. 이 메서드는 객체를 하나하나 열거하거나 상속이 아닌 고유 프로퍼티만을 원할 때 매우 유용하다.
// schoolName 프로퍼티를 갖는 새로운 school 객체를 만든다.
var school = {schoolName:"MIT"};
// schoolName school 객체의 고유 프로퍼티이므로 true를 출력한다.
console.log(school.hasOwnProperty ("schoolName"));  // true
// school 객체가 toString 메서드는 Object.prototype으로 상속되었으며, toString school 객체의 고유 프로퍼티가 아니므로 false를 출력한다.
console.log(school.hasOwnProperty ("toString"));  // false
객체 프로퍼티 접근하고 열거하기
열거할 수 있는 (고유와 상속) 프로퍼티를 접근하기 위해서는 for/in 루프나 일반 for 루프를 사용한다.
// schoolName, schoolAccredited, schoolLocation의 세 가지 고유 프로퍼티를 갖는 새로운 school 객체를 만든다.
var school = {schoolName:"MIT", schoolAccredited: true, schoolLocation:"Massachusetts"};
//school 객체의 프로퍼티를 접근하기 위해 for/in 루프를 사용하라.
for (var eachItem in school) {
console.log(eachItem); // schoolName, schoolAccredited, schoolLocation를 출력한다.
}
상속 프로퍼티 접근하기
Object.prototype에서 상속된 프로퍼티는 열거할 수 없으며, for/in 루프가 그것들을 보여주지 않는다. 그러나 열거할 수 있는 상속 프로퍼티는 for/in 루프 반복으로 보인다. 예로:
// school 객체의 프로퍼티를 접근하기 위해서 for/in 루프를 사용하라.
for (var eachItem in school) {
console.log(eachItem); // schoolName, schoolAccredited, schoolLocation를 출력한다.
}
// school 객체가 상속할 새로운 HigherLearning 함수를 만든다.
/* 사이드 노트: 날카로운 독자인 윌슨이 밑의 댓글에 정확하게 지적하였듯이, educationLevel 프로퍼티는 HigherLearning 생성자를 사용한 객체에 실제로 상속되지 않았다; 대신, educationLevel 프로퍼티는 HigherLearning 생성자를 사용한 각 객체에 새로운 프로퍼티로서 만들어졌다. 프로퍼티가 상속되지 않은 이유는 프로퍼티를 정의하기 위해 "this" 키워드를 사용하기 때문이다.
*/
function HigherLearning () {
this.educationLevel = "University";
}
// HigherLearning 생성자로 상속한다.
var school = new HigherLearning ();
school.schoolName = "MIT";
school.schoolAccredited = true;
school.schoolLocation = "Massachusetts";
// school 객체의 프로퍼티를 접근하기 위해 for/in 루프를 사용하라.
for (var eachItem in school) {
console.log(eachItem); // educationLevel, schoolName, schoolAccredited, schoolLocation를 출력한다.
}
마지막 예제에서, HigherLearning 함수로 정의된 educationLevel 프로퍼티가 school의 프로퍼티 중 하나로 열거된 것을 주목하라. educationLevel은 고유 프로퍼티가 아니며, 상속되었다.
객체의 프로토타입 속성과 프로토타입 프로퍼티
객체의 프로토타입 속성과 프로토타입 프로퍼티는 자바스크립트를 이해하기 위해 결정적으로 중요한 개념이다. 추가로 내 포스트 JavaScript Prototype in Plain, Detailed Language를 읽어라.
객체의 프로퍼티 삭제하기
객체로부터 프로퍼티를 삭제하려면, delete 연산자를 사용한다. 상속된 프로퍼티는 지울 수 없으며, configurable 속성으로 설정된 프로퍼티도 지울 수 없다. (프로퍼티가 정의되었던 곳인) 프로토타입 객체에서 상속된 프로퍼티를 지워야 한다. 또한, (var 키워드로 선언되었던) 전역 객체의 프로퍼티는 지울 수 없다.
delete 연산자는 삭제가 성공적이면 true를 반환한다. 그리고 놀랍게도 삭제할 프로퍼티가 존재하지 않거나 프로퍼티가 지워질 수 없어도(non-configurable이나 객체에 의해 소유되지 않은 등) 역시 true를 반환한다.
이러한 예를 설명하면:
var christmasList = {mike:"Book", jason:"sweater" }
delete christmasList.mike; // mike 프로퍼티를 지운다.
for (var people in christmasList) {
    console.log(people);
}
// jason만 출력한다.
// mike 프로퍼티는 지워졌다.
delete christmasList.toString; // true를 반환한다, 그러나 toString은 상속된 메서드이기 때문에 지워지지 않는다.
// 여기서 toString 메서드를 호출하면 잘 동작한다-지워지지 않았다.
christmasList.toString(); //"[object Object]"
// 프로퍼티가 그 인스턴스의 고유 프로퍼티라면 인스턴스의 프로퍼티를 지울 수 있다. 예로, educationLevel 프로퍼티는 인스턴스에 정의되었기 때문에 school 객체에서 educationLevel 프로퍼티를 지울 수 있다: HigherLearning 함수를 선언할 때 프로퍼티를 정의하기 위해 "this" 키워드를 사용하였다. HigherLearning 함수의 프로토타입에서 educationLevel 프로퍼티를 정의하지 않았다.
console.log(school.hasOwnProperty("educationLevel")); true
// educationLevel school에서 고유 프로퍼티이며, 지울 수 있다.
delete school.educationLevel; true
// educationLevel 프로퍼티는 school 인스턴스로부터 지워졌다.
console.log(school.educationLevel); undefined
// 그러나 HigherLearning 함수에 educationLevel 프로퍼티는 아직 존재한다.
var newSchool = new HigherLearning ();
console.log(newSchool.educationLevel); // University
// 다음의 educationLevel2 프로퍼티처럼 HigherLearning 함수의 프로토타입으로 정의했다면:
HigherLearning.prototype.educationLevel2 = "University 2";
// HigherLearning 인스턴스의 educationLevel2 프로퍼티는 고유 프로퍼티가 아니다.
// educationLevel2 프로퍼티는 school 인스턴스의 고유 프로퍼티가 아니다.
console.log(school.hasOwnProperty("educationLevel2")); false
console.log(school.educationLevel2); // University 2
// 상속된 educationLevel2 프로퍼티를 지워보자.
delete school.educationLevel2; true (앞에서 언급하였듯이 항상 true를 반환한다)
// 상속된 educationLevel2 프로퍼티는 지워지지 않는다.
console.log(school.educationLevel2); University 2
Serialize and Deserialize Objects
HTTP를 통해 객체를 전송하거나 문자열로 변환하기 위해서, 시리얼라이즈할(문자열로 변환할) 필요가 있을 것이다; JSON를 사용할 수 있다. 객체를 시리얼라이즈하기 하려면 함수를 문자열화하라. ECMAScript 5 전에는 JSON을 얻기 위해 (더글러스 크락포드의) 인기 있는 json2 라이브러리를 사용해야 했다는 것을 주목하라. 함수를 문자열화하는 것은 이제 ECMAScript 5에서는 표준이다.
객체를 디시리얼라이즈하기(문자열에서 객체로 변환하기) 위해서는, 같은 json2 라이브러리에서 JSON.parse 함수를 사용한다. 이 함수도 ECMAScript 5에서 표준이 되었다.
JSON.stringify 예제:
var christmasList = {mike:"Book", jason:"sweater", chelsea:"iPad" }
JSON.stringify (christmasList);
// 다음 문자열을 출력한다:
// "{"mike":"Book","jason":"sweater","chels":"iPad"}"
// 문자열화된 객체를 포매팅과 함께 출력하려면, 패러미터로 "null" "4"를 추가한다:
JSON.stringify (christmasList, null, 4);
/*
"{
    "mike": "Book",
    "jason": "sweater",
    "chels": "iPad"
}"
*/
// JSON.parse 예제 \\
// 다음은 JSON 문자열이다, 그래서 (christmasListStr.mike와 같이) 점 표기법으로 접근할 수 없다.
var christmasListStr = '{"mike":"Book","jason":"sweater","chels":"iPad"}';
// 객체로 변환하자.
var christmasListObj = JSON.parse (christmasListStr);
// 이제 객체이므로 점 표기법을 사용한다.
console.log(christmasListObj.mike); // Book
객체를 다루기 위한 ECMAScript 5 추가사항을 포함하여, 자바스크립트 객체를 좀 더 상세히 커버하기 위해서는 JavaScript: The Definitive Guide 6th Edition의 6장을 읽어라.
 
 
 
 
2015-01-28 <크라임웨어> 요약


 

<크라임웨어> 쥐도 새도 모르게 일어나는 해킹 범죄의 비밀 | 마커스 야콥슨, 줄피카 람잔 공저 / 민병호, 김수정 공역 | 에이콘출판사 | 2009년 10월 30일 | 원제 : crimeware: understanding new attacks and and defenses

 

26p~641p

하루 154p

 

2015-01-28

 

1장 크라임웨어 개괄

 기존의 악성 프로그램은 이름을 알리기 위해 개발했지만, 악성프로그램으로 적지않은 돈을 벌 수 있다는 사실을 알아채고 범죄로 변모했다.

1.1 소개

1.1.1 기밀 정보 도난

 피싱phishing 하나로 직접적인 금전적 손실이 매년 10억 달러를 넘는다.

 회사의 가상 사설망 VPN 침투

L2PT를 이용한 VPN 접속 예. 사실 접속원리는 접속규격 외에는 전부 동일하다.

- Layer 2 Tunneling Protocol. 줄여서 L2PT라고 부른다. L2F와 PPTP 프로토콜을 결합하여 만든 규격이기 때문에 PPP를 지원한다. L2PT는 터널을 확립해주기만 하며, 암호화는 IPsec 기술을 사용한다. IPsec 기술에는 IKE(Internet Key Exchange)와 ESP(Encapsulation Security Payload)가 사용된다.

 

 

- 모든 과정이 암호화된다는 특성 상 정부의 검열을 프록시 서버나 tor보다 넘사벽급으로 안전하게 피할 수 있다. 프록시 서버 항목을 보면 알겠지만 원래 사용자의 IP가 완전히 오픈되거나, 그대로 기록되는 프록시 서버 규격 또한 있기 때문에 모든 프록시 서버가 완벽한 익명성을 보장하지는 않고, 무엇보다 무료로 돌아가는 프록시 서버들은 IP가 오픈되는 경우가 많기 때문에 원래 사용자의 IP를 특정하는 것은 생각보다 간단한 편이다. Tor의 경우는 일단 접속되면 여러 IP를 거치는 루트를 이용하기 때문에 접속을 성공한 이후부터는 어느정도 안전이 보장되지만, 접속을 시도하고 터널을 확립하는 과정이 암호화가 되어있지 않다. 실제로 이런점을 악용하여 Tor 접속터널을 차단하는 국가도 있다.

 

하지만 VPN는 서버가 해외에 있다면, 전용선과 가까운 보안을 유지해야 하는 만큼 처음 순간부터 모든 과정이 암호화되어 접속 규격 자체의 보안성이 상당히 높다. 때문에 정상적인 방법으론 메인 서버 외에는 원래 사용자를 절대로 특정할 수 없다.

 

1.1.2 크라임웨어 범위

악성프로그램 - 크라임웨어(상업적이익), 불법 소프트웨어(바이러스), 합법 소프트웨어(애드웨어, 스파이웨어)

1.1.3 크라임웨어 전파

 그림 1.1. 크라임웨어의 전파기술

2007년 시만텍의 ISTR(인터넷 보안 위협 보고서)에 따르면, 악성 소프트웨어의 46%가 SMTP (단순 메일 전송 프로토콜)로 퍼졌다.

1.2 크라임웨어 유포

 봇넷(botnet) 크라임웨어가 침투한 컴퓨터들로 구성된 대규모 네트워크로 공격에 이용된다.

1.3 크라임웨어 위협 모델과 분류

 중간자공격 (man in the middle attack) 수집한 정보를 적법한 서버로 전달하기 전에 공격자에게 직접 전송한다. 전송된 정보를 공격자는 적법서버로 리다이렉팅 한다.

1.4 다양한 크라임웨어

1.4.1 키로거와 스크린 스크레이퍼

키로거

- BHO수준 (URL탈취)

- 애플리케이션 수준 (후킹) : 예) SC-Keylog, 자동완성되는 암호까지도 탈취하는 것도 있다.

- 커널수준 장치드라이버 (키보드, 마우스 입력저장) : 자동완성되는 암호는 탈취 불가능하다.

- 스크린스크레이퍼(screenscraper) 화면까지 모니터링(화상키보드 무력화)

1.4.2 메일 리다이렉터와 인스턴트 메신저 리다이렉터

- 메일 리다이렉터 Advanced Stealth Email Redirector

1.4.3 세션 하이재커

- 적법한 사용자 세션을 강제로 탈취

1.4.4 웹 트로이목마

- 가짜 로그인 창을 띄우거나 로그인 이후 추가 창을 띄워서 정보를 입력하도록 유도

1.4.5 거래transaction 생성기

- 예를 들어, 물품을 구매하고 환불을 처리하고 이 때 환불처리 트랜젝션을 여러 번 날리도록 하면 잔고가 올라간다.

1.4.6 시스템 재설정 공격

- host 파일을 수정/DNS캐시를 오염/라우터에 설정된 DNS서버를 변경시켜 www.naver.com 을 해커의 IP로 접속하게 만든다.

- 프록시를 설정해서 모든 트래픽을 해커가 가져갈 수 있다. 예) [SiN] Gateway Manager

1.4.7 데이터 절도

- herman agent

1.4.8 중간자 공격

- 라우터 등에 프폭시를 호스팅하는 것을 트롤러 피싱이라고 한다.

- 중간자 공격은 OTP나 보안토큰에 의한 임시 비밀번호를 탈취할 수 있다.

1.4.9 루트킷

- 악성 프로그램의 존재와 그 활동을 숨기는 소프트웨어다.

- 커널 수준에 접근할 정도로 매우 다양하다. 막는 방법은 주요 운영체제를 가상머신 내부에서 게스트 운영체제로 돌리고 외부 호스트 운영체제에서 보안 소프트웨어를 실행시키는 방법이 있다. 하지만, 게스트 운영체제안의 루트킷 프로그램이 호스트와 게스트를 바꿔버릴 수 있기 때문에 이 또한 무력화 될 수 있다.

 이론적으로보면 크라임웨어는 ACPI BIOS나 그래픽 카드 같은 하드웨어의 비휘발성 저장장치에도 설치할 수 있다.

1.5 크라임웨어 배포

1.5.1 첨부파일

1.5.2 P2P 네트워크

1.5.3 피기배킹

 - 겉으로는 정상적으로 동작하는 애플리케이션이 사실은 악성 코드 내장.

1.5.4 인터넷 웜

 - 컴퓨터 웜(computer worm)은 스스로를 복제하는 컴퓨터 프로그램이다. 컴퓨터 바이러스와 비슷하다. 바이러스가 다른 실행 프로그램에 기생하여 실행되는 데 반해 웜은 독자적으로 실행되며 다른 실행 프로그램이 필요하지 않다. 웜은 종종 컴퓨터의 파일 전송 기능을 착취하도록 설계된다. 컴퓨터 바이러스와 웜의 중요한 차이점은 바이러스는 스스로 전달할 수 없지만 웜은 가능하다는 점이다. 웜은 네트워크를 사용하여 자신의 복사본을 전송할 수 있으며, 어떠한 중재 작업 없이 그렇게 할 수 있다. 일반적으로 웜은 네트워크를 손상시키고 대역폭을 잠식하지만, 바이러스는 컴퓨터의 파일을 감염시키거나 손상시킨다. 바이러스는 보통 네트워크에 영향을 주지 않으며 대상 컴퓨터에 대해서만 활동한다.

 

 

1.5.5 웹 브라우저 공격

- 배포 벡터 (보안분야에서는 악성프로그램이 퍼질 수 있는 경로나 공격이 일어날 수 있는 경로를 벡터라고 한다.)

- 제로데이 공격. 취약점이 알려지기 전에 공격.

- 컨텐츠 인젝션: 적법한 사이트에 악성 컨텐츠를 삽입하는 과정을 말한다.

- SQL 인젝션

- 크로스 사이트 스크립팅

- 브라우저 플러그인 공격 : Active X, flash 등 

1.5.6 서버 침투

1.5.7 제휴 마케팅

1.6 감염과 절도 지점, 초크포인트, 대응책

- 감염지점과 데이터 절도 지점을 보면, 크라임웨어를 무력화하는 대응책을 적용할 수 있는 최우선적인 초크포인트를 알 수 있다.

- 배포저지: 스팸필터. 자동 업데이트, 크로스 사이트 스크립팅CSRF 및 SQL인젝션 차단

- 플랫폼 감염방지: 행동기반 시스템은 오탐이라는 문제가 있으나 새로운 공격에 바로 대응할 수 있다.

- 크라임웨어 실행방지: 인증된 코드만 실행되도록

- 기밀데이터 삭제방지: 하드웨어적으로 방어

- 기밀정보제공방지: 악성 사이트에 계정정보 입력시 이를 탐지하는 기능

- 기밀 데이터 수신과 사용저지:  트래픽 감시 (스니핑)

공격을 해도 금전적 이익이 없도록 하는 접근 방식도 있다.

1.7 크라임웨어 설치

- 1차 백도어 설치: 백도어는 피해자의 컴퓨터에 원격 제어 수단을 설치하는 데 사용. ex) BAD R.A.T

1.8 크라임웨어 사용

1.8.1 정보 절도

- 침투된 컴퓨터에 존재하는 사진등의 미디어 파일에 데이터를 섞는 스테가노 그래피 기술이 있다.

1.8.2 스팸 전송

1.8.3 서비스 거부 공격

DDOS는 보통 불법 사이트를 공격한다. 카지노, 토토, 불법성인사이트 등을 공격하여 돈을 요구한다.

1.8.4 부정 클릭

감염된 봇넷을 활용하여 인공적인 광고 수익을 올린다.

1.8.5 데이터 몸값 요구

- 랜섬웨어(암호 바이러스)

1.8.6 정보 수집

1.9 나머지 장의 구성

후기

 

2장 오류의 종류

2.1 골칫거리 삼형제

2.1.1 연결성 - 예전보다 인터넷에 연결되는 컴퓨터의 숫자가 크게 늘어났다. 예) IoT

2.1.2 복잡도 - 코드가 너무 길다. 버퍼 오버플로우 같은 단순한 공격도 방어하지 않는 안전하지 않은 프로그래밍 언어 (C나 C++)을 사용하면 문제는 더욱 커진다.

2.1.3 확장성

2.2 치명적인 7대 오류과

 1) 입력 확인과 표현 : 입력 확인을 하려면 차단 목록이 아니라 허용 목록을 사용하자. 버퍼 오버플로우, 크로스 사이트 스크립팅, SQL 인젝션, 캐시 오염의 제물이 된다.

 2) API 오용.

 3) 보안기능.(허술한)

 4) 시간과 상태. 분산 컴퓨팅은 시간과 상태를 다룬다. 단순 동기화만 구현한 MMORPG에서 텔레해킹을 통해 자신의 캐릭터를 순간이동 시길 수 있었다. 예기치 못한 상호작용은 공유 상태 (세마포어, 변수, 파일 시스템, 그리고 기본적으로 정보를 저장하는 모든 것을)를 통해 일어난다.

 5) 예외처리. 최근 객체 지향 시스템에서 한 때 금지됐던 개념인 goto를 다시 활용한다. 오류처리를 전혀 하지 않거나 쉽게 공격당할 정도로 대강하는 경우가 있다. 퍼징(fuzzing, fuzz testing)이란, 소프트웨어에 무작위의 데이터를 반복하여 입력하여 소프트웨어의 조직적인 실패를 유발함으로써 소프트웨어의 보안 상의 취약점을 찾아내는 것을 의미한다. 

 6) 코드 품질.

 7) 캡슐화

  + 환경

2.2.1 단순성에 대해: 7 ± 2

2.3 종

2.4 오류과와 종 정리

- 버퍼 오버플로우. 할당된 메모리 경계를 넘어서 데이터를 기록하는 일은 기존 데이터 및 프로그램을 망가뜨린다.

- 크로스 사이트 스크립팅CSRF. 확인되지 않은 데이터를 웹 브라우저로 전송하면 브라우저가 악성 코드를 실행할 수 있다.  웹사이트 관리자가 아닌 이가 웹 페이지에 악성 스크립트를 삽입할 수 있는 취약점이다.

- 포맷 스트링. 공격자는 함수의 포맷 스트링을 조작해서 버퍼 오버플로우를 발생시킬 수 있다.

- XML확인. XML파싱시 확인 과정을 거치지 않으면 공격자가 악의적인 입력을 주입할 수 있다.

2.4.1 완전한 예

2.4.2 개발 능력 향상

 

87p

3장 P2P 네트워크

3.1 P2P 네트워크 내 악성 프로그램

3.1.1 소개

 - 중앙집중식 P2P ex) 위디스크

 - 분산형 비구조화 P2P ex) 토렌트

3.1.2 데이터 수집

3.1.3 악성 프로그램 확산

3.1.4 악성 프로그램 필터링

 - 다운로드 후, 백신 프로그램

 - 다운로드 전, 질의 단계에서 악의적인 응답을 필터링

3.1.5 단일 기준 필터

3.1.6 네트워크 간 단일 기준 필터

3.1.7 복합 필터

결론

 - 파일 크기, 파일 명 기반 필터: 94~98%를 필터링 했다.

 - 호스트 IP주소, 질의 문자열에 기반한 필터를 추가했더니 95~99%를 필터링 했다.

 - 이제까지 알려지지 않은 악성 프로그램 즉, 제로데이 웜은 어떻게 필터링 하는가. 파일명과 크기의 빈도수를 모니터링 하고 지나치게 '활동적인' 파일을 감별해냄으로써 이 절에서 다룬 필터를 이용해서 빠르게 확산되는 제로데이 웜을 악성 프로그램으로 취급해 식별할 수 있다.

3.2 사람을 통해 전파되는 크라임웨어

3.2.1 문제

3.2.2 감염 경로

3.2.3 사례 연구: 서명된 애플릿

 

4장 휴대장치용 크라임웨어

4.1 USB 드라이브를 통한 전파

4.1.1 예: 윈도우 암호 훔치기

 - SAM파일과 system 파일을 탈취하여 LCP, SAM덤프, SAM 인사이드, pwdump같은 암호 복구 도구를 사용해서 오프라인으로 분석한다. 예를 들어 LCP는 SAM 파일에서 사용자명과 이에 대응되는 암호 해시를 추출한 후 사전(dictionary)공격, 브루트포스 공격(가능한 모든 암호를 대입하는 공격), 혼합공격 같은 세 가지 방식으로 사용자 암호를 알아낸다.

4.1.2 예: 그밖의 USB 드라이브 공격

4.1.3 DMA 취약점

 - 직접 메모리 접근 (Direct memory access) 이 문제가 중점적으로 제기된 것은 OHCI 규격으로 주창된 IEEE1394 규격으로 인한 것이었다. IEEE1394 규격은 성능적인 향상을 목적으로 운영체제의 관리를 통하지 않고 직접적으로 메모리에 접근할 수 있도록 함으로서 복잡한 입출력 작업에서 CPU의 점유율을 낮추고 전송 속도를 높이는데 성공한 인터페이스였다. 이러한 접근 방식은 당연히 운영체제와 CPU의 관리를 벗어나 있기 때문에, 그만큼 아무런 통제없이 시스템에 접근할 수 있도록 만드는 문제를 가져왔다. 즉 운영체제가 관리하는 범주 밖의 공간에서 관리범위의 메모리에 접근할 수 있는 길이 열리게 되는 것이다.

4.1.4 위험 측정

4.1.5 대응책

 - 백신 최신 버전으로 업데이트

 - USB 자동 실행을 끈다

 - USB 포트를 비활성화 시킨다.

 - 관리도구를 사용하여 USB 로그를 기록한다.

4.2 RFID 크라임웨어

4.2.1 RFID

4.2.2 RFID 보안 문제

 - 태그 복제: 유사한 저렴한 상품의 태그를 복사하여 사고자 하는 물건에 부착.

4.2.3 RFID 크라임웨어 유형

4.2.4 대응책과 기타 고려사항

4.3 모바일 크라임웨어

 

5장 펌웨어용 크라임웨어

5.1 펌웨어 갱신에 의한 전파

5.1.1 임베디드 제어 시스템: 유비쿼터스와 빠른 변화

5.1.2 가정용 무선 AP 사례

5.1.3 라우터 펌웨어 설정과 업그레이드

5.1.4 표준 보안 기법

- WLAN 접근 제어

AP는 SSID 감춤, vs 키스멧Kismet 은 SSID를 찾아낸다.

MAC주소를 이용한 클라이언트 필터링, vs 트래픽의 모든 프레임에 MAC주소를 전송하기 때문에 스누핑하면 된다.

 802.11 수준에서의 트래픽 암호화 기능. WEP(몇 분만에 뚫을 수 있다.) , WPA , WPA2

 - 관리자 접근 제한

관리자 암호 - 25%의 암호가 65,000개의 낱말 목록에 포함된 단어를 변형했다. 그리고 보통 잘못된 로그인에 AP는 어떠한 제재도 가하지 않는다.

인터넷 관리 기능 - 유선 연결을 통한 관리자 페이지 접근만 가능하도록 하는 것인데, 대부분의 경우 그런 기능을 꺼놓거나 아예 없는 경우가 많다.

와이파이 인증 기능

관리자 클라이언트와 웹 관리 페이지 사이의 SSL사용 의무화 - 관리자 페이지 접근은 HTTPS로 해야한다.

+ 단순히 SSID를 변경하는 것만으로도 해커의 표적에서 멀어질 수 있다. 다른 기본값도 바꿨을 가능성이 있기 때문이다.

5.1.5 취약한 보안 설정이 법이다

 - 설정 마법사의 암호란에 공란으로 두는 경우와 별표(*)로 해두는 경우 별표인 경우에는 25%의 사람들이 암호를 재설정 하지 않았다.

 - 공장 출하시 다양한 WEP 비밀번호를 활성화 시키고 그 비밀번호를 장치 하단에 부착. 사고로 인해 발생하는 문제처리 비용을 고객 지원 비용에서 상쇄.

5.1.6 공격

 - 무선 AP 재킹 공격 (WAP Jack Attack): 설정변경 공격.

 - 파밍: 라우터의 DNS서버를 설정하는 공격자는 라우터의 네트워크에서 공격자의 DNS 서버로 전송되는 모든 DNS 트래픽을 리다이렉트 한다.

 - 인터넷 관리: 기본적으로 꺼져있는 인터넷 관리 기능을 사용하면 라우터의 외부 네트워크에서도 로그인해서 설정을 변경할 수 있다.

 - 무선 브리징: 현재 WAN/인터넷 연결을 끊고 인터넷 트래픽을 근처의 라우터로 라우팅 한다. 현재 인터넷을 끊고 해커의 네트워크를 이용하는 것이다. 해커는 트래픽을 마음대로 감시, 수정, 차단 할 수 있다.

 - 무선 AP 킷 공격: 라우터에 침투한 후 펌웨어를 완전히 교체한 경우 공격 당한 라우터를 무선 AP 킷이라고 한다. 펌웨어까지 교체 당한 AP는 훨씬 다양한 공격을 할 수 있다. 무선AP킷 라우터는 모든 SSL 세션을 하이재킹 할 수도 있다.

  ex) 부정 클릭, 원격제어(좀비PC)

   중간자 공격 - 브라우저와 브라우저 사용자가 SSL 인증서를 적절히 인증하면 앞서 설명한 중간자 공격은 막을 수 있다.

   트롤러 피싱(웹 폼에 입력된 값의 복사본이 공격자에게 전송되는 공격) : 클라이언트가 로그인 정보나 개인 정보를 입력하기 전에 서비스 제공자가 SSL을 초기화 하면 막을 수 있다.

 

   레이스 파밍(라우터가 실제 서버로부터의 응답이 도착하기 전에 HTTP 응답을 스푸핑 할 수 있기 때문에 클라이언트가 자신도 모르게 공격자의 사이트로 포워딩 되는 공격) SYN-ACK 핸드 셰이크를 방해해서 TCP 연결을 하이재킹 하는 공격도 가능.

5.1.7 공격 경로

 - 워키팅: 물리적 근접성에 기반한 무선AP침투기법. 넷스텀블러나 키스멧 같은 와이파이 탐지 소프트웨어를 이용해 무선 네트워크를 찾는다. 에어스노트Airsnort는 WEP암호를 깨는 프로그램이다. 악의적인 펌웨어를 설치하기 위해 공개 웹 관리 페이지를 이용한다. 이를 위해 유향 안테나를 활용하기도 한다. DefCon에서는 2007년 기준 201km밖에서 3시간 동안 11Mbit 연결을 유지했다.

 - 라우터를 이용한 라우터 공격

 - 웹 스크립팅

 - 직접적인 장악과 재판매 : 악의적인 펌웨어 업데이트를 직접 수행한 후 이를 온라인 거래사이트에서 판매.

5.1.8 대응책

 - 전통적인 안티바이러스 소프트웨어는 도움이 되지 않는다: 안티바이러스 소프트웨어는 공격자와 무선 라우터 사이의 트래픽을 볼 수도 없다.

 - 적절한 보안 의식만 지녀도 대부분의 문제가 해결된다.

 평균정도의 보안 설정을 유지하는 것이다. 물리적 보안 계층을 추가히기 위해 라우터 설정을 변경하려면 반드시 라우터에 물리적으로 접근하게 해야한다. 라우터의 인터넷 기반 관리 또는 WAN측 관리는 반드시 비활성화해야 한다. 무선 네트워크는 WEP대신 WPA같은 강력한 암호화 기법으로 암호화 해야한다. 최소한 라우터 설정 변경에 필요한 암호는 추측하기 어려워야 한다.

 - 스스로를 해킹하자. 제조사의 펌웨어보다 엄격한 보안정책을 강제하는 펌웨어를 설치하면 된다. 예를들어 오픈WRO(OpenWRT)에는 잘못된 로그인 시도에 대한 벌점 시스템(백오프 기법)이 구현되어 있다.

 - 호스트 스캐닝: 엔맵(nMap)이나 p0f-2 같은 네트워크 호스트 스캐너를 이용하면 침투된 라우터를 탐지할 수 있다.

 - 침입 탐지 시스템 IDS(intrusion detection system)

 출처에 상관없이 악의적인 트래픽을 탐지한다. 침입 탐지 시스템에는 크게 서명 또는 규칙 기반 칩입 탐지 RIDS(rule-based intrusion detection system)와 통계 또는 변칙 탐지 시스템이 있다.

 RIDS의 단점은 알려진 공격과 이를 아주 조금 변경한 공격만 탐지한다는 점이다. 변칙 탐지 시스템은 오탐률이 높은 단점이 있다.

 - 무선 허니팟 : 허술한 AP처럼 위장해서 해커를 불러오는 방식. 공격자와 방어자 사이의 군비경쟁임.

 - 클라이언트 봉쇄: 침입 탐지 시 새로운 연결을 X분동안 금지하는 정책.

5.2 와이파이 악성 프로그램 전염 모델링

5.2.1 기본적인 방법론

5.2.2 연구 개요

5.2.3 라우터 감염

5.2.4 감염 네트워크

5.2.5 전염 모델

5.2.6 인공적인 전염 확산

 - 시카고의 경우 2주면 충분했다.

5.2.7 추가 사항

 

6장 브라우저용 크라임웨어

6.1 거래 생성기: 웹 세계의 루트킷

 - TG(거래생성기: Transaction Generator) : TG는 사용자 컴퓨터에 잠복하면서 사용자가 은행이나 온라인 쇼핑 사이트에 로그인할 때까지 대기한다. 인증을 마치고 나면 대부분의 웹사이트는 세션쿠키를 발행한다. 악성프로그램은 이 세션쿠키에 접근할 수 있다. TG가 수행한 거래는 사용자가 주로 컴퓨터를 사용하는 시간에 사용자의 IP주소에서 진행된 거래이기 때문에 웹사이트 입장에서 볼 때는 사용자가 수행한 적법한 거래와 동일해보이며 분석 도구로 탐지하기도 어렵다.

6.1.1 거래 생성기 구현

6.1.2 은닉형 거래 생성기

6.1.3 대응책

 - Chaptcha: 자동생성방지 문자

 - 무작위 거래 페이지 : 청구서를 이미지화 하거나 구조를 무작위화 해서 거래를 숨기기 어렵게 한다. 

 - 거래 확인: 쇼핑몰에서 모든 거래를 확인하게 해주는 확인 시스템을 사용하면 막을 수 있다.

결론

6.2 드라이브 바이 파밍

 - 사용자가 보기만 해도 사용자의 가정용 광대역 라우터 설정을 변경하려고 시도하는 웹 페이지를 이용한 공격을 말한다.

 - 드라이브 바이 파밍 공격은 라우터에 물리적으로 접근하지 않고도 자바스크립트 호스트 스캐닝과 CSRF로 라우터를 공격한다.

6.2.1 드라이브 바이 파밍 공격 과정

6.2.2 관련 연구

6.2.3 공격 세부사항

6.2.4 그 밖의 내용

6.2.5 대응책

 - 가정용 라우터 암호 변경

 - 로컬 방화벽 규칙

 - 라우터의 CSRF 보호.

결론

6.3 자바스크립트를 사용한 부정 클릭

6.3.1 용어 정의

 - 피싱 : 경제적 이익을 얻기 위해 타인의 계정 정보를 불법적으로 획득하려는 시도.

 - 스파이더링 (= 웹 크롤링)

 - robot.txt : 웹 마스터는 웹 크롤링 제외 대상을 여기에 적시한다.

 - 양면성 페이지 : 브라우저의 종류나 기타 기준에 따라 다르게 보이는 페이지.

6.3.2 구성요소

6.3.3 악성광고 공격 구현

6.3.4 공격 은닉

6.3.5 사용자가 악성 사이트에 방문하는 이유는 무엇일까?

6.3.6 공격 탐지와 차단

6.3.7 간단한 경제적 분석

6.3.8 결론

 

7장 봇 네트워크

7.1 봇넷 소개

 - 원격 관리자가 명령과 제어 네트워크를 통해서 제어할 수 있는 소프트웨어가 설치된 사용자 컴퓨터다.

7.1.1 봇넷 문제 측정의 어려움

 - 풋프린트: 임의의 시점에 감염된 컴퓨터의 총 개수

 - 유효 개수: 언제라도 명령을 수신할 수 있는 감염된 봇의 개수

7.1.2 봇넷 크기 측정

7.2 봇넷의 네트워크적 특징

7.2.1 봇넷 통신의 특징

 

7.2.2 통신 프로토콜

7.2.3 네트워크 수준 유연성

7.3 봇의 소프트웨어적 특정

7.3.1 일반적인 소프트웨어 기능

7.3.2 감염 상태를 유지하기 위한 기술

 - 안티바이러스 소프트웨어 설치 : 이미 감염된 PC를 다른 악성코드로부터 방어하기 위해 해커가 설치함. (트로이 목마)

 - 안티디버깅과 안티가상화 기술의 결합.

7.3.3 봇넷의 활용 분야

7.4 웹 봇과 봇넷의 전망

7.4.1 봇넷 2.0: 브라우저 기반 봇

7.4.2 봇넷의 미래

7.5 대응책

 - 차단 : 안티바이러스 최신버전 업데이트

 - 탐지 : 봇넷은 네트워크 모니터링으로 탐지할 수 있다. 시스템 관리자는 패킷 스니퍼 같은 도구를 사용해서 자신이 관리하는 네트워크에 봇넷 활동이 있는지 여부를 알아낼 수 있다.

 - 억제 : 검역소로 고립

 - 제거 : 안티바이러스 SW로 제거. 허나 루트킷 기술을 적용한 봇의 경우 어렵다.

결론

 

8장 루트킷

8.1 루트킷이란?

 - 컴퓨터에서 자신의 존재를 탐지 불가능한 형태로 유지하기 위한 은닉 컴포넌트다.

 ex) 삼성 복원 솔루션은 사용자가 실수로 백업 디렉터리를 삭제하지 못하도록 막아준다.

8.2 루트킷의 역사

8.3 사용자 모드 윈도우 루트킷

 - DLL 인젝션 : 원격 스레드 생성, 윈도우 훅의 사용, AppInit_Dlls 레지스트리의 사용.

8.3.1 타겟 프로세스에 루트킷 로딩하기

8.3.2 실행 경로 수정하기

 - IAT 후킹

 - 임포트 주소 테이블 IAT

8.4 커널 모드 루트킷 기술

8.4.1 인터럽트 디스크립터 테이블 후킹

8.4.2 시스템 호출 후킹

8.4.3 시스템 서비스 디스크립터 테이블 후킹

8.4.4 스레드 기반 SSDT 후킹

8.4.5 시스템 호출 코드 패치

8.4.6 계층화 드라이버

8.4.7 IRP 패치

8.4.8 커널 객체 직접 변경

8.4.9 스케줄러에게 스레드 숨기기

8.4.10 가상 메모리 접근 리다이렉션하기

8.4.11 SCM 없이 커널 드라이버 로딩

8.5 리눅스 루트킷

8.5.1 실행파일 교체 루트킷

8.5.2 로딩 가능한 커널 모듈 루트킷

8.5.3 실행시간 커널 패치 루트킷

8.5.4 VFS 루트킷

8.6 바이오스 루트킷

8.7 PCI 루트킷

8.8 가상 기계 기반 루트킷

8.8.1 소프트웨어 기반 VMBR

8.8.2 하드웨어 보조 VMBR

8.9 루트킷 방어

8.9.1 루트킷 차단

 - 설치되지 못하도록. 시스템 자원수정을 하기 때문에 해당 자원에 접근을 하지 못하도록 설정.

   - 프로세스 주소 공간으로의 쓰기 접근 거부하기

   - 물리 메모리로의 쓰기 접근 거부하기

   - 패치카드 보호 사용하기 ex) 사용자 계정 컨트롤 UAC, 서명 드라이버 로딩

   - ROM 업데이트 차단하기

8.9.2 루트킷 탐지

   - 비교 탐지 : 정상적인 시스템과 비교

   - 가상 머신 탐지

9장 가상 세계와 사기

9.1 소개

9.1.1 사기와 게임

9.1.2 속임수와 게임

 - 속임수 (cheating) : 게임 규칙을 어기는 행위

 - 사기 : 법을 어기는 행위

9.2 사기 행각의 무대 MMOG

9.2.1 MMOG의 기능적 측면

9.2.2 MMOG의 구조적 측면

 - 클라이언트/서버 모델 : 게임 플레이

 - P2P모델 : 파일 배포에.

 - 사설 서버를 운영하는 경우도 있다.

9.3 전자 사기

9.3.1 피싱과 파밍

 - 스피어 피싱 (spear-phishing) 즉, 상황인지피싱이다.

9.3.2 속임수 애플리케이션

9.4 MMOG에서의 사기

9.4.1 MMOG용 확장 보안 모델

 - 데이터 손실 (기밀성)

 - 데이터 수정 (무결성)

 - 서비스 거부 (가용성)

 - 허위 표시 (신빙성)

9.4.2 MMOG 보안 가이드라인

9.4.3 대응책

결론

 

10장 사이버범죄와 정치

스푸핑(Spoofing)의 사전적 의미는 '속이다'이다. 네트워크에서 스푸핑 대상은 MAC 주소IP주소포트 등 네트워크 통신과 관련된 모든 것이 될 수 있고, 스푸핑은 속임을 이용한 공격을 총칭한다.

10.1 도메인 네임 악용

10.1.1 배경지식

10.1.2 2008년 연방 선거에서의 도메인 투기

 - 타이포 스쿼트: 일반적인 실수 다섯가지에 기반해서 오타 도메인 네임을 생성한다.

10.1.3 도메인 파킹

10.1.4 악의적 의도

10.2 선거 본부를 타겟으로 하는 피싱

10.2.1 이익을 노린 피싱

10.3 악성 코드와 보안 위험 요소

10.3.1 애드웨어

10.3.2 스파이웨어

10.3.3 악성 코드: 키로거와 크라임웨어

10.4 서비스 거부 공격

10.5 인지적 선거 해킹

10.6 공공의 유권자 정보 제공자: FEC 데이터베이스

 - 미국 연방 선거 위원회에서는 200달러 이상의 기부금을 낸 사람의 정보를 공개하게 되어 있다. 이 데이터를 해커들이 악용할 수 있다.

10.7 음성 통신 가로채기

결론

후기

 

11장 온라인 광고 사기

11.1 온라인 광고의 역사

11.2 수익 모델

 - CPM : cost per mile, 천 번당 비용

 - CPC : cost per click, 클릭당 비용

 - CPA : cost per action, 행위당 비용

 

11.2.1 광고 노출 기반 모델

11.2.2 클릭 기반 모델

11.2.3 행위 기반 모델

11.2.4 신디케이션

11.2.5 참조 거래

11.3 스팸 유형

11.3.1 노출 스팸

11.3.2 클릭 스팸

11.3.3 변환 스팸

11.4 공격 형태

11.4.1 사람에 의한 클릭

11.4.2 로봇에 의한 클릭

11.5 대응책

11.5.1 방지

11.5.2 탐지

11.5.3 봉쇄

11.6 부정 클릭 감사

11.6.1 지표의 기밀성

11.6.2 데이터 제약

11.6.3 프라이버시

11.7 부정 클릭의 경제적인 측면

결론

후기

 

12장 크라임웨어 비즈니스 모델

12.1 크라임웨어 비즈니스

 - 크라임웨어도 불법 복제의 대상이다.

12.1.1 서론

12.1.2 애드웨어

12.1.3 스파이웨어와 트로이

12.1.4 봇과 봇넷

결론

12.2 애드웨어 자세히 알아보기

12.2.1 온라인 광고 플랫폼

12.2.2 광고의 악의적인 면 

 

13장 보안 교육의 방향

13.1 왜 교육이 중요한가?

13.1.1 교육의 역할

13.1.2 보안 교육이 어려운 이유

 - 간략한 교육: 많은 사람을 이해시킬 수 있으나 역이용으로 인한 피해가 심각해질 수 있다.

  예) SSL 잠금 표시를 확인하라. (많은 해커들이 잠금 표시를 한다)

 - 복잡한 교육: 이해하기 어렵고 시간을 들여 설명을 들으려 하지 않는다.

13.1.3 기존 교육 방식

13.1.4 기존 교육 방식의 문제점

 - 교실에서 이뤄지는 스키강습과 같다. 실전 연습도, 피드백도 없이 오로지 한 가지 메시지만 전달할 뿐이다.

  "넘어지지 말 것"

13.1.5 교육 목표

13.2 사례 연구: 만화를 통한 교육

 - 웹툰 형식의 보안 교육이 필요하다.

결론

 

14장 은닉형 악성 코드와 관련 법

14.1 서론

14.2 은닉형 악성 코드의 특징

14.2.1 은닉형 악성 다운로드, 설치, 혹은 작동 

14.2.2 위장과 흉내

14.2.3 개인 데이터 수집과 전송

14.2.4 컴퓨터 작동과의 인터페이스 

14.2.5 은닉형 악성 소프트웨어의 참을성

14.2.6 은닉형 악성 소프트웨어의 또 다른 악행 

14.2.7 가로챈 정보 악용

14.3 주요 관계 법령

14.3.1 컴퓨터 사기 및 방지 법안

14.3.2 연방 통상 위원회 법안

14.3.3 동산 점유 방해 금지 청구

14.3.4 안티스파이웨어에 대한 연방 주 법안

14.4 부수적인 관련 법안

14.4.1 전자통신사생활보호법

14.4.2 CAN-SPAM 법

14.4.3 지적재산권법

14.4.4 명의도용사기방지법

14.4.5 통화기록불법취득법

14.4.6 절도법

결론

 

15장 크라임웨어와 신뢰컴퓨팅

15.1 서론

신뢰컴퓨팅(TwC)이란 무엇인가?

 마이크로소프트의 "신뢰할 수 있는 컴퓨팅"(TwC)은 전기와 가스, 수도 등과 같은 수준으로 신뢰할 수 있는 컴퓨팅 환경을 제공하는 것을 의미한다. TwC는 보안(security), 프라이버시(privacy), 안정성(reliability), 비즈니스 무결성(business integrity)으로 구성된다.

- 보안(Security): 악의적인 공격으로부터 시스템의 데이터, 무결성, 가용성을 안전하게 보호하고, 공격으로 인한 장애로부터 신속하게 회복할 수 있도록 한다.

- 프라이버시(Privacy): 모든 개인이 자신의 사적 정보를 제어할 수 있도록 하며, 모든 제품과 온라인 서비스는 공정한 정보 관리 원칙을 준수한다.

- 안정성(Reliability): 제품에 상시 의존할 수 있고, 필요할 때마다 사용할 수 있으며, 기대하는 수준으로 동작하도록 한다.

- 비즈니스 무결성(Business Integrity): 고객과 개방적이고도 투명한 방법으로 대화하고, 제품과 서비스의 이슈들을 강조하며, 고객들이 적절한 솔루션을 찾을 수 있도록 돕는다.

 

15.2 공격 해부

15.3 크라임웨어와 신뢰컴퓨팅의 전쟁 

15.3.1 무결성 측정과 스토리지

15.3.2 검증

15.3.3 보호 스토리지: 바인딩과 봉인

 - TPM : 신뢰 플랫폼 모듈(Trusted Platform Module, 줄여서 TPM) 또는 신뢰할 수 있는 플랫폼 모듈[1]은 컴퓨팅 환경에서 암호화 키를 저장할 수 있는 보안 암호 처리자를 자세히 기록한 규격의 이름을 말한다. 또, "TPM 칩", "TPM 보안 장치"라 불리는 규격 기능의 총체적 이름이기도 하다.

 - 바인딩 : 수신자의 TPM에서 가져올 수 없는 비공개 키에 대응하는 공개 키를 사용해서 데이터를 암호화함을 뜻한다. 비공개 키를 관리하는 TPM만이 메시지를 해독할 수 있다.

 - 봉인 : 바인딩 과정에 한 가지 작업을 더 추가한 것이다. 중요 데이터가 무결성 메트릭과 결합된뒤 암호화된다.

15.3.4 보안 부트

15.3.5 하드웨어적 격리 (하드웨어적 소프트웨어 격리)

15.3.6 신뢰컴퓨팅은 만병 통치약?

 - 신뢰컴퓨팅의 가장 큰 문제는 '방지'에 있는게 아니라 '진단'에 있다는 점이다. 정상 시스템을 기준으로 변경이 된 것을 문제로 간주하기 때문에 정확히 어떤 악성코드가 어디에서 활동하고 있고 이를 제거하는 방법을 알 수 없다.

15.4 사례 연구

15.4.1 신용 카드 거래 보호

15.4.2 컨텐츠 보호

 -DRM

 

결론

 

16장 방어 기술

16.1 케이스 스터디: 스파이웨어 심층 방어

16.1.1 서론

 - 크라임웨어 감염은 이제 지극히 평범한 일이 돼버렸다. 미국 컴퓨터 사용자 중 89%가 스파이웨어에 감염되었으며 한 대당 평균 30개의 스파이웨어가 설치됐다고 예측했다.

 - 예방, 탐지, 봉쇄

 - Signature(시그니처): 정책 위반, 취약한 상태, 침입과 관련되었을 수 있는 활동을 나타내는 작업의 상태 또는 패턴입니다.

16.1.2 패킷 백신 (예방)

16.1.3 AGIS(탐지와 제거) : 자동 감염 시그니처 생성 기술.

16.1.4 스파이쉴드(봉쇄)

결론

16.2 크라임웨어 저항 인증

16.2.1 서론

 - 개인확인 질문은 공공 데이터베이스 조회로 알아낼 수 없어야 하고, 높은 엔트로피를 지녀야 하고(사용자 응답의 불확실성이 엔트로피. 높을 수록 좋다), 시간이 지나면 바뀌는 것이 좋다. 예) 마지막으로 키스한 이성은?

16.2.2 기존의 크라임웨어 저항 방식 

 - 텍스트 패스워드의 약점: 1) 사전(dictionary)공격에 약하다 2) 사용자는 여러 계정에 동일한 패스워드를 사용하는 경향이 있다. 3) 사용자는 자신의 패스워드를 잘 바꾸지 않는다. 4) 패스워드는 유저를 확인시켜줄 수 있지만 은행이나 기관을 확인시켜주지 못한다.(일방향)

 - 화상키보드

 - SSL인증서

 - 이중 보안 인증 : 다음 중 2가지 이상을 사용한다. 1) 사용자가 알고 있는 것(패스워드) 2) 사용자가 갖고 있는 것(보안 토큰, SMS인증) 3) 사용자 자신 (지문, 홍채)

 - 패스워드 해싱 : SSO(Single Sign On) 기술. 하나의 마스터 패스워드로 각 사이트마다 다른 패스워드를 생성해준다.

 - 스파이블락 : 사용자가 가상머신에서 웹을 탐색하게 한다.

 - 인간 중심, 시도 응답 프로토콜 : 안드로이드 패턴락과 비슷

16.2.3 선호도 근거 개인 정보 확인 질문

 - 매우 좋아함~ 매우 싫어함 까지 5가지 항목으로 나누고 질문Set을 미리 풀게하고 암호를 잃어버린 경우 해당 질문Set을 다시 풀어보게 하는 방식.

16.2.4 바람직한 개인 정보 확인 질문 

같은 장르에 대한 질문이라고 해도 선택지의 개수와 범주에 따라 좋은 질문이 되기도 하고 나쁜 질문이 되기도 한다. 해당하는 내용에 대한 구체적인 결과는 624p를 참조할 것.

16.2.5 좋은 질문 찾기

16.2.6 오류율 결정

16.2.7 질문과 엔트로피

결론

16.3 크라임웨어 방어 메커니즘으로 활약하는 가상 머신

 

17장 크라임웨어의 미래

17.1 크라임웨어, 테러웨어, 반달웨어, 랜섬웨어

 - 테러웨어: 민족이나 국가에 해를 끼칠 목적으로 제작된 악성 소프트웨어.

 - 반달웨어: 테러웨어의 동생 뻘. 정치 혹은 기업을 공격할 목적으로 느슨하게 구성된 공격자 그룹에 의해 움직인다. 핵티비즘의 중심. (ex. 잘못된 선거 정보를 유포하는 봇)

17.2 새로운 애플리케이션과 플랫폼

17.2.1 평판 시스템, 경매 사이트와 도박 애플리케이션 

17.2.2 전화, 자동차와 착용식 컴퓨터

17.3 소셜 네트워크를 이용한 공격

17.4 인터넷의 새로운 용도: 인프라스트럭처 제어

17.5 크라임웨어의 향후 전망

17.6 지식정보사회의 발전: 점점 더 약해지고 있지는 않은가?

17.7 총괄

 

 

 

 


+ Recent posts