'나홀로스터디/JS For Web Dev'에 해당되는 글 14건

클라이언트 감지

2014. 11. 20. 11:15 나홀로스터디/JS For Web Dev


9장 클라이언트 감지

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
9.1 기능 탐지 사용
9.2 브라우저 탐지의 역사
9.3 어떤 타입의 탐지를 사용할 것인가


클라이언트 탐지는 웹 개발에서 가장 논란이 많은 주제이지만 개발 전략에서 빼놓을 수 없는 중요 파트이다.



9.1 기능 탐지
클라이언트 탐지 중에서 가장 널리 쓰이는 방법은 '기능탐지'라는 방법인데 이것은 어떤 브라우저를 사용 중인지에는 관심이 없고 어떤 기능이 지원되는지에 주목한다. 기능 탐지에서 매우 중요한 두가지 개념이 있는데 같은 결과를 얻을 수 있는 가장 일반적인 방법을 제일 먼저 테스트해야 한다는 것이고, 두 번째로 중요한 개념은 사용하려는 기능을 정확히 테스트해야 한다는 것이다.


9.1.1 안전한 기능 탐지
기능 탐지는 단순히 원하는 기능이 존재하는지만이 아니라 그 기능이 정확히 동작함을 확힌할 수 있을 때 가장 효과적이다. 함수의 존재여부를 확인하기 위해 typeof 를 써야 하지만 일부 브라우저에서는 정확한 연산자를 반환하지 않을수 있으므로 브라우저와 객체를 가리지 않고 함수의 존재 여부를 확인하려면 isHostMethod() 함수를 써야한다.
// 피터 마이콕스가 개발
function isHostMethod(object, property){   var t = typeof object[property];   return t == 'function' ||     (!! (t == 'object' && object[property])) ||     t == 'unknown'; }
result = isHostMethod(xhr, "open"); // true result = isHostMethod(xhr, "foo"); // false

9.1.2 기능 탐지는 브라우저 탐지가 아니다
특정 기능이나 기능 집합을 탐지할 때 어떤 브라우저에서 실행 중인지 알 필요는 없다. 애플리케이션에서 특정 브라우저 기능이 필요하다면 기능 탐지를 반복하기보다는 몇가지 기능을 묶어서 브라우저 그룹을 만드는 방법이 적절하다.
※ 기능 탐지는 해결책을 찾지 못했을 때 쓰는 보험 같은 것이지, 어떤 브라우저에서 실행 중인지 알기 위함이 아니다.
 




9.2 쿽스 탐지
쿽스탐지는 브라우저의 특정 동작방식을 찾아내려는 것이다. 쿽스 탐지는 보통 짧은 코드를 실행하고 기능이 정확히 동작하는지 확인한다. 쿽스 탐지는 코드를 실행해야 하므로 직접적인 영향이 있는 버그만 테스트하고 가능한 스크립트 첫 부분에서 테스트해서 이를 배제하는 편이 좋다.
 



9.3 브라우저 탐지
브라우저 탐지는 사용자 에이전트 문자열을 통해 어떤 브라우저에서 실행중인지 확인한다. 사용자 에이전트 문자열은 HTTP 요청을 보낼 때마다 받는 응답 헤더에 포함되어 있으며 자바스크립트에서는 navigator.userAgent를 통해 접근한다. 서버에서는 사용자 에이전트 문자열을 보고 어떤 브라우저를 사용 중인지 확인하고 그에 맞게 반응하도록 프로그램 하는 일이 일반적이며 문제도 없지만 브라우저 탐지는 기능 탐지나 쿽스 탐지로 해결되지 않을때만 사용하는 수단으로 여겨진다.
사용자 에이전트 문자열에서 가장 심한 논란거리는 브라우저가 사용자 에이전트 문자열에 잘못된, 또는 착각을 유도하는 정보를 넣어서 서버를 속이는 소위 '위장'의 역사다


9.3.1 역사
명세는 추가적으로 사용자 에이전트 문자열을 토큰/제품 버전의 목록 형태로 만들길 요구하지만 현실에서 사용자 에이언트 문자열은 그리 단순하지 않다

초기 브라우저
첫번째 웹 브라우저인 모자이크는 1993년 NCSA(국립 슈퍼컴퓨터 애플리케이션 센터)에서 만들어졌다. 운영체제와 플랫폼에 따라 매우 다르긴 했지만 모자이크 사용자 에이전트 문자열은 매우 단순해서 다음과 같은 형태였다
Mosaic/0.9 
슬래시 앞에 있는 텍스트는 제품 이름(NCSA 모자이크 또는 변형)이고 뒤에 있는 텍스트는 제품 버전이다.
넷스케이프 커뮤니케이션즈에서 웹 브라우저 개발을 처음 시작했을 때 그 코드 네임은 모질라("모자이크 킬러")였다.
Mozilla/Version [Language] (Platform; Encryption) 
넷스케이프는 제품 이름과 버전을 사용자 에이전트 문자열 맨 앞에 두는 형식을 받아들였지만 언어, 플랫폼(운영체제), Encryption(암호화타입)을 추가했다.


넷스케이프 내비게이터3과 인터넷 익스플로러3
페이지를 인터넷 익스플로러에서 보면 브라우저를 판단할 수 없어서 페이지가 깨지곤 했으므로 마이크로소프트는 사용자 에이전트 문자열을 넷스케이프 사용자 에이전트 문자열과 호환되게 만들기로 결정했다.
Mozilla/2.0 (compatible; MSIE Version; Operating System) 

넷스케이프 커뮤니케이터4와 인터넷 익스플로러 4-8
사용자 에이전트 문자열을 업데이트하여 형식을 자주 바꾼 것은 과거에 사용하던 브라우저 탐지 스크립트와의 호환성을 유지하면서도 새 스크립트에는 다른 정보를 제공하기 위함이다.


게코
게코가 처음 개발되던 당시에는 이후 넷스케이프6이 된 범용 모질라 브라우저의 일부분이었다. 넷스케이프6을 위해 만들어진 명세에는 미래 버전에서 사용자 에이전트 문자열을 어떻게 만들어야 하는지 정의하는 내용이 들어있다.
Mozilla/MozillaVersion (Platform; Encryption; OS-or-CPU; Language;
  PrereleaseVersion) Gecko/GeckoVertion ApplicationProduct/ApplicationProductVersion 

웹킷
애플은 2003년 사파리라는 웹 브라우저를 발표했다. 사파리의 렌더링 엔진은 웹킷인데 웹킷은 리눅스 기반 웹 브라우저인 컨터러의 엔더링 엔진 KHTML에서 분기하면서 시작했고 몇 년이 지난 후 웹킷은 독자적인 오픈 소스 프로젝트가 되었고 렌더링 엔진 개발에 초점을 맞추었다.
사파리는 인기 브라우저와 호환된다고 판단할만한 정보를 사용자 에이전트 문자열에 제공하가 위해 사용자 에이전트 문자열 형식을 만들었고, 모든 웹킷 기반 브라우저는 게코 기반 브라우저와 마찬가지로 자신을 모질라 5.0이라 칭한다.


컨커러
KDE 리눅스 데스크톱 환경에 따라오는 컨커러 브라우저는 오픈 소스 렌더링 엔진인 KHTML을 렌더링 엔진으로 사용한다. 호환성을 위해 컨커러 사용자 에이전트 문자열 형식을 인터넷 익스플로러와 비슷하게 만들기로 정했다.
Mozilla/5.0 (compatible; Konqueror/Version; OS-or-CPU) 

크롬
구글의 크롬 웹 브라우저는 렌더링 엔진으로 웹킷을 사용하지만 자바스크립트 엔진은 독자적으로 개발했다. 크롬의 사용자 에이전트 문자열에는 웹킷이 들어가는 모든 정보와 함께 크롬 버전도 포함된다.


오페라
오페라의 기본 자용자 에이전트 문자열은 최신 브라우저 중에서는 가장 논리적이어서 이름과 버전을 정확히 표시한다.


IOS와 안드로이드
모바일 운영체제인 iOS와 안드로이드의 기본 웹 브라우저는 모두 웹킷이므로 데스크톱과 같은 기본 사용자 에이전트 문자열 형식을 공유한다.
 


9.3.2 브라우저 탐지 사용
사용자 에이전트 문자열을 가지고 특정 브라우저인지 판단하는 것은 대단히 복잡한 문제이다.

