# BOM Browser Object Model

자바스크립트가 브라우저에게 'talk' 할 수 있게 해줌.

# window 객체

  • 모든 브라우저에서 지원함.
  • 모든 자바스크립트 전역 (객체, 함수, 변수) 는 자동으로 window 객체의 멤버가 됨.
  • 전역 변수 : window object 의 프로퍼티
  • 전역 함수 : window object 의 메서드
  • document object : window object 의 프로퍼티
window.document.getElementById("header");
document.getElementById("header");
1
2

# Window Size

# Inner / Outer

  • 픽셀 단위의 크기 반환 image

  • outerHeight : 전체 브라우저 창의 높이

  • innerHeight : 가로 스크롤 막대 포함한 높이

  • <html>TagElement.clientHeight : 가로스크롤과 테두리를 제외한 창의 높이

  • outerWidth : 사이드바, 창크기 조정 테두리 포함한 전체 브라우저 창의 너비

  • innerWidth : 세로 스크롤 막대를 포함한 너비

익스플로러 8/7/6/5 환경을 고려한다면 아래와 같이 사용해야 한다고 함

const w = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;

const h = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
1
2
3
4
5
6
7

outer 는 그냥 안쓰다고 생각하면 된다.

# window size 메서드

  • window.open() 새 창 open
    • window.open("http://myurl.domain", "myWindowName", "resizable");
      • 창의 크기를 조절할 수 있도록 하려면 resizable 필요
  • window.close() 현재 창 close
  • window.moveTo(x, y) 창을 화면 (x, y) 에 위치시킴 🔗
  • window.moveBy(x, y) 창을 화면 현 위치에서 (x, y) 만큼 이동시킴 🔗
  • window.resizeTo(outerWidth, outerHeight) 현재 창의 크기를 바꿈 🔗
  • window.resizeBy(xDelta, yDelta) 현재 크기를 기준으로, 지정된 양만큼 현재 창의 크기를 조정함. 🔗
  • 여는 창이 현재 창과 동일한 Origin 이 아닌 경우 해당 창/탭의 크기를 조정하거나 정보에 액세스 할 수 없다.

# window.screen 🔗

  • 사용자 스크린(해상도)에 대한 정보 (브라우저가 아님)
  • 픽셀 단위

# screen.width / screen.height

화면(해상도)의 너비/높이 반환

익스플로러의 경우, screen 을 보고할 때, 브라우저의 확대/축소 를 고려함

  • 확대 축소가 100% 일 때에만 실제 해상도 반환

# screen.availWidth / screen.availHeight

avail.. 속성 : 작업표시줄(Windows Taskbar) 크기를 제외한 해상도

# screen.colorDepth / screen.pixelDepth

hardware for color resolution

  • 8 bits = 256 different "VGA colors".
  • 16 bits = 65,536 different "High Colors"
  • 24 bits = 16,777,216 different "True Colors"
  • 32 bits = 4,294,967,296 different "Deep Colors"

rgb 는 HTML 에서 'True Color' 이다

  • 최신 컴퓨터는 color Depth 와 pixel Depth 는 동일함

# screen.orientation 🔗

  • 화면의 현재 방향
    • portrait-primary
    • portrait-secondary
    • landscape-primary
    • landscape-secondary
  • 설치된 웹 앱, full-screen mode 의 웹페이지에서 동작함

# window.location

  • 현재 페이지의 주소(URL) 가져오기
  • 브라우저를 새로운 페이지로 redirect

image

# window.location / document.location 🔗

image

  • 같은 방식으로 사용함
  • 공식적으로
    • window.location 현재 위치를 object 로 가져올 수 있는 표준방법
    • document.location 현재 URL 값이 String 으로 반환
  • 혼란: document.location -> document.URL 변경
  • 모든 최신 브라우저는 document.locationwindow.location 에 매핑함.

# location.href 🔗

  • 현재 페이지의 URL (href) 반환
  • href 변경
