자바스크립트는 웹 페이지와 상호작용하도록 디자인된 스크립트 언어이며 다음 세 부분으로 구성됩니다.
ECMA-262에서 정의하는 ECMAScript 핵심 기능을 제공합니다.
문서 객체 모델(DOM) 웹 페이지 콘텐츠를 조작하는 메서드와 인터페이스를 제공합니다.
브라우저 객체 모델(BOM) 브라우저와 상호작용하는 메서드와 인터페이스를 제공합니다.
이들 부분에 대한 주요 웹 브라우저(크롬, 익스 등)의 지원은 각기 다릅니다. ECMAScript 3에 대한 지원은 일반적은 좋은 편이며, ECMAScript 5에 대한 지원은 점점 나아지는 중이지만, DOM지원은 편차가 심합니다.
BOM은 최근에야 HTML5에서 표준화되고 있으므로 브라우저 사이에 일부 공통인 점이 있긴 하지만 매우 다르다고 생각해야 합니다.
2. HTML 속의 자바스크립트
자바스크립트는 <script>요소를 통해 HTML페이지에 삽입됩니다. 자바스크립트는 HTML 페이지 안에 인라인으로 쓸 수도 외부 파일로 분리 할 수도 있습니다. 다음 내용은 이 장의 핵심입니다.
외부 자바스크립트 파일을 불러오려면 src 속성에 파일의 위치를 나타내는 URL을 씁니다. ㅍ외부 파일은 페이지와 같은 서버에 있어도 되고 완전히 다른 도메인에 있어도 됩니다.
모든 <script> 요소는 페이지에 나타나는 순서대로 해석됩니다. defer 속성이나 async 속성을 사용하지 않았다면 <script> 요소의 코드를 완전히 해석한 이후에 만 그 다음 <script> 요소의 코드를 해석하고 처리할 수 있습니다.
브라우저는 지연되지 않은 <script> 요소의 코드를 완전히 해석한 이후에만 페이지 렌더링을 계속할 수 있습니다. 이 때문에 <script> 요소는 보통 페이지의 주요 콘텐츠 다음, </body> 태그 바로 앞에 놓습니다.
defer 속성을 써서 스크립트의 실행을 문서 렌더링 이후로 미룰 수 있습니다.
async 속성을 쓰면 해당 스크립트가 해석될 떅가지 다른 스크립트나 문서 렌더링을 차단하지 않아도 된다고 명시할 수 있습니다. 비동기 스클빝트는 마크업 순서대로 실행된다는 보장은 없습니다.
<nosciprt> 요소를 쓰면 해당 콘텐츠는 브라우저가 스크립트를 지원하지 않거나 비활성화되었을 때만 표시됩니다. <noscript> 요소의 콘텐츠는 브라우저에서 스크립트를 사용할 수 있는때는 결코 표시되지 않습니다.
3. 언어의 기초
자바스크립트의 핵심 기능은 ECMA-262에서 ECAMScripts라는 이름의 가상 언어로 정의했습니다. ECMAScript는 기본적인 문법과 연산자, 데이터 타입, 객체 등 기복적인 작업에 필요한 것은 모두 정의했지만, 입출력을 다루는 부분은 정의하지 않았습니다. ECMAScript를 충분히 이해해야 웹 브라우저에서 구현한 자바스크립트를 이해할 수 있습니다. 가장 널리 구현된 ECMAScript 버전은 ECMA-262 3판이며 많은 브라우저에서 5판을 도입하고 있습니다. ECMAScript의 기본요소는 다음과 같습니다.
ECMAScript의 기본 데이터 타입은 Undefiend와 Null, Boolean, Number, String입니다.
여타 언어와는 달리 ECMAScript는 정수와 부동소수점 숫자를 구분하지 안습니다. 숫자 데이터 타입의 두 가지를 모두 나타냅니다.
복잡한 데이터 타입인 Object 타입도 있으며 이 타입은 자바스크립트의 모든 개체의 기반입니다.
스트릭트 모드는 자바스크립트에서 에러가 자주 생기는 부분에서 몇 가지 제약을 가한 겁니다.
ECMAScript는 C 및 C와 비슷한 언어에서 사용하는 기본 연산자인 산술 연산자, 불리언 연산자, 관계 연산자, 동일(일치) 연산자, 할당 연산자등을 제공합니다.
자바스크립트의 제어문은 대개 다른 언어에서 차용한 것이며, if 문이나 for문, switch 문 등이 이에 해당합니다.
ECMAScript의 함수는 다른 언어의 함수와 다르게 동작합니다.
함수는 언제든, 무슨 값이든 반환할 수 있으므로 함수의 반환ㄴ 값을 미리 명시할 필요는 없습니다.
값을 반환하지 않는 함수는 사실 특별한 값 undefined를 반환합니다.
ECMAScript의 함수에는 시그니처 같은 성질은 없는데 매개변수가 사실 배열이며, 어떤 값이든 가질 수 있기 때문입니다.
함수에 넘기는 매개변수 숫자에는 제한이 없으며, arguments 객체를 통해 접근할 수 있습니다.
함수 시그니처가 없기 때문에 ECMAScript의 함수는 오버로딩이 불가능합니다. 매개변수의 종류와 타입에 따라 달리 동작하도록 정의해서 오버로딩을 흉내낼수는 있습니다.
4. 변수와 스코프, 메모리
자바스크립트 변수에는 원시 값과 참조 값 두 가지 형태로 값을 저장할 수 있습니다. 원시 값은 불리언과 숫자, 문자열, Undefiend, Null의 다섯 가지 원시 데이터타입니다. 원시 값과 참조 값에는 다음과 같은 특징이 있습니다.
원시 값은 고정된 크기를 가지며 스택 메모리에 저장됩니다.
원시 값은 한 변수에서 다른 변수로 복사하면 값 자체가 복사됩니다.
참조 값은 객체이며 힙 메모리에 저장됩니다.
변수에 참조 값을 저장하면 해당 변수는 객체에 대한 참조만 저장할 뿐 객체 자체를 저장하는 것은 아닙니다.
참조 값을 한 변수에서 다른 변수로 복사하면 해당 객체에 대한 참조만을 복사하므로 두 변수는 같은 객체를 참조합니다.
원시 값과 참조 값을 가리지 않고 모든 변수는 스코프라고 부르기도 하는 실행 컨텍스트에 존재하는데, 실행 컨텍스트는 변수가 존재하는 기간을 결정하며 어느코드가 해당 변수에 접근할 수 있는지도 결정합니다. 실행 컨텍스트는 다음과 같이 요약할 수 있습니다.
실행 컨텍스트에는 전역 컨텍스트와 함수 컨텍스트가 있습니다.
실행 컨텍스트에 진입할 때마다 스코프 체인이 만들어지며, 스코프 체인은 변수와 함수를 검색하는 데 쓰입니다.
함수 컨텍스트는 해당 스코프에 있는 변수, 해당 스코프를 포함하는 컨텍스트에 있는 변수, 전역 컨텍스트에 있는 변수에 모두 접근 할 수 있습니다.
전역 컨텍스트는 전역 컨텍스트에 있는 변수와 함수에만 접근할 수 있으며 로컬(함수) 컨텍스트에 있는 데이터에 직접적으로 접근할 수 는 없습니다.
실행 컨텍스트는 변수에 할당된 메모리를 언제 해제할 수 있는지 판단하는데 도움이 됩니다.
자바스크립트는 자동으로 가비지 컬렉션을 수행하므로 개발자가 메모리 할당과 회수에 크게 신경 쓸 필요는 없습니다. 자바스크립트의 가비지 컬렉션 루틴은 다음과 같이 요약할 수 있습니다.
값이 스코프를 벗어나면 자동으로 표시되고 다음에 가비지 컬렉션을 실행할 때 삭제됩니다.
주로 쓰이는 가비지 켈렉션 알고리즘은 '표시하고 지우기'라 불리는데, 이 방법은 현재 사용하지 않는 값에 표시를 남겨서 메모리를 회수하는 방법입니다.
다른 알고리즘은 참조 카운팅이라 불리는데, 이 방법은 값이 얼마나 많이 참조되었는지 추적하는 방법입니다. 이 알고리즘은 거의 쓰이지 않지만 인터넷 익스플로러에서는 아직 쓰이는데 DOM 요소처럼 네이티브 자바스크립트 객체가 아닌 객체를 자바스크립트에서 접근해야 하기 떄문입니다.
변수에서 참조를 제거하면 순환 참조 문제도 해결할 수 있고 가비지 콜렉션에도 도움이 도비니다. 가능한 한 많은 메모리를 회수해 효율적으로 관리하려면 전역 객체, 전역 객체의 프로퍼티, 순환 참조에 대한 참조를 제거해야 합니다.
5. 참조 타입
자바스크립트 객체는 참조 값이라고 불리며 다음과 같이 내장된 참조 타입을 통해 특정한 타입의 객체를 만들 수 있습니다.
ECMAScript의 참조 타입은 전통적인 객체 지향 언어의 클래스와 비슷하지만 다른 점도 많습니다.
모든 참조 타입은 Object 타입의 작동방직을 상속합니다.
Array 타입은 테이터의 순서 있는 목록이며 포함한 값을 조작하고 변환하는 기능을 제공합니다.
Date 타입은 현재의 날짜와 시간을 포함해 날짜와 시간에 관한 정보를 제공하며 이를 가공하는 메서드도 갖고 있습니다.
RegExp 타입은 ECMASciprt에서 지원하는 정규 표현식에 대한 인터페이스이며 정규 표현식의 기본 기능은 대부분 지원하고 고급 기능도 일부 지원합니다.
자바스크립트의 독특한 점은 함수가 Function 타입의 인스턴스, 즉 함수도 객체의 일종이라는 점입니다. 함수는 객체이므로 메서드가 있고 이 메서드를 통해 함수의 동작 방식을 확장 할 수 있습니다.
자바스크립트에는 원시 레퍼 타입이 있어서 원시 값을 마치 객체라며 다룰 수 있습니다. 원시 래퍼 타입은 Boolean, Number, String 세가지 입니다. 원시 레퍼 타입에는 다음과 같은 특징이 있습니다.
각 래퍼 타입은 같은 이름의 원시 타입에 대응합니다.
원시 값을 읽기 모드로 접근할 때 원시 래퍼 객체의 인스턴스가 만들어지며 이를 통해 테이터를 조작합니다.
래퍼 객체는 원시 값을 조작하는 문장이 실행되는 즉시 파괴됩니다.
내장 객체인 Global, Math 객체는 코드가 실행되는 즉시 실행됩니다. ECMAScript에서 Global 객체에 접근할 수 있는 방법은 없지만 웹 브라우저는 Global 객체를 window 객체로 구현합니다. Global 객체는 모든 전역 변수와 함수를 프로퍼티 형태로 포합합니다. Math 객체에는 복잡한 수학 계산에 필요한 프로퍼티와 메서드가 들어 있습니다.
6. 객체 지향 프로그래밍
ECMAScript는 클래스나 인터페이스의 개념 없이 객체지향 프로그래밍을 지원합니다. 객체는 코드 실행 도중에 생성되고 확장되므로 엄격히 정의된 엔티티라기 보다는 동적 성격이 강합니다. 클래스 대신 다음 패턴을 사용하여 객체를 생성합니다.
팩토리 패턴은 단순한 함수를 써서 객체를 생성하고 프로퍼티와 메서드를 할당한 후 반환합니다. 이 패턴은 생성자 패턴을 밀려 거의 쓰이지 않습니다.
생성자 패턴은 내장 객체 인스턴스와 같은 방법으로 new 연산자를 이용해 커스텀 참조 타입을 생성합니다. 하지만 생성자 패턴은 함수를 포함해 객체 멤버 어떤 것도 재사용 불가능하다는 약점이 있습니다. 자바스크립트에서는 함수를 느슨한 타입으로 생성할 수 있으므로 여러 객체 인스턴스에서 함수를 공유하지 않을 이유가 없습니다.
생성자의 prototype 프로퍼티로 공유 할 프로퍼티와 메서드르 할당하는 프로토타입 패턴에는 이런 문제가 없습니다. 생성자와 프로토타입을 조합하는 패턴에서는 생성자를 써서 인스턴스 프로퍼티를 정의하고 프로토타입 패턴으로 공유 프로퍼티와 메서드를 정의합니다.
자바스크립트에서 상속은 일차적으로 프로토타입 체인 개념을 통해 구현됩니다. 프로토타입 체인은 생성자의 프로토타입에 다른 타입의 인스턴스를 할당하는 방법입니다. 이렇게 하면 하위 타입은 클래스 기반 상속과 비슷한 방법으로 상위타입의 프로퍼티와 메서드를 상속합니다. 프로토타입 체인의 문제는 모든 객체 인스턴스에서 프로퍼티와 메서드를 공유하므로 독자적인 사용이 어렵다는 점입니다. 생성자 훔치기 패턴은 하위 타입의 생성자 안에서 상위 타입의 생성자를 호출하는 방식으로 이 문제를 해결합니다. 이렇게 하면 각 인스턴스가 고유한 프로퍼티를 가질 수 있지만, 생성자 패턴을 통해서만 타입을 정의할 수 있다는 한계가 있습니다. 상속에서 가장 인기 있는 패턴은 프로토타입 체인을 이용해 공유 프로퍼티와 메서드를 상속하고 생성자 훔치기로 인스턴스 프로퍼티를 상속하느 조합 상속입니다. 상속에는 다음 대체 패턴도 있습니다.
프로토타입 상속은 주어진 객체를 복제하는 식으로 상속을 구현하며 미리 정의된 생성자는 필요 없습니다. 결과 객체를 더 확장할 수도 있습니다.
프로토타입 상속과 밀접히 관련된 기생 상속이란 패턴도 있습니다. 이 패턴은 다른 객체나 정보에 기반해 객체를 생성하고 확장하여 반환합니다. 이 패턴은 조합 상속과 함께 써서 상위 타입 생성자를 여러 번 호줄하는 비효율성을 제거하는 용도로도 사용합니다.
기생 조합 상속은 타입 기반 상속을 가장 효과적으로 구현하는 패턴으로 알려져 있습니다.
7. 함수표현식
함수 표현식은 자바스크립트 프로그래밍에서 유용한 도구입니다. 함수 표현식은 함수에 꼭 이름이 필요하지 않게 함으로 진정 동적인 프로그래밍을 가능케 합니다. 이러한 익명 함수를 람다 함수라 부리기도 하는데 자바스크립트 함수를 사용하는 강력한 방법입니다. 다음은 함수 표현식의 요약입니다.
함수 표현식은 함수 선언과는 다릅니다. 함수 선언에는 이름이 필요하지만 함수 표현식에는 필요하지 않습니다. 이름 없는 함수 표현식을 익명 함수라고 부르기도 합니다.
함수를 참조하는 방법으로 명확히 정의된 것이 없어서 재귀 함수는 더 복잡해졌습니다.
스트릭트 모드가 아닐 떄는 재귀 함수에서 함수 이름 대신 arguments.callee를 써더 자기 자신을 호출 가능합니다.
클로저는 다른 함수안에서 정의된 함수입니다. 따라서 클로저는 외부 함수의 변수에 접근 가능합니다.
클로저의 스코프 체인에는 자기 자신과 외부 함수, 전역 컨텍스트의 변수 개체가 담깁니다.
일반적으로 함수가 실행을 마치면 함수의 스코프 및 그에 담긴 변수 전체가 파괴됩니다.
함수가 클로저를 반환했다면 해당 함수의 스코프는 클로저가 존재하는 동안에는 메모레에 계속 존재합니다.
클로저를 사용하면 자바스크립트 자체에서는 지원하지 않는 블록 스코프를 다음과 같이 흉내 낼 수 있습니다.
함수를 생성하는 즉시 호출하면 내부의 코드를 실행하지만 그에 관한 참조는 남지 않습니다.
결과적으로 함수에서 사용한 변수는 모두 파괴되는데 외부 스코프의 특정 변수로 설정된 변수는 예외입니다.
클로저는 다음과 같이 객체에 고유 변수를 만들 때도 쓸 수 있습니다.
자바스크립트에 고유 객체 프로퍼티라는 정식 개념은 없지만, 클로저를 쓰면 외부 스코프에 정의된 변수에 접근 가능한 공용 메소드를 구현 할 수 있습니다.
함수 표현식과 클로저는 자바스크립트에서 대단히 강력한 기능 중 하나이며 많은 일을 할 수 있습니다. 하지만 클로저는 스코프를 더 관리해야 하므로 과용하면 메모리 소비가 늘어날 수 있습니다.
8. 브라우저 객체 모델
브라우저 객체 모델(BOM)은 브라우저 창과 페이지의 보이는 영역을 나타내는 window 객체에 기반하여 만들어집니다. window 객체는 ECMAScript의 Global 객체에 해당하므로 전역 변수와 함수는 모두 window 객체의 프로퍼티가 되고 네이티브 생성자와 함수는 처음부터 window 객체에 존재합니다. 이 장에는 다음과 같은 BOM요소를 설명했습니다
프레임을 사용하면 각 프레임마다 window 객체가 생기고 그에 따라 네이티브 생성자와 함수를 가집니다. 각 프레임은 frame 켈렉션에 저장되며 위치나 이름을 통해 찾을 수 있습니다.
부모 프레임에 포함된 다른 프레임을 참조하는 포인터가 몇가지 존재합니다.
top 객체는 항상 전체 브라우저 창을 나타내는 최상위 프레임을 가리킵니다.
parent 객체는 외부 프레임을 나타내며 self는 window를 가라킵니다
location 객체를 통해 브라우저의 내비케이션 시스템에 접근하고 조작할 수 있습니다. location 객체의 프로퍼티를 설정해서 브라우저의 URL 일부 또는 전체를 변경 할 수 있습니다.
replace() 메서드는 새 URL로 이동하는 동시에 브라우저 히스토리 상의 현재 페이지를 덮어씁니다.
navigator 객체는 브라우저에 관한 정보를 제공합니다. 어떤 타입의 정보를 제공하는지는 브라우저에 따라 매우 다르지만 모든 브라우저에서 지원하는 userAgent 같은 공통 프로퍼티도 있습니다.
BOM에는 다른 개체가 두개 더 있는데 이들의 기능은 매우 제한적입니다. screen 객체는 클라이언트 화면에 관한 정보를 제공합니다. 이 정보는 일반적으로 통계 목적의 웹사이트에서 쓰입니다. history 객체는 브라우저의 히스토리 스택에 대해 제한된 접근을 허용하며 개발자는 이를 통해 히스토리 스택에 얼마나 많은 기록이 남아 있는지 알 수 있고 히스토리 남아 있는 페이지로 이동할 수 있습니다.
9. 클라이언트 탐지 - deprecated
10. DOM
DOM은 HTML과 XML문서에 접근하고 조작하는 언어 독립적인 API입니다. DOM 레벨 1은 HTML 및 XML 문서를 노드의 계층 구조로 표현하며 자바스크립트로 이를 조작하여 문서의 구조와 외형을 바꿀 수 있습니다. DOM은 다음에 나열하는 노드 타입으로 이루어집니다.
기본 노드 타입은 Node입니다. Node 타입은 문서의 각 부분을 추상화해 표현한 것이며 다른 타입은 모두 Node를 상속합니다.
Document 타입은 전체 문서를 표현하며 노드 계층 구조의 루트입니다. 자바스크립트에서 document 객체는 Document의 인스턴스이고 노드를 쿼리하고 가져오는 다양한 방법을 제공합니다.
Element 노드는 문서의 HTML 및 XML 요소 전체를 표현하며 각 요소의 콘텐츠와 속성을 조작하는 사용합니다.
그 밖에 텍스트 콘텐츠, 주석, 문서 타입, CDATA 섹션, 문서 버퍼에 대한 노드타입이 존재합니다.
DOM 접근은 보통 예상대로 이러우지지만 <script>나 <style> 요소는 다소 복잡할 수 있습니다. 이들 요소는 각각 스크립트와 스타입 정보를 포함하므로 브라우저는 이들을 다른 요소와 다르게 취급할 때가 많습니다.
DOM에서 가장 중요한 부분을 아마 성능에 관한 부분일 겁니다. DOM 조작은 자바스크립트에서 가장 느린 작업이며 그중에서도 NodeList객체에 특히 골칫거리입니다. NodeList객체는 "살아있는" 것으로 간주하는데 객체에 접근할 때마다 다시 쿼리한다는 의미입니다. 이 때문에 가능하면 DOM조작을 최소화하는 편이 좋습니다.
11. DOM 확장
XML 및 HTML 문서를 조작하는 핵심 API는 DOM에 정의되어 있지만 표준 DOM을 확장하는 다른 명세도 여러 가지입니다. 이들 확장 대부분은 처음에는 브라우저 전용 확장이었지만 나중에 브라우저끼리 서로의 기능을 흉내 내면서 사실상의 표준이 된 것들입니다. 이 장에서는 세 가지 명세를 설명했습니다.
선택자 API는 CSS 선택자에 기반해 DOM 요소를 선택해 반환하는 querySelector(), querySelectorAll() 두 가지 메서드를 정의합니다.
요소 이동은 DOM 요소에서 다음 관련된 DOM 요소로 쉽게 이동하는 프로퍼티를 몇 가지 정의합니다. 이 명세가 필요하게 된 주된 이유는 브라우저마다 DOM에 있는 공백을 다르게 취급하기 떄문입니다.
HTML5는 표준 DOM에 여러 가지 확장을 추가합니다. 추가된 확장에는 innerHTML 같은 사실상의 표준을 표준으로 확정하고 포커스 관리, 문자셋, 스크롤 등을 다루는 기능을 추가했습니다.
현재 DOM 확장은 많지 않지만 웹 기술이 발전함에 따라 그 숫자가 늘어날 것은 분명합니다. 브러우저들은 여전히 전용 확장을 실험하고 있으며 성공적이라면 innerHTML 같은 사실상의 표준이 되거나 명세의 미래 버전에서 표준이 될 겁니다.
12. DOM 레벨 2와 레벨 3
DOM 레벨 2 명세는 여러 가지 모듈을 정의하여 DOM 레벨 1의 기능을 확장합니다. DOM 레벨 2 코어는 XML 네임스페이스와 관련된 새 메서드를 다양한 DOM 타입에 추가합니다. 이들 새 머서드는 XML이나 XHTML 문서에서만 필요하며 HTML 문서에는 필요하는 않습니다. XML 네임스페이스와 무관한 메서드는 Document의 새 인스턴스와 DocumentType 객체를 생성하는 메서드입니다. DOM 레벨 2 스타일 모듈은 요소의 스타일 정보를 조작하는 방법을 정의하며 다음과 같이 요약됩니다.
모든 요소에는 style 객체가 잇어서 인라인 스타일을 확인하거나 조작하는데 쓰입니다.
요소에 적용된 CSS 규칙 전체를 포함해 계산된 스타일이 필요할 떄는 getComputed Style() 메서드를 사용합니다.
인터넷 익스플로러는 이 메서드를 지우너하지 않지만 같은 정보를 반환하느 currentStyle 프로퍼티를 지원합니다.
document.styleSheets 컬렉션을 통해 스타일시트에 접근할 수도 있습니다.
인터넷 익스폴러 8 및 이전 버전을 제외한 모든 브라우저에서 스타일 시트 인터페이스를 지원합니다. 스타일싵트 인터페이스는 거의 모든 DOM 기능에 대응하느 프로퍼티와 메서드를 제공합니다
DOM레벨 2 이동과 범위 모듈을 다음과 같이 DOM 구조와 상호작용하는 새로운 방법을 제사합니다.
NodeIterator와 TreeWalker는 수직 방향을 우선으로 하는 방식으로 DOM 트리를 이동합니다.
NodeIterator 인터페이스는 매우 단순하며 한 단계 앞이나 뒤로 이동하는 방법만 있습니다. TreeWalker 인터페이스는 매우 단순하며 한 단계 앞이나 뒤로 이동하는 방범만 있습니다. TreeWalker 인터페이스는 이에 더해 부모, 형제, 자식 등 모든 방향의 이동을 지원합니다.
범위는 DOM 구조의 특정 부분을 선택한 후 이를 확장합니다.
범위는 문서의 일정 부분을 선택하여 제거하더라도 문서 형식이 깨지는 일은 없으며 선택한 부분을 복사할 수도 있습니다.
인터넷 익스플로러 8 및 이전 버전은 지원 DOM 레벨 2 이동과 범위를 지원하지 않지만 전용 텍스트 범위 객체를 제공하여 단순한 텍스트 기반 범위 조작은 가능합니다. 인터넷 익스프로러 9는 DOM 이동을 완전히 지원합니다.
13. 이벤트
이벤트는 자바스크립트와 웹 페이지를 연결하는 우선적인 방식입니다. 공통 이벤트는 대부분 DOM 레벨 3 이벤트 명세나 HTML5에 정의되어 있습니다 기본 이벤트에 대한 명세가 존재하지만, 많은 브라우저가 명세에서 정한 이상을 전용 이벤트로 구현하여 사용자 상호작용에 대해 더 많이 알아내려고 합니다. 모바일 사파리 orientationchage 이벤트가 IOS 장치 전용이듯 전용 이벤트 일부는 특정 장치가 직접 관련되어 있습니다. 이벤트에는 메모리와 성능에 관래 주의할 점이 있습니다. 다음과 같이 요약할 수 있습니다.
이벤트 핸들러가 많을수록 페이지 메모리를 많이 사용하고 페이지의 응답성이 떨어지므로 이벤트 핸들러 개수를 제한하는 편이 좋습니다.
이벤트 위임은 이벤트 버블링의 장점을 활용하여 이벤트 핸들러 숫자를 제한합니다.
페이지를 언로드하기 전에 페이지에 추가했던 이벤트 핸드러를 모두 제거하는 편이 좋습니다.
자바스크립트를 이용해 이벤트를 시뮬레이트할 수 있습니다. DOM 레벨 2와 3 이벤트 명세는 모든 이벤트의 시뮬레이션 방법을 제공하므로 정의된 이벤트는 모두 쉽게 시뮬레이트할 수 있습니다. 다른 테그닉을 조합하여 키보드 이벤트를 시뮬레이트할 수도 있습니다. 인터넷 익스플로러 8 및 이전 버전도 인터페이스는 좀 다르지만 이벤트 시뮬레이션을 지원합니다.
이벤트는 자바스크르빝으에서 가장 중요한 주체 중 하나이므로 어떻게 동작하는지, 서능에 어떤 영향이 있는지 잘 이해해야 합니다.
14. 폼 스크립트
HTML과 웹 애플리케이션은 매우 많이 발전했지만 웹 폼은 거의 바뀌지 않았습니다. 자바스크립트를 이용해 이미 존재하는 폼 필드를 확장해서 새 기능을 추가하고 사용성을 올릴 수 있습니다. 다음은 이 장에서 소개한 개념 일부입니다.
텍스트 박스의 텍스트 전체, 또는 일부를 선택하는 방법은 표준과 비표준에 다양하게 존재합니다.
모든 브라우저에서 선택한 텍스트를 조작할 때 파이어폭스의 방법을 받아들여 표준이 되었습니다.
텍스트 박스의 키보드 이벤트를 주시해서 특정 문자를 금지하거나 허용 할 수 있습니다.
오페라를 제외한 모든 브라우저에서 클립보드 이벤트 copy, cut, paste를 지원합니다. 클립보드 이벤트 구현은 다음과 같이 브라우저마다 다릅니다.
인터넷 익스플로러, 파이어폭스 등 자바스크립트에서 클립보드 데이터에 접근할 수 있자만, 오페라는 허용하지 않습니다.
그 중에서도 인터넷 익스폴로러, 크롬, 사파리의 구현 방법이 다릅니다.
파이어 폭스, 사파리, 크롬은 paste 이벤트에서만 클립보드 데이터를 읽을 수 있지만 인터넷 익스플로러에는 이런 제한이 없습니다.
파이어 폭스, 사파리, 크롬은 클립보드 정보를 클립보드 관련 이벤트에서만 쓸 수 있게 제한하지만 인터넷 익슾ㅍ폴러에서는 언제든 데이터에 접근 가능합니다.
클립보드 이벤트를 주시하면 텍스트 박스에 반드시 제한된 문자만 입력해야 하는 상황에서 붙어넣기를 막을 수 있습니다.
SELECT 박스도 자주 자바스크립트로 컨트롤합니다. DOM 덕분에 SELECT 박스를 조작하는 일이 전보다 휠씬 쉬워졌습니다. 표준 DOM 테크닉을 이용해 옵션을 추가하고, 제거하고, SELECT 박스 사이에서 이동하며 순서를 바꿀 수도 있습니다.
리치 텍스트 편집은 빈 HTML 문서가 들어 있는 iframe 요소를 이용합니다. 문서의 designMode 프로퍼티를 "on"으로 설정하면 페이지가 편집 가능한 상태가 되며 마치 워드 프로세스처럼 동작합니다. 요소에 contenteditable 속성을 지정해도 됩니다.
기본적으로 볼드체나 이텔릭체 같은 폰트 스타일을 토급하고 클립보드를 조작할 수 있습니다. 자바스크립트에서는 execCommand() 메서드를 통해 이 기능 일부를 수행하며 성택한 텍스트에 대한 정보는 queryCommandEnabled(), queryCommandState(), queryCommandValue() 메서드를 통해 얻습니다.
이런 식으로 만든 리치 텍스트 에디터에서 폼 필드를 생성하지는 않으므로, 편집한 HTML을 서버에 전송하려면 폼 필드에 복사해야 합니다.
15. 캔버스와 그래픽
16. HTML5
HTML5에서는 새로운 마크업 규칙과 함께 여러 가지 자바스크립트 API를 정의했습니다. 이들 API는 데스크톱 애플리케이션과 비교할 만한 웹 인터페이스 기능을 만들 수 있도록 디자인되었습니다. 이 장에서 설명한 API는 다음과 같습니다.
문서간 메서징을 동일 소스 정책 수준의 보안을 유지하면서 다른 소스에서 유래한 문서 사이에서 메시지를 주고 받습니다.
네이티브 드래그 앤 드롭을 이요하면 요소가 드래그 가능함을 쉽게 표현할 수 있고 드롭에 대해 운영체제처럼 매끄럽게 반응 가능합니다. 임의 요소를 드래그 대상으로도, 드롭 타킷으로도 만들 수 있습니다.
새 미디어 요소은 <audio>와 <video>에는 오디오와 비디오를 다루는 독자적인 API가 있습니다. 모든 브라우저가 모든 미디어 형식을 지원하지는 않은므로, canPlayType() 메서드를 써서 브라우저가 해당 형식을 제대로 지원하는 확인하십시오
히스토리 상태 관리를 이용하면 현재 페이지에서 나기지 않고도 브라우저와 히스토리 스택을 바꿀 수 있습니다. 자바스크립트만으로 사용자가 뒤로가기/앞으로 가기 버튼을 눌러 페이지 상태 사이를 이동하도록 처리할 수 있습니다.
17. 에러처리와 디버깅
try-catch 문은 에러가 발생할 수도 있는 상황에 적합하며 브라우저가 에러를 처리하게 내버려두지 않고 적절히 처리할 수 있습니다.
window.onerror 이벤트 핸들러를 쓸스도 있습니다. 이 이벤트는 try-catch로 처리하지 않은 에러를 모두 받습니다.
심각한 에러인지 그렇지 않은지 판답합니다.
다음에는 코드를 검토하면서 에러가 일어날 만한 곳을 찾아봅니다. 자바스크립트 에러는 대개 다음 중 한 가지 이유로 발생합니다.
타입강제
불충분한 데이터 타입 체크
서버와 주고받는 데엍와 부정확한 경우
18. 자바스크립트와 XML
자바스크립트의 XML 관련 기술 지원은 꽤 높은 단계입니다. 유감스럽지만 명세가 일찍 제정되지 않은 탓에 한 가지 기능이 여러 가지로 구현되었습니다. DOM 레벨 2에는 빈 XML 문서를 만드는 API는 있지만 파싱하거나 직렬화하는 API는 없습니다. 필수적인 기능이 빠져 있으므로 브라우저 제조사들은 나름대로 구현할수 밖에 없었습니다. 인터넷 익스플로러는 다음과 같은 접근법을 택했습니다.
인터넷 익스플로러는 ActiveX 객체를 통해 XML 지원을 구현했는데, 이 객체는 데스크톱 애플리케이션에서도 쓰입니다.
MSXML 라이브러리는 윈도에 포함되어 있으며 자바스크립트에서도 접근할 수 있습니다.
MSXML 라이브러리에는 기본적인 XML 파싱과 직렬화 기능이 있고 XPath나 XSLT 같은 기술도 지원합니다.
반면 파이어폭스는 새로운 타입을 두 가지 도입하여 이를 통해 XML 파싱과 직렬화를 수행합니다.
DOMParser 타입은 XML문자열을 DOM 문서로 파싱하는 단순한 객체입니다
XMLSerializer 타입은 반대로 DOM 문서를 직렬화하여 XML 문자열을 만듭니다.
파이어폭스가 도입한 새 타입이 단순하고 인기 있었으므로 인터넷 익스플로러 9와 오페라, 크롬, 사파리에서도 이들 객체를 채택하여 사실상의 표준이 되었습니다.
19. XML을 위한 ECMAScript - deprecated
20. JSON
JSON은 복잡한 데이터 구조를 쉽게 표현하도록 디자인된 경량화된 데이터 형식입니다. 형식은 자바스크립트 문법의 부분집합을 이용하여 객체, 배열, 문자열, 숫자, 불리언, null을 표현합니다. XML로도 같은 일을 할 수 있지만 JSON이 더 간결하며 자바스크립트 지원도 더 좋습니다.
ECMAScript 5는 객체를 JSON형식으로 직렬화하고 JSON 데이터를 자바스크립트 객체로 파싱하는 네이티브 JSON 객체를 정의했습니다. 이러한 조작은 각각 JSON.stringify()와 JSON.parse() 메서드에서 이루어집니다. 각 메서드에는 기본 동작을 바꾸는 많은 옵션이 있어서 결과를 필터링하는 등의 조작이 가능합니다. 모든 브라우저가 네이티브 JSON 객체를 잘 지원합니다.
21. Ajax와 코멧
Ajax는 현재 페이지를 새로고침하지 않고도 서버에서 데이터를 받아오는 방법입니다. Ajax에는 다음과 같은 특징이 있습니다.
Ajax의 핵심은 객체 XMLHttpRequest(XHR) 객체입니다
이 객체는 서버에서 자바스크립트로 XML 데이터를 가져오기 위해 마이크로소프트에서 만들었고 인터넷 익스플로러 5에 처음 도입되었습니다.
파이어폭스, 사파리, 크롬, 오페라에서도 곧 이를 도입했고, W3C에서는 XHR의 동작을 정의하는 명세를 만들어 XHR을 웹 표준으로 받아들였습니다.
구현에 따라 조금씩 차이가 있지만 XHR 객체의 기본적인 사용법은 모든 브라우저에서 거의 비슷하므로 웹 애플리케이션에 사용해도 안전합니다.
XHR의 주요 제약은 도메인과 포트, 프로토콜이 모두 같은 서버 외에는 통신할 수 없게 하는 동일 소스 정책입니다. 안전성이 증명된 크로스 도메인 솔루션을 사용하지 않고 이 제한을 넘으려 하면 보안 에러가 발생합니다. 솔루션이란 소스 간 자원공유(CORS)이며 인터넷 익스프롤러 8 이상에서는 XDomainRequest 객체를 통해 다른 브라우저는 XHR 객체 자체에서 이를 구현했습니다. 이미지 핑과 JSON 역시 크로스 도메인 통신 테크닉에 속하지만 CORS 만큼 견고하지는 못합니다.
코멧은 서버에서 거의 실시간으로 클라이언트에 데이터를 보내게끔 한 Ajax 확장입니다. 코멧에서 주로 사용하는 방법은 HTTP 스트로밍과 롱 폴링입니다. 롱폴링은 모든 브라우저에서 지원하며 HTTP 스트리밍을 자체적으로 지원하는 브라우저는 아직 일부입니다. 서버 송신 이벤트(SSE)는 코멧의 HTTP 스트리밍과 롱 폴링을 모두 지원하는 브라우저 API입니다.
웹 소켓은 완전한 양방향 통신 채널입니다. 다른 솔루션과는 달리 웹 소켓은 HTTP 대신 작은 뎅터를 빠르게 전송하도록 디자인된 커스텀 프로토콜을 사용합니다. 이를 이용하려면 웹 서버를 변경해야 하지만 속도에 장점이 있습니다.
Ajax와 코멧은 개발자들이 자바스크립트에 열광하게 만들었고 웹 개발에 많은 영향을 끼쳤습니다. Ajax와 관련된 개념은 아직 새로운 것에 속하므로 계속 바뀔것이 확실합니다.
22. 고급 테그닉
자바스크립트 함수는 일급 객체이며 대단히 강력합니다. 클로져와 함수 컨텍스트 스위칭을 이용하면 함수를 매우 다양한 방법으로 활용 가능합니다. 이 장에서는 다음과 같은 활용법을 설명했습니다.
스코프 확인 생성자를 쓰면 new 연산자 없이 생성자를 사용해도 컨텍스트 객체를 잘못 적용하는 일이 없습니다.
함수를 처음 호출할 때 분기를 확정하는 지연 로딩을 쓸 수 있습니다.
함수 바인딩을 이용하면 함수가 항상 특정한 컨텍스트에서 동작하게 할 수 있고 함수 커링을 사용하면 함수 생성 시점에서 일부 매개변수를 미리 채워넣을 수 있습니다.
바인딩과 커링을 조합하면 함수를 어떤 컨텍스트에서도, 어떤 매개변수로도 실행가능합니다.
ECMAScript 5판에서는 쉽게 조작할 수 없는 객체를 여러 가지 제공합니다.
확장 불가능한 객체ㅔ는 새 프로퍼티나 메서드를 추가할 수 없습니다.
봉인된 객체는 확장 불가능하며 이미 존재하는 프로퍼티나 메서드를 삭제할 수 없습니다.
동결된 객체는 봉인된 동시에 객체 멤버를 덮어쓸 수 없습니다.
자바스크립트 타이머는 setTimeout()이나 setInterval()로 생성합니다.
타이머 코드는 지정한 인터벌에 도달할 떄까지 대기 영역에 있다가 인터벌에 도달하면 자바스크립트 프로세스 큐에 추가되어, 자바스크립트 프로세스가 한가해지면 바로 실행됩니다.
코드가 완전히 실행될 떄마다 약간의 갭이 있어서 다른 브라우저 프로세스가 실행됩니다.
타이머를 이용해서 오래 실행되는 스크립트를 작게 나누어 실행 사이에 캡을 둘 수 있습니다. 이렇게 하면 웹 애플리케이션의 반은성을 개선할 수 있습니다.
옵저버 패턴은 자바스크립트 이벤트 모델의 원형입니다. 이벤트는 보통 DOM과 함께 사용하지만 커스텀 이벤트를 만들어 쓸 수도 있습니다. 커스템 이벤트를 사용하면 코드의 각 부분을 분리 할 수 있으므로 관리하기 쉽고 코드를 수정하다가 다른 에러가 생기는 일도 작습니다.
드래그 앤 드롭은 데스크톱과 웹 애플리케이션 모두에서 인기 있는 인터페이스 패러다임이며 쉽고 직관적인 방식으로 요소를 재정렬하거나 설정하는 데 쓰입니다. 마우스 이벤트에 몇 가지 단순한 계싼을 추가하면 자바스크립트로도 이 기능을 구현할 수 있습니다. 드래그 앤 드롭 동작과 커스텀 이벤트를 조합하면 여러 가지로 재사용 가능한 프레임워크를 만들 수 있습니다.
23. 오프라인 애플리케이션과 클라이언트 사이드 스토리지
오프라인 웹 애플리케이션과 클라이언트 데이터 스토리지는 웹의 미래에서 중요한 부분을 차지할 겁니다. 최근의 브라우저는 사용자가 오프라인이 되었음을 감지하고 자바스크립트 이벤트를 일으키므로 애플리케이션에서 이에 맞게 반응할 수 있습니다. 애플리케이션 캐시는 어떤 파일을 오프라인에서도 쓸 수 있어야 하는지 지정합니다. 자바스크립트 API 통해 애플리캐이션 캐시의 현재 상태를 파악하고 어떻게 변할지도 알 수 있습니다.
이장에서는 다음과 같은 클라이언트 스토리지를 설명했습니다.
전통적으로 이런 종류의 스토리지는 쿠키 하나뿐이었습니다. 쿠키에는 정보를 조금밖에 저장할 수 없으며 요청을 보낼 때마다 함께 전송됩니다.
자바스크립트에서는 document.cookie를 통해 쿠키에 접근합니다.
쿠키에는 여러 가지 제한이 있어서 데이터를 조금만 저장할 때는 상관없지만 많이 저장하기엔 비효율적입니다.
인터넷 익스플로러에는 다음과 같이 페이지 요소에 적용하는 지속성 사용자 데이터라는 개념이 있습니다.
요소에 사용자 데이터를 적용하면 이름 붙은 데이터 저장소에서 데이터를 불러 올 수 있으며, 이 정보에는 getAttribute(), setAttribute(), remove Attribute() 메서드를 통해 접근 가능합니다.
세션이 끝나도 데이터를 유지하려면 반드시 save() 매서드를 이용해 이름 붙은 데이터 저장소에 명시적으로 저장해야 합니다.
웹 스토리지는 데이터를 저장할 객체로 sessionStorage와 localStorage 두 가지를 정의합니다. sessionStorage는 브라우저를 종료할 때 데이터를 제거하므로 브라우저 세션에서만 사용 가능합니다. localStorage는 세션이 끝나도 데이터를 유지하며 크로스 도메인 보안 정책을 적용합니다.
indexedDB는 SQL 데이터베이스와 비슷한 구조화된 데이터 스토리지 메커니즘입니다. indexedDB는 데이터를 테이블에 저장하지 않고 객체 저장소에 저장합니다. 객체 저장소를 생성할 때는 먼저 키를 정의한 후 데이터를 추가합니다. 커서를 이용해 객체 저장소에서 필요한 데이터만 쿼리할 수 있으며 인뎃를 생성하면 프로퍼티를 기준으로 빠르게 검색할 수 있습니다.
이들을 사용하면 자바스크립트에서도 상당한 데이터를 클라이언트 컴퓨터에 저장 가능합니다. 데이터 캐시는 함호화되지 않으므로 민감한 정보를 저장해서는 안됩니다.