렌더링 엔진 식별
렌더링 엔진을 정확히 식별하려면 정확한 순서로 테스트해야 한다. 브라우저의 비일관성 때문에 테스트 순서가 틀리면 부정확한 결과를 얻게 된다.
첫 번째로 오페라인지 판단해야 하는데 오페라의 사용자 에이전트 문자열이 다른 브라우저와 완전히 똑같을 수 있기 때문이다. 오페라에서 실행 중인지 판단하려면 window.opera  객체가 있는지 확인해야 하는데 버전 7.6 이후에는 브라우저 버전 번호를 문자열로 반환하는 version() 메서드가 있다.
두 번재로 테스트할 렌더링 엔진은 KHTML이다. KHTML의 사용자 에이전트 문자열에도 "Gecko"가 들어 있으므로 웹킷과 KHTML 을 모두 배제한 뒤에 게코를 체크하면 안전하다. 케코 버전 번호는 "rv:"와 닫는 괄호()) 사이에 있으므로 버전 번호를 추출하는 정규 표현식은 닫는 괄호가 아닌 모든 문자를 캡처 해야한다.
마지막 렌더링 엔진은 인터넷 익스플로러이다. 버전 번호는 "MSIE"와 세미콜론 사이에 있으므로 이를 찾는 정규 표현식은 단순하다.


브라우저 확인
렌더링 엔진만으로 자바스크립트 기능에 대해 알 수 없을때가 있다. 애플의 사파리 브라우저와 구글의 크롬 브라우저는 모두 웹킷 렌더링 앤진을 쓰지만 자바스크립트 엔진은 서로 다르다. 오페라와 인터넷 익스플로러의 경우 browser 객체에 저장된 값은 engine 객체에 저장된 값과 같다.


플랫폼 감지
여러 플랫폼에서 동작하도록 만들어진 브라우저는 플랫폼별로 다른 문제가 있을 수 있다.
렌더링 엔진과는 달리 플랫폼 정보는 일반적으로 매우 제한적이며 운영체제나 버전 정보를 쉽게 얻기는 힘들다.


윈도 운영체제 식별
플랫폼이 윈도일 경우 사용자 에이전트 문자열에서 운영체제 정보를 더 얻을 수 있다. XP 이전의 윈도는 가정용과 비즈니스용 두 가지 버전이 있었는데 가정용 버전은 윈도라고 불렀고 버전은 95, 98, ME가 있다. 비즈니스 버전은 윈도 NT와 윈도2000이 있다. 윈도 XP는 두 버전을 윈도 NT에서 발전한 공통 코드로 통합했다. 윈도 비스타는 윈도 XP를 기반으로 만들어졌다.


모바일 장치 식별
주요 브라우저는 모두 모바일 버전이 있고 다른 장치에서 동작하는 버전도 있으므로 이를 구분할 수 있어야 한다. 모바일 장치 식별의 첫 단계는 모든 모바일 장치가 해당하는 프로퍼티를 추가하는 것이다.
iOS 장치 탐지는 문자열 "iPhone", "iPod", "iPad" 만 검색되므로 정규 표현식을 써서 사용자 에이전트 문자열에 iOS 버전이 들어 있는지 확인한다.
안드로이드 운영체제는 문자열 "안드로이드"를 검색하기만 하면 되고 버전 번호는 바로 뒤에 있다.
노키아 N 시리즈 스마트폰도 웹킷을 이용하고 사용자 에이전트 문자열에 "Safari"가 들어있긴 하지만 실제 사파리 브라우저는 아니다. 이 스마트폰은 사용자 에이전트 문자열 "NokiaN"만 체크해도 된다.
마지막 주요 모바일 장치 플랫폼은 포켓 PC와 스마트폰용 윈도 모바일(이전에는 윈도CE라고 불린)이다. 이 장치들은 윈도 플랫폼에 속하므로 윈도 운영체제와 비슷한 값을 반환한다.


게임 시스템 식별
Wii 브라우저는 오페라 커스텀 버전이므로 Wii는 단순히 문자열 "Wii"를 테스트 하는 것으로 충분하다.  플레이스테이션에서는 정규 표현식을 써서 사용자 에이전트 문자열을 테스트하되 대소문자를 가리지 않게 했다.
 


9.3.4 사용법
브라우저 탐지는 클라이언트 탐지에서 가장 마지막 옵션으로 생각해야 한다. 가능하다면 기능 탐지나 쿽스 탐지를 먼저 시도해야 하고 다음과 같은 상황에 사용하는것이 알맞다.
- 기능이나 쿽스를 직접 정확히 탐지할 수 없을때
- 같은 브라우저의 기능이 플랫폼별로 다를 때
- (사용자 통계 등의) 정보 수집 목적으로 정확히 어떤 브라우저인지 알아야 할때
 



9.4 요약
기능탐지 - 특정 브라우저 기능을 사용하기 전에 먼저 테스트하는 이 접근법에서는 개발자가 브라우저 타입이나 버전에 신경 쓰지 않고 단순히 원하는 기능이 존재하는지만 알면된다. 기능탐지로는 특정 브라우저나 버전을 정확히 알수 없다.

쿽스탐지 - 쿽스는 사실 브라우저 구현상의 버그인데 쿽스 탐지는 보통 짧은 코드를 실행해서 브라우저에 해당 버그가 있는지 확인하는 방식이다. 쿽스 탐지는 특정 버그가 스크립트 진행을 방해할 소지가 있을 때만 사용한다.

브라우저 탐지 -  사용자 에이전트 문자열을 통해 브라우저를 식별한다. 자용자 에이전트 문자열에는 브라우저에 관한 정보가 매우 많은데 브라우저, 플랫폼, 운영체제, 브라우저 버전 등이 이에 속한다. 브라우저 탐지는 어려운 작업이지만 사용자 에이전트 문자열을 통해 모바일장치나 게임 시스템을 포함한 모든 브라우저에서 렌더링 엔진과 플랫폼을 파악할 수 있다.

 
 
 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

DOM 확장  (0) 2014.12.18
DOM  (0) 2014.12.08
브라우저 객체모델  (0) 2014.11.12
함수 표현식  (0) 2014.10.23
참조타입  (0) 2014.10.17

브라우저 객체모델

2014. 11. 12. 11:30 나홀로스터디/JS For Web Dev


8장 브라우저 객체 모델

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
8.1 BOM의 핵심인 window 객체에 대한 이해
8.2 창과 프레임, 팝업 컨트롤
8.3 location 객체에서 얻는 페이지 정보
8.4 navigator 객체를 통한 브라우저 이해



8.1 window 객체
window 객체는 브라우저 창의 자바스크립트 인터페이스 구실을 하고 다른 한편으로는 ECMAScript Global 객체로 기능하며 window에 정의된 parseInt() 등의 메서드를 이용한다.


8.1.1 전역 스코프
window 객체가 ECMAScript의 Global 객체 구실을 하므로 전역에서 선언한 변수와 함수는 모두 window 객체의 프로퍼티 및 메서드가 된다.


8.1.2 창 사이의 관계와 프레임
페이지에 프레임이 들어있으면 각 프레임은 독자적인 window 객체를 가지며 이 객체들은 frames 컬렉션에 저장된다.
각 window 객체는 프레임의 name을 프로퍼티로 가진다.
top 객체는 항상 최상위(즉, 가장 바깥에 있는) 프레임을 가리키는데 이는 곧 브라우저 창이다.
window 객체 중에는 parent도 있는데 parent 객체는 항상 현재 프레임의 바로 상위인 부모 프레임이다.

최상위 window에는 name 프로퍼티 값이 존재하지 않는데 window.open() 메서드를 통해 창을 열었을 때는 예외다. self 객체는 항상 window를 가리키므로 window 객체는 self와 서로 바꿔서 써도 된다.

8.1.3 창의 위치
창의 위치를 가져오거나 설정하는 프로퍼티와 메서드도 다양한데 IE/Safari/Opera/Chrome은 모두 화면 왼쪽위에서 각각 얼마나 떨어졌는지를 나타내는 screenLeft/screenTop 프로퍼티를 지원한다.
FF는 이 기능을 screenX/screenY 프로퍼티로 지원하는데 Safari/Chrome도 이 프로퍼티를 지원한다.

var leftPos = (typeof window.screenLefr == "number") ? window.screenLeft : window.screenX;
var topPos = (typeof window.screenTop == "number") ? window.screenTop  window.screenY;

이 예제는 사용해도 브라우져마다 지원하는 위치값의 차이가 있기 때문에 일관적으로 구할 방법은 없다.
하지만 moveTo()/moveBy() 메서드로 정확한 위치로 옮기는 일은 가능하다. 각 메서드는 두개의 매개변수를 받는데 moveTo()는 이동할 x/y 좌표를 받고 moveBy()는 각 방향으로 몇 픽셀 이동할지 나타내는 숫자를 받는다.
브라우저에서 이 메서드를 금지할 가능성이 있다.


8.1.4 창 크기
창크기를 알아내는 방법은 IE9/FF/Safari/Opera/Chrome 모두 innerWidth, innerHeight, outerWidth, outerHeight 네가지 프로퍼티를 지원한다.
outerWidth, outerHeight 브라우저 창 크기를 반환하고  innerWidth, innerHeight 프로퍼티는 브라우저 창 내부의 페이지 뷰포트 크기를 나타낸다.
IE/FF/Safari/Opera/Chrome 에서 document.documentElement.clientWidthdocument.documentElement.clientHeight 프로퍼티는 각각 페이지 뷰포트의 너비와 높이를 나타낸다.