string = object.href;
object.href = string;
1
2
// <a id="myAnchor" href="https://developer.mozilla.org/en-US/Location/href"> 
const anchor = document.getElementById("myAnchor");
const result = anchor.href; // Returns: 'https://developer.mozilla.org/en-US/Location/href'
1
2
3

# location.replace(url) / location.assign(url) 🔗

  • 현재 리소스를 제공된 url 의 리소스로 바꿈
  • replace 현재 페이지를 사용한 후에는 history 되지 않음 -> 뒤로가기 버튼으로 이동 X
  • assign 뒤로 버튼을 눌러 호출한 페이지로 돌아갈 수 있다.
  • url 이 Origin 과 다른 경우 보안 오류를 발생
  • url 이 유효하지 않은 경우 syntax Error 가 발생
// Navigate to the Location.reload article by replacing this page
window.location.replace('https://developer.mozilla.org/en-US/docs/Web/API/Location.reload');
1
2

# location.hostname

# location.pathname

# location.protocol

# location.hash

<a id="myAnchor" href="https://developer.mozilla.org/en-US/docs/Location.search?q=123">

const anchor = document.getElementById("myAnchor");
const queryString = anchor.search; // Returns:'?q=123'

// Further parsing:
let params = new URLSearchParams(queryString);
let q = parseInt(params.get("q")); // is the number 123
1
2
3
4
5
6

# URLSearchParams.get(name)

https://example.com/?name=Jonathan&age=18

let params = new URLSearchParams(window.location.search.substring(1));
let name = params.get("name"); // is the string "Jonathan"
let age = parseInt(params.get("age"), 10); // is the number 18

let address = params.get("address"); // null
1
2
3
4
5

# URL.searchParams

const urlSearchParams = url.searchParams

  • @return URLSearchParams 객체

https://example.com/?name=Jonathan%20Smith&age=18

let params = (new URL(document.location)).searchParams;
let name = params.get('name'); // is the string "Jonathan Smith".
let age = parseInt(params.get('age')); // is the number 18
1
2
3

# location.reload() 🔗

새로고침 버튼처럼 현재 리소스를 다시 불러 온다.

  • location.relaod() 를 호출한 스크립트의 origin 과 Location 객체를 소유한 문서의 origin 이 다를 때 CORS 에 의해 SECURITY_ERROR DOMException 가 발생한다. (?TODO 예시)

# window.history

브라우저 히스토리를 담고 있는 객체

# history.length 🔗

  • 현재 페이지를 포함해, 세션 기록의 길이를 나타내는 정수를 반환한다.
  • 뒤로가기 할 수 있는 페이지의 개수

# history.back() 🔗

  • 브라우저가 세션 기록의 바로 뒤 페이지로 이동하도록 지시.
  • 브라우저에서 뒤로가기 버튼을 눌렀을 때
  • history.go(-1)
  • 비동기적 메서드
    • popstate 이벤트 처리기를 통해 탐색 완료 시점을 알 수 있다.

# popstate

  • Event handler property : onpopstate
  • 사용자의 세션 기록 탐색으로 인해 현재 활성화된 기록 항목이 바뀔 때 발생한다.
  • 브라우저의 back 이벤트 / history.back() 을 통해서만 발생함.
  • history.pushState() / history.replaceState() 으로 활성화 엔트리 생성
    • popstate 이벤트의 state 속성 <= 히스토리 엔트리 state 객체의 복사본