8.1.5 네비게이션과 열기
window.open() 메서드는 URL 로 이동한 후 브라우저 창을 새로 연다.
이 메서드는 이동할 URL, 대상 창, 기능을 나타내는 문자열, 새 페이지가 브라우저 히스토리에서 현재 페이지를 대체할지 나타내는 불리언 값 네가지 매개 변수를 받는데 일반적으로 세번째 매개변수까지만 사용하며 마지막 매개변수는 새 창을 열때는 적용되지 않는다.
window.open()의 두 번째 매개변수가 이미 존재하는 창이나 프레임 이름이라면 주어진 URL은 해당 이름의 창이나 프레임에서 열린다.

팝업창
두 번재 매개변수가 기존의 창/프레임 이름이 아니라면 세 번재 매개변수에 지정한 문자열로 새 창이나 탭을 생성하고 세번째 매개변수가 없다면 새 브라우져 창이 열리고 기본 브라우저 창 설정(툴바, 주소표시 줄, 상태 바 등)이 적용된다. 세 번째 매개변수는 새 창을 열 때에만 적용되고 새 창의 정보를 나타내는 쉼표로 구분된 문자열이다.

fullscreen = "yes" or "no" : 브라우저 창을 최대 크기로 생성할지 나타냄(IE전용)
height = 숫자 : 새창의 높이를 나타냄, 최소값은 100
left = 숫자 : 새 창의 x 좌표로 음수는 쓸수 없음
location = "yes" or "no" : 주소 표시줄을 표시할지 나타냄, 기본값은 브라우저에 따라 다름
menubar = "yes" or "no"  : 메뉴바를 표시할지 나타냄, 기본값은 "no"
resizable = "yes" or "no"  : 새 창의 테두리를 드래그해서 크기를 조절할수 있는지 나타냄, 기본값은 "no"
scrollbas = "yes" or "no"  : 새 창 컨텐츠가 뷰포트를 넘칠 때 스크롤을 허용할지 나타냄, 기본값은 "no"
status = "yes" or "no"  : 상태바를 표시할지 나타냄, 기본값은 브라우저에 따라 다름
toolbar = "yes" or "no"  : 툴바를 표시할지 나타냄, 기본값은 "no"
top = 숫자  : 새 창의 y 좌표, 음수는 쓸 수 없음
width = 숫자 : 새 창의 너비, 최소값은 100


이름- 값  쌍은 등호(=)로 구분하며 각 쌍은 공백을 포함할 수 없다.
window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");

팝업 차단
브라우저에 내장된 팝업 차단기가 동작했다면 window.open()은 대개 null을 반환한다.


8.1.6 인터벌과 타임아웃(setTimeout(), clearTimeout())
브라우저에서 자바스크립트는 단일 스레드로 실행되지만 타임아웃과 인터벌을 통해 코드가 특정 시간에 실행되게끔 조절할 수 있다.
타임아웃은 일정 시간 뒤에 코드를 실행하는 것이고, 인터벌은 일정 시간마다 코드를 반복 실행하는 것이다.
타임아웃은 window의 setTimeout() 메서드로 설정한다. 이 메서드는 매개 변수를 두 개 받는데 하나는 실행할 코드이고 하나는 코드를 실행할 때까지 기다리는 시간(밀리초)이다.
setTimeout()을 호출하면 해당 타임아웃의 숫자형 ID를 반환하고 대기중인 타임아웃을 취소하려면 다음 예제처럼 clearTimeout() 메서드에 타임아웃 ID를 넘긴다.

타임아웃으로 실행하는 코드는 항상 전역 스코프에서 실행되므로 함수의 this값은 스트릭트 모드가 아닐 때는 항상 window이고 스트릭트 모드에서는 항상 undefined이다.

인터벌은 타임아웃과 비슷하지만 페이지가 종료되거나 인터벌을 취소하기 전에는 일정한 시간마다 코드를 반복 실행한다는 점이 다르다. setInterval() 메서드로 인터벌을 설정하며 이 메서드는 setTimeout()과 같은 매개변수, 즉 실행할 코드(문자열 또는 함수)와 각 실행 사이에 대기할 시간을 밀리초로 받는다.
setInterval() 메서드 역시 인터벌 ID를 반환하며 clearInterval() 메서드는 이 ID를 매개변수로 받아 해당 인터벌을 취소한다. 인터벌을 취소하지 않으면 페이지가 떠 있는 동안 계속 실행되므로 인터벌 취소는 타임아웃 취소보다 중요하다.


8.1.7 시스템 대화상자
브라우저는 alert(), confirm(), prompt() 메서드를 통해 사용자에게 시스템 대화상자를 표시한다.
얼럿 대화상자는 일반적으로 에러처럼 사용자가 할수 있는 일이 없지만 반드시 알려야 할때 쓴다.
컨펌 대화상자는 확인과 취소버튼이 있어서 사용자가 선택할 수 있고, true 또는 false 불리언 값을 반환한다.
프롬프트 대화상자는 확인과 취소버튼 외에도 사용자가 데이터를 입력하는 텍스트 박스가 있다. prompt() 메서드는 매개변수를 두개 받는데 하나는 대화상자에 표시할 텍스트이며 하나는 텍스트 박스의 기본값(빈 문자열 가능)이다.

 

8.2 location 객체
location 객체는 현재 창에 불러온 문서 정보와 함께 일반적인 네비게이션 기능을 제공한다. location 객체는 window 의 프로퍼티인 동시에 document의 프로퍼티다. location은 현재 문서에 대한 정보를 갖고 있으며 URL 을 파싱해서 몇가지 조각으로 분리해 각각을 프로퍼티로 저장한다.


8.2.1 쿼리스트링 확장
URL 정보중 쿼리스트링은 다루기 쉬운 형태로 제공되지는 않으므로 쿼리스트링을 파싱해서 각 매개변수를 프로퍼티로 갖는 객체를 반환한다.


8.1.2 location 조작
다양한 방법으로 location 객체를 조작해서 페이지를 이동할 수 있다. 가장 많이 쓰이는 것은 assign() 메서드다.

location.assign("http://www.wrox.com"); 


이렇게하면 즉시 새 URL로 이동하며 브라우저의 히스토리 스택에 기록이 추가되는데 lacation.href이나 window.lacation에 URL을 지정하면 그 값으로 assign() 메서드를 호출한다.  헤이지를 이동하는 이 세가지 방법중에서 lacation.href을 설정하는 방법이 가장 자주 쓰인다.
location 객체의 프로퍼티를 변경하면 현재 페이지에도 영향이 있다. hash, search, hostname, port 프로퍼티를 변경하면 현재 URL에 새 값이 반영되며 새 URL로 페이지를 다시 읽는데 hash 프로퍼티를 바꿀 때는 예외이다.

 location.hash ="#section1";
 location.search = "?q=javascript";
 location.hostname = "www.yahoo.com";
 location.patname = "mydir"; 

이와 같은 방법으로 URL을 수정하면 브라우저의 히스토리 스택에 기록이 남아 사용자가 뒤로가기 버튼을 클릭해 이전 페이지로 돌아갈 수 있다. replace() 메서드를 쓰면 매개변수로 URL을 받아 이동하지만 히스토리 스택에 기록을 남기지 않기 때문에 뒤로가기 버튼을 클릭해 이전 페이지로 돌아갈 수 없다.

현재 위치를 다시 불러오는 reload() 메서드는 매개변수 없이 호출하면 페이지를 가능한 한 가장 효과적인 방법으로 다시 읽는다. 마지막 요청이후 페이지가 바뀌지 않았다면 브라우저 캐시에서 읽어오는데 서버에서 읽어오도록 강제하려면 true를 매개변수로 넘긴다.

location.reload(); // 가능하면 캐시에서
location.reload(true); // 항상 서버에서 

reload() 호출 이후에 있는 코드는 네트워크 지연이나 시스템 자원 같은 요인의 영향으로 코드 마지막에 두는 것이 최선이다.

 


8.3 navigator 객체
navigator 객체의 프로퍼티는 일반적으로 웹 페이지를 실행중인 브라우저 타입을 판단하는데 사용한다.
브라우저에 따라 navigator 객체에서 지원하는 프로퍼티가 다르다.


8.3.1 플러그인 감지
스크립트로 가장 많이 탐지하는 것 중 하나는 브라우저에 특정 플러그인이 설치되어 있는지이다. IE 이외의 브라우저에서는 plugins 배열에서 이 정보를 얻을수 있다.

name - 플러그인 이름
description - 플러그인 설명
filename - 플러그인 파일 이름
length - 플러그인이 처리하는 마임 타입 숫자

일반적으로 name만 있으면 플러그인을 식별하기 충분하지만 항상 그렇지는 않다.


각 plugin 객체는 MineType 객체의 배열이기도 하며 대괄호 표기법으로 접근 가능하다. 각 Mime Type 객체에는 프로퍼티가 네개 있는데 마임 타입 설명인 description, plugin, 객체를 가리키는 포인터인 enablePlugin, 마임 타입의 파일 확장자를 쉼표로 구분한 문자열인 suffixes, 마지막으로 완전한 마임 타입 문자열인 type이다.


IE는 넷스케이프 스타일 객체를 지원하지 않으므로 플러그인 탐지가 어렵다. IE는 플러그인을 COM 객체로 구현했고 이들을 고유한 문자로 식별하기 때문에 hasIEPlugin() 함수로 IE 전용타입인 ActiveXObject를 사용해서 플러그인을 인스턴스화 하는 방법으로 플러그인 설치여부를 판단하는 함수를 만들수 있다.

plugins 컬렉션에는 refresh() 라는 메서드가 있는데 이 메서드는 새로 설치된 플러그인이 반영되도록 plusgins을 갱신한다. 이 메서드는 매개변수로 페이지를 새로고침해야 하는지 나타내는 불리언 값을 받는다.





8.3.2 처리기 등록
FF2는 navigator 객체에 registerContentHangler()와  regitorProtocalHandler() 메서드를 도입했다.
이 메서드는 웹사이트가 특정한 타입의 정보를 처리할 수 있음을 나타낸다.
registerContentHangler() 메서드는 처리할 마임타입, 해당 마임 타입을 처리할 페이지 URL, 애플리케이션 이름 세가지 매개변수를 받는다.
regitorProtocalHandler()은 처리할 프로토콜("mailto", "ftp" 등), 프로토콜을 처리할 페이지 URL, 애플리케이션 이름을 매개변수로 받는다. 




8.4 screen 객체
screen 객체 역시 window의 프로퍼티인데 이 객체에는 픽셀 너비와 높이 등 클라이언트 화면에 관한 정보가 들어있고 브라우저별로 screen 객체에서 지원하는 프로퍼티가 다르다.




8.5 historty 객체
history 객체는 창을 첫 번째 연 이후 사용자의 네비게이션 히스토리를 보관한다.
history는 window의 프로퍼티이므로 브라우저 창, 탭, 프레임은 각각 자신의 window 객체에 속한 history 객체를 가진다.

go() 메서드는 사용자의 이동 히스토리에서 앞으로 또는 뒤로 이동한다. 이 메서드는  매개변수로 이동할 페이지 수를 나타내는 하나의 정수를 받는데,음수를 받으면 히스토리에서 뒤로 이동하고 양수를 받으면 앞으로 이동한다.
매개변수로 문자열을 받는 경우 브라우저는 히스토리에서 해당 문자열을 포함한 첫 번째 위치로 이동한다.
go() 메서드 대신 단축 메서드인 back()forward() 메서드를 쓸수 있다.

history 객체의 length  프로퍼티는 history 스택에 기록이 얼마나 많이 있는지 나타낸다.

페이지의 URL이 바뀔 때마다 히스토리 스택에 새 기록이 추가된다. IE8 이상, Opera FF Safari3 이상, 크롬에서는  이 기록에 URL 해시가 포함되며 따라서 이들 브라우저에서 location.hash를 설정하면 히스토리 스택에 새 기록이 추가된다




 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

DOM  (0) 2014.12.08
클라이언트 감지  (0) 2014.11.20
함수 표현식  (0) 2014.10.23
참조타입  (0) 2014.10.17
객체에 대한 이해  (0) 2014.10.15

함수 표현식

2014. 10. 23. 09:55 나홀로스터디/JS For Web Dev


7장 함수 표현식

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
함수 표현식의 특징
함수와 재귀
클로저를 이용한 고유 변수


함수를 정의하는 방법은 함수 선언함수 표현식 두 가지다.

첫 번째 방법인 함수 선언은 function 키워드에 함수 이름을 쓰는 형태로 파이어폭스, 사파리, 크롬, 오페라는 모든 함수에 프로퍼티인 name을 지원하므로 이 값은 function 키워드 다음에 쓴 함수의 이름과 항상 일치한다.
function functionName(arg0, arg1, arg2){
  // 함수 본문
}
alert(functionName.name);  // "functionName"
함수 선언에서 가장 뚜렷한 특징은 '함수 선언 끌어올림(함수 선언부를 다른 코드보다 먼저 읽고 실행한다)'이다.


함수를 정의하는 두 번째 방법은 함수 표현식이다.
var functionName = function(arg0. arg1. arg2){
  // function body
}
함수를 생성하고 이를 functionName 이란 변수에 할당하도록 생성된 함수는 function 키워드 다음에 함수 이름이 없으므로 익명 함수로 간주한다. 따라서 함수의 name프로퍼티는 빈 문자열이다. 그러므로 함수 표현식은 반드시 호출하기 전에 할당해야한다.
 



7.1 재귀
'재귀 함수'는 함수가 자기 자신을 이름으로 호출하는 형태이다.
function factorial(num){
  if(num <= 1){
    return 1;
  }else{
    return num * arguments.callee(num-1);
    // return num * factoriial(num-1);
  }
}
arguments.calee는 현재 실행중인 함수를 가리키는 포인터이므로 재귀 함수를 사용할 때는 함수 이름 대신 arguments,callee를 권장한다.
 



7.2 클로저
'익명함수'와 '클로저'는 자주 잘못 혼용되지만 '클로저'란 다른 함수의 스코프에 있는 변수에 접근 가능한 함수이다.
클로저를 이해하기 위해서는 스코프 체인이 어떻게 생성되고 사용되는지 알아야 한다. 함수를 호출하면 실행 컨텍스트와 스코프 체인이 생성되고 함수의 활성화 객체는 arguments 및 이름 붙은 매개변수로 초기화 된다.
외부 함수의 활성화 객체는 스코프 체인의 두 번째 객체이고 이 과정이 포함 관계에 있는 함수에서 계속 생성하여 스코프 체인이 전역 실행 컨텍스트에서 종료될 때까지 이어진다.
함수를 실행하면 값을 읽거나  쓸 변수를 스코프 체인에서 검색한다.
스코프 체인이란 변수 객체를 가리키는 포인터 목록이며 객체를 직접 포함하는 것은 아니다.
클로저는 외부 함수의 스코프를 보관해야 하므로 다른 함수에 비해 메모리를 많이 요구한다. 클로저를 사용하면 메모리 문제가 생길 수 있으니 반드시 필요할 때만 사용하길 원한다. 크롬 v8처럼 자바스크립트 코드를 최적화하는 엔진은 클로저 때문에 반환 불가능해진 메모리를 회수하려 시도하기도 하지만 클로저를 쓸 때는 조심하는 편이 상책이다.
 
7.2.1 클로저와 변수
스코프 체인에는 한 가지 눈에 띄는 부작용이 있는데 항상 외부함수의 변수에 마지막으로 저장된 값만 알 수 있다는 점이다.
클로저가 특정 변수가 아니라 전체 변수 객체에 대한 참조를 저장한다는 것을 기억하라.

7.2.2 this 객체
this 객체는 런타임에서 함수가 실행 중인 컨텍스트에 묶인다. 즉 전역함수에서 this는 스트릭트 모드가 아닐 때는 window, 스트릭트 모드에서는 undefined 이며 함수가 객체 메서드로 호출되었을 때 this 는 해당 객체이다.
모든 함수는 호출되는 순간 자동으로 thisarguments 두 특별한 변수를 갖게 되는데 내부 함수는 결코 외부함수의 this, arguments에 직접적으로 접근할 수 없다.  외부 스코프의 매개변수 객체에 접근해야 한다면 클로저에서 접근할 수 있도록 이에 대한 참조를 다른 변수에 저장해야 한다.

7.2.3 메모리 누수
클로저는 인터넷 익스플로러 9 이전 버전에서 메모리 문제를 일으키는데 이는 JScript 객체와 COM 객체에 사용하는 가비지 컬렉션 방법이 다르기 때문이다.
 



7.3 블록 스코프 흉내내기
자바스크립트에는 블록 레벨 스코프라는 개념이 없으므로 블록 문장에서 정의한 변수는 해당 문장이 아니라 외부 함수에 묶여서 그 시점수터 함수 내에서 접근 할수 있게 된다. 이것은 익명 함수를 블록 스코프처럼 쓰는 문법(고유 스코프)으로 해결할 수 있다.
(function(){
  // 코드블록
})();
이 문법에서는 익명 함수를 정의하는 즉시 호출한다. 이를 '즉시 호출 함수'라고 부르기도 한다.
 


 
7.4 고유 변수
함수 안에서 정의한 변수는 함수 밖에서 접근할 수 없으므로 모두 고유 변수라고 간주한다. 함수 내부에서는 고유 변수에 접근 할 수 있지만 함수 밖에서는 불가능하다. 클로저를 이 함수 안에서 만들면 스코프 체인을 통해 이들 변수에 접근할 수 있다.
특권 메서드는 고유 변수.함수에 접근 가능한 공용 메서드로 만드는 방법은 두 가지가 있다.