window.onpopstate = function(event) {
  console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
history.pushState({page: 1}, "title 1", "?page=1");
history.pushState({page: 2}, "title 2", "?page=2");
history.replaceState({page: 3}, "title 3", "?page=3");
history.back(); // Logs "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // Logs "location: http://example.com/example.html, state: null
history.go(2);  // Logs "location: http://example.com/example.html?page=3, state: {"page":3}
1
2
3
4
5
6
7
8
9

TODO 위에 예시에서 로그가 뜨는 순서의 이해의 보충이 필요하다.

  • 브라우저마다 이벤트 시점이 다를 수 있다.

# history.forward()

  • 히스토리 목록에서 다음 url 를 로드하는 메서드
  • 브라우저에서 앞으로 가기 버튼
  • history.go(1)
  • 비동기적 메서드
    • popstate 이벤트 처리기를 통해 탐색 완료 시점을 알 수 있다.

# history.pushState(state, title[, url]) 🔗

브라우저의 세션 기록 스택에 상태 추가

  • SPA 를 만들 때 자주 이용 된다.
  • 페이지 깜박임 없니 주소를 바뀌고, 바뀐 주소에 따른 액션을 취할때 사용된다.
const state = { 'page_id': 1, 'user_id': 5 };
const title = '';
const url = 'hello-world.html';

history.pushState(state, title, url);
1
2
3
4
5

# state

  • 새로운 세션 기록항목에 연결할 상태 객체
  • 직렬화 가능한 객체

# title

  • 현재 대부분의 브라우저가 title 매개변수를 무시함.
  • 빈문자열을 정하면 나중의 변경 사항에도 안전할 것임

# url

  • 새로운 세션 기록 항목의 url
  • pushState() 이후 브라우저는 주어진 url 의 탐색을 하지 않지만, 브라우저를 재시작 하였을 때 탐색을 시도할 수 있다.
  • 현재 url 을 기준으로, 상대 url 을 사용할 수 있음
  • cross origin 일 경우 예외 발생

# pushState() VS window.location = "#foo"

  • 공통점 : 명령문 이후 같은 문서에 머무른다.

  • window.location 설정 (해시 기반 방식)

    • 해시만 수정해야 같은 문서에 머무른다.
    • 현재 해시가 #foo 가 아닐 때만 새로운 기록 항목을 생성한다.
    • 임의의 데이터를 연결하기 위해서는 필요한 모든 데이터를 인코딩해 짧은 문자열로 만들어야 한다.
  • pushState() 는 url 을 바꾸지 않아도 된다.

    • 호출 이후 url 의 탐색을 하지 않는다.
    • 호출 할 때 url 을 바꾸지 않아도 된다.
    • 임의의 데이터를 세션 기록 항목에 연결할 수 있다. state
    • 이전 URL 와 신규 URL 의 해시가 다르더라도 hashchange 이벤트를 유발하지 않는다.
    • HTML 외의 문서에서는 이름공간 URI 가 null 인 요소를 생성한다.

# history.replaceState(stateObj, title[, url]) 🔗

  • 현재 history 를 수정해 메서드의 매개 변수에 전달된 stateObj, title, URL 로 대체함.
const stateObj = { foo: 'bar' };
history.pushState(stateObj, '', 'bar.html');
history.replaceState(stateObj, '', 'bar2.html');
1
2
3
  1. URL 표시줄에 https://www.mozilla.org/bar2.html 이라고 표시
  2. 브라우저가 bar2.html 로드/파일 확인 을 하지 않는다.

# window.navigator 🔗

스크립트를 구동 중인 애플리케이션에 대한 메서드와 속성

브라우저 버전에 따라서 오류가 있을 수도 있다.

  • 다른 브라우저에서 동일한 이름을 사용할 수 있습니다.
  • navigator data 는 브라우저 소유자가 변경할 수 있습니다.
  • 일부 브라우저는 사이트 테스트를 우회하기 위해 자신을 잘못 식별합니다.
  • 브라우저는 브라우저보다 늦게 출시 된 새 운영 체제를 보고 할 수 없습니다.
  • 쿠키 사용 여부
  • Boolean 값을 반환
  • Readonly
  • Browser Application Name
navigator.appName; // "Netscape"
1

Netscape : IE11, Chrome, Firefox, Safari. 일 때 🔗

  • 단지 호환성을 위해 Netscape 를 반환한다. (?)
  • 브라우저 감지는 나쁜 관행 (?) 이다.
  • 대신 navigator.userAgent 속성을 사용한다.

Mozilla : Chrome, Firefox, IE, Safari, Opera

  • 단지 호환성을 위해 Mozilla 를 반환한다. (?)
navigator.appCodeName; // Mozilla
1
  • 브라우저 엔진의 프로덕트 이름

Gecko 모든 브라우저

게코(영어: Gecko)은 웹 브라우저를 만드는 데 기반을 제공하는 오픈 소스 응용 프로그램 프레임워크이다.

navigator.product; // Gecko
1

브라우저 버전정보

// 5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36
navigator.appVersion;
1
2
  • Mozilla/5.0 (Macintosh;Intel Mac OS X 10_15_6)
    • appCodeName/appVersion number (Platform; Security; OS-or-CPU;
  • AppleWebKit/537.36 (KHTML, like Gecko)
    • Localization; rv: revision-version-number) product/productSub
  • Chrome/86.0.4240.80 Safari/537.36
    • Application-Name Application-Name-version
navigator.userAgent; // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36
1

browser platform : operating system

navigator.platform; // MacIntel
1
  • navigator.language

    • 사용자가 선호하는 언어 (일반적으로 브라우저의 UI 언어)
    • 알 수 없는 경우 null
    navigator.language; // ko-KR
    
    1
  • navigator.languages

    • 선호도에 따라 사용자에게 알려진 언어를 나타내는 배열
    navigator.languages; // ["ko-KR", "ko", "en-US", "en"]
    
    1
  • 브라우저의 온라인 상태 boolean 반환
  • 값이 바뀔 때
    • 브라우저의 네트워크 연결 기능이 변경 될 때 마다
    • 사용자가 링크를 따르거나, 스크립트가 원격 페이지를 요청할 때
  • 브라우저마다 구현된 작동 속성이 다르다. 🔗
  • window.ononline window.onoffline 이벤트를 수신하여 네트워크 상태 변화를 확인
window.addEventListener('offline', function(e) { console.log('offline'); });
window.addEventListener('online', function(e) { console.log('online'); });
1
2

현재 브라우저가 Java 를 사용할 수 있는지 여부

navigator.javaEnabled(); //  false
1

@return ServiceWorkerContainer 객체

  • ServiceWorker 와 상호작용을 제공.
    • 등록, 제거, 업그레이드
if ('serviceWorker' in navigator) {
  // 브라우저가 서비스 워커를 지원하는지 확인
}
1
2
3

TODO 서비스 워커

  • 모달창(부모 창으로 돌아가기 전에 사용자의 상호 작용을 요구하는 자식 창)으로 사용자는 대화 상자가 닫힐 때까지 다른 모든 인터페이스에 접근할 수 없다.
  • 대화 상자를 만드는 함수를 남용해서는 안된다.
  • 대화 상자로 사용자 확인을 받는 것은 피해야 한다. 🔗

# window.alert([message]) 🔗

  • 경고 대화 상자
    • 확인 버튼
    • message 메시지를 지정할 수 있다.
      • 경고 대화 상자에 표시할 텍스트 문자열이나 문자열로 변환해 나타낼 객체
  • 쓰임
    • 사용자의 확인을 제외한 다른 입력을 요구하지 않는 메시지를 전달

# window.confirm(message)

  • 확인과 취소 두 버튼

  • message를 지정할 수 있는 모달 대화 상자를 띄운다.

    • 경고 대화 상자에 표시할 텍스트 문자열
  • @return

    • 확인 -> true
    • 취소 -> false
    • 브라우저가 페이지 내 대화 상자 무시 -> false

# window.prompt([message, default]) 🔗

  • 사용자가 텍스트를 입력할 수 있도록 안내하는 선택적 메시지를 갖고 있는 대화 상자
  • message
    • 사용자에게 보여줄 문자열
    • 프롬프트 창에 표시할 메시지가 없으면 생략가능
  • default
    • 텍스트 입력 필드에 기본으로 채워넣을 문자열
    • IE 7/8 default -> undefined
  • @return
    • 사용자가 입력한 문자열 else null

# Timing Events

timing events 자바스크립트가 시간 간격(time intervals) 으로 실행 될 수 있는 것.

# window.setTimeout(function, milliseconds) 🔗

타이머가 만료된 뒤 함수나 지정된 코드를 실행하는 타이머를 설정함

const timeoutID = window.setTimeout(func[, delay, param1, param2, ...]);
const timeoutID = window.setTimeout(code[, delay]);
window.setTimeout(function, milliseconds);
1
2
3
  • func
    • 타이머가 완료된 후 실행됨
  • code
    • 함수 대신 문자열
    • eval() 과 같은 보안 위험성으로 권장되지 않음
    • window.setTimeout("alert('Hello World!');", 500);
  • delay
    • 타이머가 지정된 함수나 코드를 실행시키기 전에 기다려야할 ms(1/1000초) 단위의 시간
    • default 는 0
    • 실제 지연 시간은 더 길어질 수 있다.
  • param1, ..., paramN
    • 타이머가 완료되고 func 에 전달되는 추가적인 매개변수들
  • @return
    • timeoutID 숫자
    • setTimeout() 을 호출하여 만들어진 타이머를 식별할 수 있는 0 이 아닌 값
    • 타이머를 취소하기 위해 window.clearTimeout() 에 전달
    • setTimeout()setInterval() 은 같은 ID 공간을 공유
      • cleatTimeout() clearInterval() 은 기술적으로 동일
      • 코드 유지보수에 혼란을 피하기 위해 쌍을 일치시켜 주자

# this

setTimeout() 에 의해 실행된 코드는 별도의 실행 컨텍스트에서 setTimeout 이 호출된 함수로 호출된다.

  • 비엄격모드 -> 전역객체
  • 엄격 모드 -> undefined

myArray.myMethod() 가 메서드로 호출되었기 때문에 this 는 myArray 임.

myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
1
2
3
4
5
6
7

myArray.myMethod 가 호출되지 않고 setTimeout 에 전달됨

  • 호출 될 때 this 가 설정되어 있지 않아 기본 값(전역 객체)
  • 역시 forEach, reduce 와 같은 array 메서드 : this 를 넘길 수 있는 옵션 X
setTimeout(myArray.myMethod, 1000); // 1초 뒤 "[Window 객체]" 출력
setTimeout(myArray.myMethod, 1500, "1"); // 1.5초 뒤 "undefined" 출력
1
2

해결책

  1. this 설정이 필요한 곳을 함수로 감싼다.
    setTimeout(function(){myArray.myMethod()}, 2000); // 2초 뒤"zero,one,two" 출력
    setTimeout(function(){myArray.myMethod('1')}, 2500); // 2.5초 뒤"one" 출력
    
    1
    2
  2. 화살표 함수
    setTimeout(() => {myArray.myMethod()}, 2000); // 2초 뒤 "zero,one,two" 출력
    setTimeout(() => {myArray.myMethod('1')}, 2500); // 2.5초 뒤 "one" after 2.5 출력
    
    1
    2
  3. bind()
    myArray = ["zero", "one", "two"];
    myBoundMethod = (function (sProperty) {
        console.log(arguments.length > 0 ? this[sProperty] : this);
    }).bind(myArray);
    
    myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
    myBoundMethod(1); // prints "one"
    setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
    setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  4. 전역함수 setTimeout()과 setInterval()를 this 객체를 전달할 수 있는 전역함수로 대체

# 타이머가 지연되는 이유

# 1. 중첩된 타임 아웃이 4 ms 이하일 경우

  • 최소 지연보다 작은 time 메서드 호출 -> 최소 지연을 사용하도록 강제됨
  • 최소 지연시간은 : 브라우저마다 다르다.
  • 최신 브라우저에서 0ms 타임 아웃을 구현하려면 window.postMessage()

# 2. 비활성화 탭에서 타임아웃이 1000ms 에 여러번 일어날 경우

부하/배터리 사용양 감소를 위해, 비활성화 탭들에서 타입아웃이 1초에 여러번 일어나지 않도록 clamping 된다.

활성화탭

  • 현재 사용하고 있는 탭
  • 나머지 탭들은 비활성화 탭 image

# 3. 타임 아웃 지연

다른 작업들로 인해 늦게 실행 될 수 있다.

# 최대 지연 값

  • IE, Chrome, Safari, and Firefox : 32-bit 부호있는 정수
  • 2147483647 보다 더 큰 지연 > 정수 오버플로우가 발생, 타임아웃이 즉시 실행

setTimeout 을 읽어보면서 이전에 작성했던 피드백을 다시 읽어보았다. 🔗 setInterval 의 콜백 함수로 function(){...}을 넣어주면 해당 function 은 setInterval 객체의 메소드가 된다. 즉, 콜백함수 내 작성된 this 는 실행객체, setInterval 함수를 가리키게 되고 ...

# Cookies

  • 웹 페이지에 저장되는 작은 크기의 문자열
  • 이름-값 의 쌍이다. username = John Doe
  • 각 쌍은 ;로 구분
  • HTTP 프로토콜의 일부이다.
  • 쓰임
    • 인증, 클라이언트 식별
  • 주로 웹 서버에 의해 만들어짐
    1. [서버] HTTP Response Header 에 Set-Cookie 에 내용을 넣어 전달
    2. [브라우저] Set-Cookie 내용을 브라우저의 쿠키에 저장.
    3. [브라우저] 사용자가 쿠키를 생성하도록 한 동일 서버(사이트) 에 접속할 때마다 쿠키의 내용을 Cookie Request Header 에 넣어 전달
    4. [서버] 쿠키를 보고 사용자에게 필요한 정보를 준다.

쿠키를 CRUD 할 수 있다.

# Create

  • 새 쿠키를 설정하면 document.cookie 에 추가됨
    • 데이터 프로퍼티가 아닌 접근자 프로퍼티
    • 이전 쿠키를 덮어 쓰지 않음
  • 쿠키의 이름
    • 모든 글자 허용
    • 형식의 유효성과 일관성유지 -> encodeURICpmponent 를 사용하여 이름과 값을 이스케이프 처리
    // 특수 값(공백)은 인코딩 처리해 줘야 합니다.
    let name = "my name";
    let value = "John Smith";
    
    // 인코딩 처리를 해, 쿠키를 my%20name=John%20Smith 로 변경하였습니다.
    document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
    
    alert(document.cookie); // ...; my%20name=John%20Smith
    
    1
    2
    3
    4
    5
    6
    7
    8
  1. document.cookie = "username=John Doe";
    
    1
  2. 만료 Date 명시하기(UTC time)

    document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC";
    
    1
  3. path : 쿠키가 속한 페이지 지정

    document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";
    
    1

# Read

const x = document.cookie;  // string: cookie1=value; cookie2=value; cookie3=value;
1

# Update

overwritten 이 된다.

document.cookie = "username=John Smith; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";
1

# Delete

  1. 브라우저가 종료될 때

  2. 만료 Date 적기, 빈 값

    document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
    
    1
    • 쿠키 경로를 정의해야 올바르게 쿠키를 삭제할 수 있다.
  • 일반 텍스트 문자열과 다르다.
  • 전체 쿠키 문자열을 써도 다시 읽으면 이름-값 쌍만 볼 수 있다.
  • 지정된 하나의 쿠키 값을 찾기
    • 쿠키 문자열에서 쿠키 값을 검색하는 JavaScript 함수 작성 필요

쿠키에 대한 내용은 추후에 다룰것이다.

# Reference

  • https://www.w3schools.com/js/js_window.asp
  • MDN
  • https://lifea.co.kr/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-window-screen/
  • https://poiemaweb.com/js-global-object
  • https://ko.javascript.info/cookie
  • https://www.zerocho.com/category/JavaScript/post/573b321aa54b5e8427432946