7.4.1 정적 고유 변수
특권 메서드는 고유 변수나 함수를 정의할 때 쓰는 고유 스코프를 통해서 생성할 수도 있다.

7.4.2 모듈 패턴
모듈 패턴은 객체를 반환하는 익명 함수를 사용한다.
모듈 패턴은 단 하나의 객체를 반드시 생성하고 몇 가지 데이터를 가지며 또한 고유 데이터에 접근 가능한 공용 메서드를 외부에 노출하도록 초기화 해야 할 때 유용하다.

7.4.3 모듈 확장 패턴
객체를 반환하기 전에 확장하는 확장 패턴은 싱글톤 객체가 특정 타입의 인스턴스지만 프로퍼티나 메서드를 추가하여 확장해야 할 때 유용하다.
 
 

 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

클라이언트 감지  (0) 2014.11.20
브라우저 객체모델  (0) 2014.11.12
참조타입  (0) 2014.10.17
객체에 대한 이해  (0) 2014.10.15
변수와 스코프, 메모리  (0) 2014.10.07

참조타입

2014. 10. 17. 17:29 나홀로스터디/JS For Web Dev


5장 참조타입

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
객체로 작업하기
배열 생성하고 조작하기
자바스크립트의 데이터 타입 이해
원시 데이터 및 원시 래퍼로 작업하기


참조 값(객체)이란 특정 '참조타입'의 인스턴스이다.
참조타입은 데이터와 기능을 묶는 구조로 객체가 가져야 할 프로퍼티와 메서드를 정의한다는 점때문에 '객체정의'라고 불리기도 한다.

생성자는 객체를 생성하는 함수로 객체를 생성할 때는 new 연산자 뒤에 '생성자'를 쓴다.

var person = new Object();


이 코드는 참조타입 Object 의 인스턴스를 생성해서 변수 person에 할당한다.
생성자는 Object()이며, 기본 프로퍼티와 메서드만 가진 단순한 객체를 생성했다.




5.1 Object 타입
참조-값 형태의 Object 타입은 Object의 인스턴스에 많은 기능이 들어있지는 않지만 애플리케이션에 사용할 데이터를 저장하고 전송하는 목적에 안성맞춤이다.

Object 의 인스턴스를 명시적으로 생성하는 방법은 두가지가 있는데 첫번째는 new 연산자와 Object 생성자를 함께 쓰는 방법이고

var person = new Object();

person.name = "Nicholas";
person.age = 38;

다른 방법은 '객체 리터럴' 표기법이다.

ver person = {
  name: "Nicholas",
  age: 28
}

객체 리터럴 표기법을 쓸때 중괄호 안쪽을 빈 공간으로 남겨두면 생정자를 썼을때와 마찬가지로 기본 프로퍼티만 가진 객체를 만들수 있다.

var person = {}; // new Object()와 동일

객체리터럴 표기법을 사용해 객체를 생성할 때는 Object 생성자를 호출하지 않는다.
Object 의 인스턴스는 둘 중 어떤 방법으로 만들어도 상관없지만 객체 리터럴 표기를 쓰면 양이 줄어들고 옵션 매개변수를 여러개 넘길때 많이 사용한다.

객체 프로퍼티는 다른 객체 지향 언어와 마찬가지로 '점 표기법'을 써서 접근하지만 '대괄호 표기법'을 쓸수도 있다.

console.log(person["name"]);
console.log(person.name);

두방법의 차이는 없지만 대괄호 표기법의 장점은 변수를 써서 프로퍼티에 접근할 수 있다는 점이다.

var propertyName = "name";
console.log(person[propertyName]);

프로퍼티 이름에 공백이 있거나 알파벳이나 숫자가 아닌 문자를 써야하는 경우 점 표기법으로는 접근할수 없으므로 대괄호 표기법이 필요하다.

 

5.2 Array 타입
데이터의 순서 있는 목록이라는 점은 다른 언어의 배열과 마찬가지지만 ECMAScript 의 배열 슬롯에는 어떤 타입의 데이터라도 넣을수 있다.

배열은 두가지 방법으로 만드는데 첫번째는 Array 생성자를 쓰는 방법이고 배열에 데이터가 몇개 들어갈지 알고 있다면 생성자에 매개변수를 넘겨서 length 프로퍼티가 자동으로 그 값에 맞게 바뀌게 하면 된다. Array 생성자를 쓸때 new 연산자는 생략이 가능하다.

var color = new Array();
var color = new Array(20); // 데이터가 20개 있는 배열 생성
var color = new Array("red", "blue", "green"); // 문자열이 3개 있는 배열 생성

배열을 생성하는 두번째 방법은 '배열 리터럴' 표기법으로 대괄호 안에 데이터를 쉼표로 구분해 쓰는 방법이다.

var color = ["red", "blue", "green"];  // 문자열이 3개 있는 배열 생성 var name = []; // 빈배열 생성

console.log(color[0]); // 첫번째 데이터 표시 color[2] = "block" // 세번째 데이터 값 변경

배열값에 접근하려면 대괄호 안에 인덱스를 넣으면 된다.
length 프로퍼티는 배열에 저장된 데이터의 개수인데 항상 0 이상의 값을 반환하고 length 프로퍼티의 값을 바꾸면 배열 길이가 그에 맞게 바뀌면서 데이터를 제거하거나 빈 슬롯을 추가한다.
length 프로퍼티는 배열 마지막에 데이터를 추가할때도 유용하게 사용된다.

color[color.length] = "black" // 마지막 슬롯 인덱스 다음에 데이터 추가




5.2.1 배열감지
객체와 배열을 구분하기 쉽지 않은데 전역 스코프가 하나뿐인 단순한 웹 페이지에서는 instanceof 연산자를 쓴다. 하지만 instanceof 연산자는 실행 컨텍스트가 하나뿐이라고 가정하는 문제가 있다.

if(value instanceof Array){
  // 배열일때 실행하는 코드
} 

ECMAScript 5에서는 이 문제를 우회하기 위해 Array.isArray() 메서드를 제공하고 IE9이상, FF4이상, Safari5이상,Opera10.5 이상, Chrome 에서 지원한다.

if(Array.isArray(value)){   // 배열일때 실행하는 코드 }




5.2.2 변환 메서드
객체에는 모두 toLocaleString(), toString(), valueOf() 메서드가 있다.
배열의 각 슬롯을 쉼표로 구분한 문자열을 반환하는데 배열에서 toString()과 valueOf()는 같은 값을 반환한다.
join() 메서드를 통해 구분자가 될 문자열을 입력할수 있다.

alert(배열이름)는 매개변수로 문자열을 받으므로 먼저 배열에서 toString() 을 호출하고 따라서 toString()을 명시적으로 호출한것과 같은 결과가 나타난다.

배열에서 join(), toLocaleString(), toString(),valueOf() 메서드를 호출했을 떄 null이나 undefined 인 데이터는 빈 문자열로 표시된다.

 

5.2.3 스택 메서드
배열객체는 데이터 삽입과 제거에 제한이 있는 데이터 구조인 스택(LIFO last-in-first-out)처럼 동작할수 있다.
스텍에서 데이터 삽입(push)와 제거(pop)는 단 한지점에서만 발생하는데 ECMAScript 배열에는 push() 와 pop() 메서드가 있어서 마치 스택처럼 마지막에 추가된 데이터가 삭제되고 추가된다.

push() 메서드는 받은 매개변수 그대로 배열에 추가한 후 이에 맞게 늘어난 배열 길이를 반환한다.
pop() 메서드는 배열의 마지막 데이터를 제거하고 length 프로퍼티를 그에 맞게 줄여서 반환한다.

 

5.2.4 큐 메서드
큐는 목록 마지막에 데이터를 추가하며 목록 맨 앞에서 데이터를 꺼낸다.
push()메서드는 배열 마지막에 데이터를 추가하므로 shift()를 사용하면 큐처럼 동작할수 있게 된다.
unshift() 와 pop() 을 조합하면 큐의 반대 배열 처음에 데이터를 추가하고 앞에서 꺼내는 방식으로 쓸수 있다.

 

5.2.5 정렬 메서드
배열 순서를 직접 조작하는 메서드는 reverse()sort() 두가지인데 이름에서 예상하듯 reverse() 메서드는 단순히 배열에 저장된 데이터 순서를 뒤집을때 사용하나 유연성은 없다.
배열의 데이터 순서를 마음대로 조작하기 위해서는 sort() 메서드가 필요한데 sort() 메서드는 가장 작은 값이 앞에오고 가장 큰 값이 뒤에 오도록 정렬한다.
이를 위해 이면에서  String() 함수를 호출해 데이터를 문자열로 변환한 후 정렬하고 비교함수를 넘겨서 순서를 조절할 수 있다.

reverse() 와 sort() 는 모두 자신을 호출한 배열에 대한 참조를 반환한다.

 

5.2.6 조작 메서드
concat() 메서드는 현재 배열 데이터를 기반으로 새로운 배열을 만드는 것으로 현재 배열을 복사한 다음 메서드의 매개변수를 새 배열 마지막에 추가해서 반환한다.배개변수를 넘기지 않으면 현재 배열의 복사본을 반환한다.

slice() 메서드는 배열에 포함된 데이터 일부를 가진 새 배열을 만든다.
slice() 메서드는 매개변수를 두개 받는데 각 매개변수는 원래 배열에서 가져올 데이터 범위의 시작과 끝을 나타내어 첫번째 매개변수에 해당하는 인덱스부터 두번째 매개변수에 해당하는 인덱스 바로 앞까지 가져오고, 매개변수를 하나만 넘기면 해당 인덱스에서 끝까지 모든 데이터를 가져온다.

slice() 에 배개변수로 음수를 넘기면 배열길이 해당값을 더한 숫자를 사용하고 두번째 매개변수가 첫번재 매개변수보다 작으면 빈 배열을 반환한다.

splice() 메서드는 배열 중간에 데이터를 삽입하는 것인데 세가지 방법으로 사용한다.


splice() 메서드는 항상 원래 배열에서 삭제한 데이터의 배열을 반환하는데 삭제한 것이 없다면 빈 배열을 반환한다.

 

5.2.7 위치 메서드
ECMAScript 5 에서는 배열에 indexOf()와 lastIndexOf() 두 위치 메서드가 추가되었다.
이들 메서드는 매개변수를 두개 받는데 첫번째는 검색할 데이터이며 두번째는 검색을 시작할 인덱스이다.
indexOf()메서드는 배열의 처음부터 마지막까지 검색하고, lastIndexOf()메서드는 배열의 마지막에서 처음까지 검색한다.

데이터 검색은 === 연산자로 비교하고 두 메서드는 찾아낸 데이터의 인덱스를 반환하는데 찾지 못한 경우 -1을 반환한다.

 

5.2.8 반복 메서드
이들 메서드는 모두 매개변수를 두 개 받는데 하나는 배열의 각 데이터에서 실행할 함수이며 하나는 함수를 실행할 스코프 객체이다.

every() -  배열의 모든 데이터에서 콜백 함수를 호출하고 반환값이 전부 ture면 true를 반환한다.
filter() - 배열의 모든 데이터에서 콜백함수를 호출하고 반환값이 true인 데이터를 새 배열에 저장하여 반환한다.
forEach() - 배열의 모든 데이터에서 콜백함수를 호출한다 .반환값이 없다
map() - 배열의 모든 데이터에서 콜백함수를 호출하고 그 결과를 새 배열에 저장하여 반환한다
some() - 배열의 모든 데이터에서 콜백함수를 호출하고 반환 중 하나라도 true면 true를 반환한다.

 

5.2.9 감소 메서드
reduce() 메서드는 배열의 첫 번재 데이터에서 시작해 마지막까지 진행하고 reduceRight()는 반대로 마지막 데이터에서 시작해 첫 번째까지 진행한다. 두 메서드 모두 두개의 매개변수를 받는데 첫번째 매개변수는 각 데이터에서 실행할 콜백 함수고 두번째 매개변수는 감소 작업을 시작할 초기 값이다.
reduce()와 reduceRight() 의 콜백 함수가 넘겨받는 매개변수는 이전 값, 현재 값, 현재 값의 인덱스, 현재 배열 네가지다.

 

 

5.3 Date 타입
Date 타입은 날짜와 시간을 저장할 때 1970년 1월 1일 자정부터 몇 밀리초가 지났는지 나타내는 숫자를 사용하고 날짜 객체를 생성할 때는 new 연산자 다음에 Date 생성자를 쓴다.

var now = new Date(); 

Date() 생성자에 매개변수를 넘기지 않으면 생성된 객체는 현재 날짜와 시간이 저장된다.
Date.parse() 메서드는 매개변수로 날짜를 표현하는 문자열을 받고 해당 문자열을 날짜의 밀리초 표현으로 변환을 시도한다.

Date.UTC()의 매개변수는 해당 시각의 년, 월 인덱스(0이 1월), 일(1~31), 시(0~23), 분, 초, 밀리초이다.


5.3.1 상속된 메서드
Date 타입도 toLocaleString(), toString(), valueOf() 메서드를 오버라이드 하지만 Date 타입의 toLocaleString() 메서드와 toString() 메서드는 디버그 목적으로 사용하고 valueOf() 메서드는 밀리초 단위로 비교가 가능하다.


5.3.2 날짜 표시 메서드
Date 타입에는 날짜를 특정 형식으로 표현하는 메서드가 있다.

toDateString() - 날짜를 요일, 월, 일, 년 형식으로 표현하고 정확한 형식은 브라우저를 따른다.
toTimeString() - 날짜를 시, 분, 초, 타임존 형식으로 표현하고 정확한 형식은 브라우저를 따른다.
toLocaleDateString() - 날짜를 요일, 월, 일, 년 형식으로 표현하고 정확한 형식은 브라우저를 따른다.
toLocaleTimeSting() - 날짜를 시, 분, 초 타임존 형식으로 표현하고 정확한 형식은 브라우저를 따른다.
toUTCString() - 날짜를 UTC(협정 세계시) 형식으로 표현하고 정확한 형식은 브라우저를 따른다.


5.3.3 날짜/시간 부속 메서드
날짜의 특정 부분을 가져오거나 설정하는데 쓰인다.

 


5.4 RegExp 타입

var expression = /pattern/flags;

패턴 부분에 정규표현식을 나타내는 식을 쓰며, 문자 클래스, 수량자, 그룹, 룩어헤드, 역참조 등이 포함된다.
플래그를 통해 어떻게 동작할지 나타내며 세가지가 있다.

g - 전역모드를 지정한다. 문자열에서 패턴을 찾는 즉시 종료하지 않고 문자열 전체에서 동작한다.
i - 대소문자 비구분 모드를 지정한다. 패턴을 찾을때 대소문자를 구분하지 않는다.
m - 여러줄 모드를 지정한다. 텍스트의 줄 끝에 도달해도 멈추지 않고 계속 패턴을 찾는다.

메타문자를 패턴에 쓸 때는 반드시 역슬래시를 써서 이스케이프 해야한다.

( [ { \ ^ $ | } ] ) ? * + .



5.4.1 정규 표현식 인스턴스 프로퍼티

RegExp 인스턴스에는 다음 프로퍼티가 있으며 각 프로퍼티는 패턴에 대한 정보를 포함한다.

global - g 플래그 설정 여부 불리언 값.
ignoreCase - i 플래그 설정 여부 불리언 값.
lastIndex - 패턴 매칭의 시작 위치를 나타내는 정수 값이며, 항상 0에서 시작한다.
multiline - m 플래그 설정 여부 불리언 값.
source - 정규 표현식을 생성한 문자열. 항상 리터럴 형식으로 반환하되 여닫는 /문자는 포함되지 않는다. 생성자를 통해 생성되었더라도 리터럴 형식으로 반환한다.



5.4.2 정규 표현식 인스턴스 메서드
가장 많이 쓰는 메서드는 그룹을 캡처할 의도로 만들어진 exec() 메서드로 패턴을 테스트할 문자열을 매개변수로 받고 패턴에 일치하는 문자열 배열을 반환하며 일치하는 부분을 찾을 수 없을 때는 null 을 반환한다.
exec() 메서드가 반환하는 배열은 Array의 인스턴스인 동시에 프로퍼티 두개 추가되는데 index 프로퍼티는 패턴이 일치한 위치를 나타내고 input 프로퍼티는 exec() 메서드에 넘긴 문자열이다.

정규 표현식의 또다른 메서드는 test() 인데, 문자열이 패턴에 일치하는 지만 확인하여 일치할 때는 true를 반환하고 그렇지 않을 때는 false를 반환한다.

객체 프로토타입에서 상속한 메서드 toLocaleString() 과 toString()은 리터럴 형식을 반환한다. valueOf() 메서드는 정규 표현식 자체를 반환한다.



5.4.3 RegExp 생성자 프로퍼티
정식이름과 짧은 이름이 있는데 오페라는 짧은 이름을 지원하지 않는다.
짧은 이름은 반드시 대괄호 표기법을 써야한다.


5.4.4 패턴의 한계
ECMAScript의 정규 표현식은 완전히 개발된 상태이지만 펄 같은 언어에서 가능한 고급 정규 표현식 기능에는 미치지 못한다.

 



5.5 Function 타입
모든 함수는 Function 타입의 인스턴스이며 다른 참조 타입과 마찬가지로 프로퍼티와 메서드가 있고 함수 이름은 단순히 함수 객체를 가리키는 포인터가 된다.

보통 함수선언 문법을 통해 정의된다.

function sum (num1, num2){
  return num1 + num2;
}

변수를 정의하면서 함수를 초기화 하는 방법은 함수 이름은 필요하지 않다.(함수 표현식)

var sum = function(num1, num2){
  return num1 + num2;
}; 
 

함수를 정의하는 마지막 방법은 Funtion 생성자를 이용하는 방법으로 매개변수 숫자에는 제한이 없고 마지막 매개변수는 함수 바디로 간주한다.

var sum = new Function("num1", "num2", "return num1 + num2") // 권장하지 않음.



5.5.1 오버로딩 없음
함수 이름이 단순한 포인터임을 이해하면 ECMAScript에서 함수 오버로딩이 불가능한 이유도 이해할 수 있다.


5.5.2 함수 선언 vs 함수 표현식
함수 선언은 실행전에 모든 실행 컨텍스트에서 접근하고 실행할수 있지만 함수 표현식은 코드 실행이 해당 줄까지 진행하기 전에는 사용할 수 없다.

함수 표현식을 쓰면서도 함수 선언처럼 보이게, 즉 var sum = function sum() {}처럼 쓸 수 있다.


5.5.3 값처럼 쓰는 함수
함수이름은 변수일 뿐이므로 함수를 다른 함수에 매개변수로 넘기거나 함수 실행 결과로 다른 함수를 반환하는 일이 가능하다.


5.5.4 함수의 내부구조
함수 내부에는 arguments, this라는 특별한 객체가 있다.
argument 객체는 전달된 매개변수를 모두 포함하는 배열과 비슷한 객체이며 주요 목적은 함수 매개변수를 표현하는 것이지만 arguments 객체의 소유자인 함수를 가리키는 포인터인 calee라는 프로퍼티도 있다.

this 는 함수가 실행 중인 컨텍스트 객체에 대한 참조이다. 함수를 웹페이지의 전역 스코프에서 호출했다면 this 객체는 window를 가리킨다.

caller 프로퍼티는 해당 함수를 호출한 함수에 대한 참조를 저장하며 전역 스코프에서 호출했다면 null이 저장된다.


5.5.5 함수 프로퍼티와 메서드
ECMAScript에서 함수는 객체이므로 프로퍼티와 메서드를 가지는데 모든 함수에 공통인 프로퍼티는 length와 prototype이다.  length 프로퍼티는 함수가 넘겨받을 것으로 예상하는 이름 붙은 매개변수의 숫자이다.
prototype 프로퍼티는 개발자 자신만의 참조 타입과 상속을 정의할 때 매우 중요하며, 열거할수 없는 프로퍼티이므로 for-in문에 나타나지 않는다.

apply()call() 두 가지 메서드는 소유자인 함수를 호출하면서 this를 넘기는데 결과적으로 함수 내부에서 this 객체의 값을 바꾸는 것이나 마찬가지이다.
apply() 메서드는 매개변수로 소유자 함수에 넘길 this 와 매개변수 배열을 받는데 두 번째 매개변수는 Array의 인스턴스일 수도 있고 arguments 객체일 수도 있다.

 

5.6 원시 래퍼 타입
Boolean, Number, String은 원시 값을 편리하게 조작하기 위해 디자인된 참조타입이다.
원시 값을 읽을 때마다 이에 해당하는 래퍼 타입이 이면에서 생성되므로 메서드를 사용할수 있다.
new 연산자를 사용해 참조 타입의 인스턴스를 만들면 스코프를 벗어날 때까지 메모리에 존재하지만 자동으로 생성된 원시 래퍼 타입은 코드의 해당 행을 벗어나는 즉시 파괴된다. 따라서 원시 래퍼 타입에는 런타임에 프로퍼티나 메서드를 추가할 수 없다.

원시래퍼 타입에  typeof를 대입하면 "object"를 반환하며 원시 래퍼 객체는 모두 불리언 값인 true로 변환된다.

Object 생성자에 문자열을 넘기면 String 인스턴스가 생성되며 숫자를 넘기면 Number 의 인스턴스가, 불리언을 넘기면 Boolean 인스턴스가 생성되는데 new를 사용해 원시 래퍼 생성자를 호출한 것과 같은 이름의 형변환 함수를 호출한 결과는 다르다.


5.6.1 불리언 타입
Boolean 타입은 불리언 값에 대응하는 참조 타입으로 객체를 생성하기 위해서는 Boolean 생성자에 ture나 false를 넘긴다.

var booleanObject = new Boolean(ture); 

Boolean 인스턴스는 원시 값 true나 false를 반환하도록 valueOf() 메서드를 오버라이드한다.


5.6.2 Number 타입
Number타입은 숫자형 값의 참조타입으로 Number 객체는 Number 생성자에 숫자를 넘겨 생성한다.

var numberObject = new Number(10); 

Number 타입에는 상속받은 메서드 외에도 숫자를 다양한 형식의 문자열로 반환하는 메서드가 있다.
toFixed() 메서드는 매개변수로 지정한 만큼의 정확도로 소수점을 찍은 문자열을 반환하고 지정한 자리수보다 크다면 반올림한다.

toExponential() 메서드는 숫자를 지수 표기법 문자열로 반환한다.
toPrecision() 메서드는 자신을 호출한 객체의 숫자형 값에 따라 toFixed()나 toExponentiol() 중 하나를 호출하여 지수 표기법이나 소수점 표기법을 선택하여 반환한다.


5.6.3 String 타입

var stringObject = new String("Hello world"); 

String 객체의 메서드는 모두 원시 문자열에서 사용할수 있다.
String 인스턴스는 모두 length 프로퍼티가 있는데 이 프로퍼티에는 문자열 길이를 나타내는 숫자가 저장된다.

글자 메서드
문자열의 특정 문자에 접근하는 메서드는 charAt()charCodeAt() 두 가지이고 각 메서드는 매개변수 하나를 받는데 이는 원하는 문장의 인덱스이다.
특정 문자를 호출할때는 charAt() 메서드를 사용하고 문자 자체가 아니라 문자 코드가 필요할 때는 charCodeAt()을 사용한다.


문자열 조작 메서드
concat() 메서드는 문자열을 병합하여 그 결과를 반환하며 매개변수 숫자에 제한이 없다.
하지만 문자열을 합칠때는 + 연산자가 더 많이 쓰이며 더 빨리 동작한다.

ECMAScript 에는 문자열 일부로 새 문자열을 만드는 메서드가 slice(), substr(), substring() 세가지가 있다.
slice()와 substring() 에서는 두번째 매개변수 직전까지의 문자를 가져오고, substr()에서는 두번째 매개변수가 문자를 몇개 가져올지 나타낸다. 두번째 매개변수를 생략하면 열 전체 길이가 기본 값으로 사용된다.


문자열 위치 메서드
문자열의 위치를 찾는 메서드는 indexOf()와 lastIndexOf() 두가지가  있는데 문자열을 검색해 그 위치를 반환하며 찾지 못핬을때는 -1을 반환한다. 두 메서드의 차이는 indexOf()가 문자열 처음에서 검색을 시작하는 반면 lastIndexOf()는 문자열 마지막막에서 검색을 시작한다.


trim() 메서드
trim() 메서드는 문자열을 복사한 후 앞뒤 공백을 모두 제거한 결과를 반환한다.


대소문자 메서드
toLowerCase(), toLocaleLowerCase(), roUpperCase(), toLocaleUpperCase() 네가지 메서드가 있는데 일부 언어에서는 대소문자 변환에 따른 특별한 규칙이 필요하며 이 때문에 지역 메서드가 필요하다. 일반적으로 작성한 코드가 어느 지역에서 실행될지 모른다면 지역 메서드를 쓰는 편이 안전한다.

문자열 패턴 매칭 메서드
String 타입에는 문자열 내에서 패턴 매칭을 하도록 만들어진 메서드가 몇가지 있는데 가장 많이 쓰이는 메서드는 match()로 RegExp 객체의 exec() 메서드와 같은 결과를 반환한다.
match() 메서드는 매개변수로 정규 표현식 리터럴이나 RegExp 객체를 하나 받는다.

serch() 메서드는 패턴에 일치하는 첫번째 문자열 인덱스를 반환하며 일치하는 것을 찾지 못했을 때는 -1을 반환한다. 항상 문자열 처음에서 검색을 시작한다.

replace() 는 문자열 일부를 바꾼다.
매개변수를 두개 받는데 첫번째 매개변수는 RegExp 객체 또는 문자열이고 두번째 매개변수는 문자열 또는 문자열을 반환하는 함수이다.

htmlEscape() 함수는 HTML에서 사용할 수 있도록 특수문자를 이스케이프하게 만들었다.
HTML에서 <,  >,  &,  "  문자를 그대로 쓸수 없으므로 반드시 이스케이프해야 한다.

split() 메서드는 텍스트를 구분자를 기준으로 분리해서 배열에 담아 변환한다.

localeCompare() 메서드
문자열 두 개를 비교한 후 세가지 값 -1. 0. 양수(대부분1) 중 하나를 반환한다.  메서드를 호출하는 텍스트가
매개변수로 넘긴 문자열보다 알파벳 순서상 뒤에있다면 -1
매개변수 문자열이 일치하면 0
매개변수로 넘긴 문자열보다 알파벳 순서상 앞에 있다면 1

fromCharCode() 메서드
문자 코드를 받아 문자열로 변환하는것으로 charCodeAt() 메서드가 하는 일을 거꾸로 한다고 생각하면 된다.

HTML() 메서드
자바스크립트에서 동적으로 HTML 형식을 생성할 필요가 있지만 이 메서드를 쓰면 시멘틱 마크업을 해치므로 거의 사용하지 않는다.

 

5.7 내장된 싱글톤 객체

5.7.1 Global 객체
Global 객체는 명시적으로 접근할수 없다는 점에서 가장 독특한 객체이다.
ECMA-262는 Global 객체를 소유자가 없는 모든 프로퍼티와 메서드를 담는 객체로 정의한다. 사실 전역 변수나 전역 함수라는 것은 존재하지 않는다. 전역에서 정의한 변수와 함수는 모두 Global 객체의 프로퍼티가 된다.

 
URI 인코딩 메서드
encodeURI() 와 encodeURIComponent() 메서드는 브라우저에 전달할 URI를 인코드하는 메서드이다.
URI 인코딩 메서드는 특별한 UTF-8 인코딩을 써서 URI에 사용할 수 없는 문자를 브라우저가 인식하고 이해할수 있는 문자로 바꿔준다.

encodeURI() 메서드는 전체 URI에 대해 작업하도록 만들어졌고 : 이나 /,  ?,  #처럼 URI의 일부분으로 쓰이는 특수 문자는 인코드 하지 않지만 encodeURIComponent() 메서드는 비표준 문자를 모두 인코드 한다.

decodeURI()와 decodeURIComponent()는 반대의 역할을 한다.


eval() 메서드
eval() 메서드는 ECMAScript 인터프리터 자체인 듯 동작하며 매개변수로 문자열을 하나 받는데 이 문자열은 실행할 수 있는 ECMAScript 코드여야 한다.

eval("alert('hi");
alert("hi");

인터프리터가 eval()을 만나면 매개변수를 실제 ECMAScript 문장으로 해석해서 eval() 이 있던 위치에 삽입한다. eval()이 실행하는 코드는 eval()을 호출한 실행 컨텍스트의 일부분으로 간주되며 해당 컨텍스트와 같은 스코프 체인을 갖는다.

문자열을 코드로 변환하는 eval()을 쓸때는 항상 주의해야하며 사용자가 악의적으로 보안을 해치는 값을 입력할수 있기 때문에 eval()을 쓸때는 특히 더 조심해야 한다.


Global 객체의 프로퍼티
특별한 값인 undefined, NaN, Infinity외에 네이티브 참조 타입 생성자인 Object나 Function 등도 Global 프로퍼티다.
ECMAScript 5판에서는 undefined, NaN, Infinity에 값을 할당할 수 없음을 명확히 했다. 이들에 값을 할당하려 하면 스트릭트 모드가 아닐 때에도 에러가 난다.


window 객체
웹브라우저에서는 window 객체를 통해 global객체에 접근 할 수 있다.
즉 전역 스코프에서 선언한 변수와 함수는 모두 window 객체의 프로퍼티가 된다.


5.7.2 Math객체
수학 공식과 각종 상수를 Math 객체에 저장한다.

Math 객체의 프로퍼티
Math 객체의 프로퍼티는 대부분 수학에서 쓰이는 특별한 상수이다.


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() 메서드
Math.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)];

 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

브라우저 객체모델  (0) 2014.11.12
함수 표현식  (0) 2014.10.23
객체에 대한 이해  (0) 2014.10.15
변수와 스코프, 메모리  (0) 2014.10.07
언어의 기초  (0) 2014.10.01

객체에 대한 이해

2014. 10. 15. 16:08 나홀로스터디/JS For Web Dev


6장 객체에 대한 이해

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
6.1.1 프로퍼티타입
6.1.2 다중 프로퍼티 정의
6.1.3 프로퍼티 속성 읽기


객체지향(Object-oriented) 언어는 일반적으로 클래스를 통해 같은 프로퍼티와 메서드를 가지는 객체를 여러개 만드는 특징이 있는데 ECMAscript는 객체를 "프로퍼티 순서 없는 컬렉션이며 각 프로퍼티는 원시 값이나 객체, 함수를 포함한다" 는 것이다.
이것은 객체가 특별한 순서없이 값의 배열이라는 의미로 ECMAscript객체를 이름-값 쌍의 그룹이며 각 값은 데이터나 함수가 되는 해시 테이블이라고 이해하면 된다.

객체를 만드는 가장 단순한 방법은 Object의 인스턴스를 만들고 여기에 프로퍼티와 메서드를 추가하는 방법이다.

var person = {   name : "nicholas",   age " 29",

  sayName : function(){     console.log(this.name);   } }


6.1.1 프로퍼티타입
프로퍼티의 특징은 내부적으로만 유효한 속성에 따라 자바스크립트 엔진 내부에서 구현하는 것으로 정의했으므로 이들 속성에 직접적으로 접근할수 있는 방법은 없다.
프로퍼티에는 데이터 프로퍼티와 접근자 프로퍼티 두가지 타입이 있고 이들 속성은 [[Enumerable]] 처럼 이름을 대괄호로 감싸서 나타낸다.


데이터 프로퍼티
데이터 프로퍼티는 데이터 값에 대한 단 하나의 위치를 포함하여 이 위치에서 값을  읽고 쓴다.

[[Configurable]] - 해당 프로퍼티가 delete를 통해 삭제하거나 프로퍼티 속성을 바꾸거나 접근자 프로퍼티로 변환할수 있음을 나타내고 기본 속성은 true이다.
[[Enumerable]] - for-in 루프에서 해당 프로퍼티로 반환함을 나타내고 기본속성은 true이다.
[[Writable]] - 프로퍼티의 값을 바꿀수 있음을 나타내고 기본 속성을 true이다.
[[Value]] - 프로퍼티의 실제 데이터 값을 포함하고 기본 속성 값은 undefined이다.

기본 프로퍼티 속성을 바꾸려면 반드시 Object.defineproperty()메서드를 써야하고 이 메서드는 프로퍼티를 추가하거나 수정할 객체, 프로퍼티 이름, 서술자 객체 세가지를 매개변수로 받는다.


접근자 프로퍼티
접근자 프로퍼티에는 데이터 값이 들어있지 않고 대신 getter 함수와 setter 함수로 구성된다
접근자 프로퍼티를 읽을 때는 getter 함수가 호출되며 유효한 값을 반환할 책임은 이 함수에 있고 접근자 프로퍼티에 쓰기 작업을 할 때는 새로운 값과 함께 함수를 호출하며 이 함수가 데이터를 어떻게 사용할지 결정한다.

[[Configurable]] - 해당 프로퍼티가 delete를 통해 삭제하거나 프로퍼티 속성을 바꾸거나 접근자 프로퍼티로 변환할수 있음을 나타내고 기본 속성은 true이다.
[[Enumerable]] - for-in 루프에서 해당 프로퍼티로 반환함을 나타내고 기본속성은 true이다.
[[Get]] - 프로퍼티를 읽을 때 호출할 함수로 기본값은 undefined이다.
[[Set]] - 프로퍼티를 바꿀 때 호출할 함수로 기본값은 undefined이다.

접근자 프로퍼티를 명시적으로 정의할수 없으며 반드시 Object.defineproperty()를 써야한다.
프로퍼티의 값을 바꿨을 떄 해당 프로퍼티만 바꾸는게 아니라 부수적인 절차가 필요한 경우에 사용한다.


6.1.2 다중 프로퍼티 정의
객체에서는 프로퍼티를 동시에 여러개 수정해야할 가능성이 높으므로 Object.defineProperties() 메서드를 제공한다. 

var book = {};

Object.defineProperties(book, {   _year : {     value : 2004   },
  edition : {     value : 1   },

  year : {     get : function(){       return this._year;     },     set : function(newValue){       if(newValue > 2004){         this._year = newValue;         this.edition += newValue - 2004;       }     }   } })

 


이 코드는 book 객체에 _year 와 edition 두 가지 데이터 프로퍼티와 접근자 프로퍼티 year 를 생성한다.


6.1.3 프로퍼티 속성 읽기
ECMAscript5의 Object.getOwnPropertyDescriptor() 메서드를 이용해 원하는 프로퍼티의 서술자 프로퍼티를 읽을수 있고 읽어올 프로퍼티가 포함된 객체, 서술자를 가져올 프로퍼티 이름 두 가지 매개변수를 받는다.

 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

함수 표현식  (0) 2014.10.23
참조타입  (0) 2014.10.17
변수와 스코프, 메모리  (0) 2014.10.07
언어의 기초  (0) 2014.10.01
HTML 속의 자바스크립트  (0) 2014.09.23
Copyright © HuckleberryM All Rights Reserved | JB All In One Designed by CMSFactory.NET