바인딩이란, 서로 묶어서 연결해 준다는 뜻이다. 이벤트 바인딩이란, 발생하는 이벤트와 그 후에 어떤 일이 벌어질지 알려주는 함수(콜백함수)와 묶어서 연결해 준다는 뜻이다. 예를 들어, 어떤 버튼을 사용자가 클릭하게 되면, 클릭(‘click’)이벤트가 발생하게 되고, 그 이벤트가 발생했을 때 어떤 일이 벌어진다는 것을 알려주는 콜백함수를 실행하게 된다. 이때, 이 콜백함수를 이벤트 핸들러라고 한다.
이벤트 바인딩에는 대표적으로 3가지 방식이 있다.
HTML 이벤트 핸들러
전통적인 DOM 이벤트 핸들러
Event Listener를 이용한 이벤트 핸들러
1~2번의 단점을 보완한 방식이 Event Listener를 이용한 이벤트 핸들러 방식이다.
1. HTML 이벤트 핸들러
HTML 요소의 이벤트 Attribute에 이벤트 핸들러를 대응시키는 방법이다.
1 2 3 4 5
<button onclick="clickBtn()">Click me</button>
function clickBtn() { alert('Button clicked!'); }
옛날 코드를 보게 되면 위와 같은 방식을 사용한 코드가 있다. 그래서 혹시 모를 상황에 대비해 알아둘 필요는 있지만, 현재 이 방식은 사용되지 않고, 사용해서도 안된다. 또한, 이렇게 되면 HTML과 Javascript가 혼용이 되는데, 이 둘은 관심사가 다르기 때문에 같이 사용하는 것을 피해야 한다.
HTML 이벤트 핸들러 내부의 this
HTML 이벤트 핸들러 방식의 경우, 이벤트 핸들러 내부의 this는 window를 가리킨다.
todoList.addEventListener('change', function (e) { toggleTodoComplete(e.target.id); });
var toggleTodoComplete = function (id) { todos = todos.map(function (todo) { return todo.id === +id ? Object.assign({}, todo, { completed: !todo.completed }) : todo; } ); renderTodos(); };
6. Clipboard Event
Event
Description
cut
콘텐츠를 잘라내기할 때
copy
콘텐츠를 복사할 때
paste
콘텐츠를 붙여넣기할 때
copy 이벤트를 사용하는 예제
1 2 3 4 5
document.addEventListener('copy', function(e){ e.clipboardData.setData('text/plain', 'Hello, world!'); e.clipboardData.setData('text/html', '<b>Hello, world!</b>'); e.preventDefault(); // We want our data, not data from any selection, to be written to the clipboard });
Browser안에는 위와 같이 자바스크립트엔진 뿐만 아니라 다른 것들이 같이 포함되어 있다.
자바스크립트엔진(크롬: V8)
Heap과 Stack으로 구성되어있고, 자바스크립트가 브라우저에서 실행되는 곳이 자바스크립트엔진, 정확히는 Stack이다.
Web APIs
비동기 방식으로 호출되는 것들(Timer 함수/DOM Event/Ajax)이 정의되는 영역이다.
Callback Queue
Web APIs으로부터 옮겨와 자바스크립트엔진의 Stack으로 이동하기 위해 기다리는 곳이다.
Event Loop
Callback Queue에서 기다리고 있는 비동기 방식으로 호출되는 것들(Timer 함수/DOM Event/Ajax)을 Stack이 완전히 비어있을 때 이동시키는 역할을 한다.
자바스크립트 기본 특징
자바스크립트는 싱글쓰레드(single-threaded), 즉 1개의 쓰레드를 가지고있다. 1개의 쓰레드를 가지고 있다는 말은 한번에 하나일을 처리한다는 것이다. 자바스크립트엔진의 Stack에서 한번에 하나의 일(함수 호출)을 처리한다는 뜻이다. 그런데, 실제로 자바스크립트 기반의 애플리케이션은 여러가지일이 동시에 일어난다.
왜 그럴까? 이걸 전문적으로 말하면 자바스크립트는 동시성(Concurrency)을 지원한다는 것인데, 어떻게 그럴 수 있을까? 여기서 이벤트루프(Event Loop)에 대한 개념이 나온다.
먼저 동기적(한번에 하나의 일을 처리)으로 작동하는 기본적인 자바스크립트 코드가 돌아가는 원리를 알아보자.
비동기로 호출되는 것들(Timer 함수/DOM Event/Ajax)이 없는 자바스크립트 코드의 경우, 자바스크립트엔진의 Stack에서만 하나씩 호출되어 코드가 돌아간다. 즉, Web AIPs, Callback Queue, 그리고 Event Loop 등을 사용하지 않는다.
아래 동기적 코드를 보자.
1 2 3 4 5 6 7 8 9
function multiply(a, b) { return a*b; } function square(a) { const sq = multiply(a, a);
위 그림과 같이, Stack에서 push로 하나씩 함수가 쌓이고, pop으로 마지막에 쌓인 것부터 하나씩 호출되어 실행되고, 제거된다. 이런식으로, 한번에 하나씩 순서대로 일이 진행되어, 결과값이 나오게 된다. 이게 동기적 방식이다.
Error: Maximum call stack size exceeded
Stack안에 쌓이는 각 함수를 Stack Frame이라고 한다. 보통, 이런 각 Stack Frame은 ms(1초=1000ms)안에 동작이 끝난다. 그런데, Stack에는 Stack Frame의 수가 정해져 있고, 이 수를 넘게되면 에러가 발생하게 된다.
아래 코드를 보자.
1 2 3 4
function foo() { return foo(); } foo();
위 코드를 작성하고 실행하게 되면, 다음과 같은 에러가 발생한다.
1
RangeError: Maximum call stack size exceeded
이 에러의 원인은 Stack안에 정해진 Stack Frame의 수를 초과했다는 뜻이다. 즉, foo 함수가 호출될 때, return 값으로 foo 함수가 호출되기 때문에, 계속해서 호출되게 되고, 그 말은 Stack에 계속해서 foo 함수가 쌓인다는 뜻이다. 그래서 정해진 Stack Frame의 수를 초과하게 되어, 위와 같은 에러가 발생하게 된다. 이런 자바스크립트의 Stack에 대한 개념을 모르게되면, 이 에러가 발생했을 때 해결하기가 어려울 수 있다.
비동기로 호출되는 것들(Timer 함수/DOM Event/Ajax)이 있는 자바스크립트 코드의 경우, 자바스크립트엔진의 Stack에서 Web AIPs로 이동하게 되고, 다시 Callback Queue로 이동하게 된다. 그리고 Stack에 있는 모든 함수가 제거되고 난뒤, Event Loop로 인해 Stack으로 이동되어, 함수가 호출되고 제거된다.
아래 비동기적 코드를 보자.
1 2 3 4 5
console.log("Print this 1st"); setTimeout(() => { console.log("Print this 3rd"); }, 500); console.log("Print this 2nd");
이 코드는 어떤 순서로 호출되어 값이 나오게 될까?
1 2 3
"Print this 1st" "Print this 2nd" "Print this 3rd"
비동기 함수인 setTimeout 함수가 0.5초뒤에 실행되니, 그 전에 마지막 console.log가 먼저 출력되어, 순서가 저렇게 된것일까? 이 과정을 정확하게 위해서는 이벤트루프(Event Loop) 개념을 이해해야 한다.
이 순서를 Architecture에서 확인해보자. 위 코드가 실제로 실행되는 과정은 아래와 같다.
이동한 setTimeout 함수는 Web APIs에서 0.5초(500ms) 동안 있다가, Callback Queue로 이동한다.
Event Loop는 Stack에 있는 모든 함수가 제거된 것을 확인한 후, Callback Queue에 있는 setTimeout 함수를 Stack으로 보내고 실행한다.
그리고, 그 setTimeout 함수는 Stack에서 제거된다.
자바스크립트에서의 비동기적 방식은 위와 같이 진행되기 때문에, 비동기 함수보다 다른 일반 함수들이 먼저 실행되고, 그 다음에 비동기 함수가 진행된다. 결국, 자바스크립트엔진 밖에 있는 Web APIs, Callback Queue, 그리고 Event Loop가 비동기 함수를 따로 관리함으로써 자바스크립트에 동시성이 가능하게 된다. 따라서, 자바스크립트 기반의 애플리케이션은 여러가지 일들이 동시에 발생할 수 있는 것이다.
만약, setTimeout 함수의 두번째 인수가 ‘0’초면 어떻게 될까?
아래 코드를 보자.
1 2 3 4 5
console.log("Print this 1st"); setTimeout(() => { console.log("Print this 3rd"); }, 0); console.log("Print this 2nd");
이 코드는 어떤 순서로 호출되어 값이 나오게 될까?
1 2 3
"Print this 1st" "Print this 2nd" "Print this 3rd"
이 또한 setTimeout 함수의 두번째 인수가 0.5초일때와 동일하게 나온다. 즉, timer 함수의 시간과 상관없이, 이벤트루프는 Stack에 있는 다른 모든 함수가 제거된 뒤, timer 함수를 Stack으로 이동시키기 때문이다. 단지, Wep APIs에서 0.5초 걸리느냐, 0초 걸리느냐에 차이이다.
Ajax는 Asynchronous JavaScript And XML의 약자로, XMLHttpRequest 객체를 이용하여 비동기 방식으로 서버와 통신을 하는 것을 말한다. 웹 브라우저의 클라이언트와 서버간 통신은 url를 이용한 http 통신으로 이루어진다. 즉 브라우저가 서버로 request를 날리기 위해서는 해당 브라우저의 url 주소를 변경하여야 하는데 이때는 페이지 이동이 일어나게 된다. 하지만 ajax 의 경우 브라우저의 url 주소의 변경을 이용하지 않고 내부적으로 통신하여 response 를 받아오기 때문에 특정 데이터만 불러오거나 비동기로 데이터를 불러와야하는 경우 사용된다. 이때 Same Origin Policy 정책으로 인해 cross domain 을 허용하지 않기 때문에 외부 도메인을 사용하여야 하는경우 JSONP, XML 등을 이용하여야 한다.
비동기적이란, 서버에 요청을 하고 그냥 기다리는 것이 아닌, 기다림과 동시에 다른 작업을 할 수 있다는 것을 말한다. Ajax가 가지고 있는 중요 특징은 바로 이 비동기성으로, 서버로부터 웹페이지가 반환될 때, 화면 전체를 갱신하지 않고, 페이지 일부만을 갱신하게 해준다. 즉, 페이지 이동이나 새로고침 없이 페이지 일부만을 갱신할 수 있다. 예를 들어, 사용자가 페이지에서 어떤 이벤트를 발생시키면, 페이지 전체가 아닌 페이지 일부분만을 업데이트해서 보여주기 때문에, 페이지 전체가 Refresh 되지 않아, 사용자가 그 일부의 데이터를 기다리면서, 다른 일을 하여도 문제가 없다.
Ajax를 사용하는 대표적인 애플리케이션이 페이스북 타임라인이다. 페이스북 타임라인을 밑으로 내려가면서 보면, 그 페이스북 페이지 자체는 그대로 있는데, 필요한 타임라인 데이터만 받아올 수 있다. 웹 사이트 중 페이지 전환없이 새로운 데이터를 불러오는 사이트는 대부분 Ajax 기술을 사용하고 있다.
JSON이란?
JSON은 JavaScript Object Notation의 약자로, 클라이언트와 서버간에 데이터를 교환하기 위해 필요한 데이터 포맷을 말한다. 예전에는 데이터 교환을 위한 데이터 포맷으로 XML을 사용했으나, 요즘에는 데이터 구조화도 잘 되어있고, 가볍고 가독성이 좋은 JSON을 사용한다. JSON의 형태는 자바스크립트의 객체 리터럴과 비슷하지만, 순수 문자열로 구성된 규칙이 있는 구조화된 데이터 포맷이다.
JSON의 이름(key)는 반드시 큰따옴표(“”)로 둘러싸야 한다.(작은따옴표(‘’)는 사용이 안된다.)
JSON.parse() & JSON.stringify()
클라이언트와 서버간에 통신을 할때는, JSON 형태, 즉 문자열로 데이터를 주고 받는다. 그러나, 서버로부터 응답받은 데이터를 클라이언트(브라우저)에서 사용하기 위해서는 JSON 형태의 문자열을 객체로 바꿔줘야 한다. 이를 역직렬화(Deserializing)이라고 하는데, 이를 위해서는 내장 객체 JSON의 static 메소드인 JSON.parse()를 사용해야 한다.
이와 반대로, 클라이언트(브라우저)에서 서버로 데이터를 보내기 위해서는 객체를 문자열로 바꿔줘야 한다. 이때는 JSON.stringify()를 사용해야 한다.
Javascript를 이용해서 서버로 보내는 Ajax Request를 만들기 위해서는 XMLHttpRequest 객체를 사용해서 Ajax 요청을 생성하고 전송한다. 서버로부터 응답을 받을때도 XMLHttpRequest 객체를 사용해서 처리한다. 즉, XMLHttpRequest 객체의 프로퍼티 및 메소드를 사용하여 코드를 작성한다.
코드 작성시, 크게 3가지로 나눌 수 있다.
서버로 요청 보내기
서버로 요청보낼때, Request Header 보내기
서버로부터 받은 응답 처리하기
1. Ajax Request 보내기
XMLHttpRequest 객체를 사용해서 Ajax 요청 처리에 대한 코드는 다음과 같다.
1 2 3
var xhr = new XMLHttpRequest(); xhr.open('GET', '/users'); xhr.send();
1-1. XMLHttpRequest 인스턴스 생성
1 2
// XMLHttpRequest 생성자로 xhr 인스턴스를 생성 var xhr = new XMLHttpRequest();
// XMLHttpRequest가 가지고 있는 send 메소드로 요청을 전송 xhr.send();
서버에 요청을 준비하는 단계를 보자.
1
xhr.open('GET', '/users');
이때 HTTP Method로 ‘GET’을 사용하게 되면, URL의 일부분인 query string(쿼리문자열)로 데이터를 서버로 전송하기 때문에, send 메소드에 인수로 데이터를 보낼 필요가 없다. send 메소드에 인수를 Request Body라고 하는데, 이부분이 null이 되어, 무시된다.
이럴 경우, XMLHttpRequest.setRequestHeader() 메소드를 사용해서, HTTP Request Header의 값을 설정해야 한다. 이때, setRequestHeader 메소드는 open 메소드 다음에, send 메소드 전에 호출해야 한다. 다음과 같이 작성하면 된다.
REpresentational State Transfer의 약자로, 서버의 자원을 정의하고, 자원에 대한 주소를 지정하는 방법(표기법)을 말한다. 2000년, 아파치 HTTP 서버 프로젝트의 공동설립자인 Roy fielding(로이 필딩)에 의해 처음 소개가 되었는데, 이 분은 HTTP/1.0,1.1 스펙 작성에 참여하신 분이다.
그는 웹의 장점을 최대한 활용할 수 있는 Architecture로써 REST를 소개하면서, REST API 규칙을 만들었다. 이런 REST API 규칙을 잘 지킨 서비스 디자인을 “RESTful”하다고 표현한다. REST API는 HTPP 프로토콜을 정확히 의도에 맞게 활용하여 디자인하게 유도하기 때문에, 디자인 기준이 명확해지고, 의미적인 범용성을 지닌다. 즉, 서버가 이해하기 쉽게 자원에 대한 주소를 지정하는 표기법이 REST API이다.
REST API 구성 요소
REST API를 구성하는 것은 다음과 같이 3가지가 있다.
자원(Resource)
행위(Verb)
표현(Representation)
자원(Resource)
자원(Resource)이란, 해당 소프트웨어가 관리하는 모든 것이 될 수 있다. JSON, XML 등의 문서가 될 수 있고, 그림파일이 될 수도 있다. 즉, 어떤 데이터(문서, 파일, 비디오 등)를 말한다.
예를 들어, 서버 데이터베이스에 사용자들에 대한 정보가 들어가 있다면, 이 사용자들의 정보가 데이터이기 때문에, 자원(Resource)이 된다. 이때, 이 사용자들에 대한 데이터를 대표하는 이름을 users라고 해보자. 만약, 이 사용자들 중에서 어떤 한 명의 사용자에 대한 자원을 얻고자 한다면 어떻게 해야할까? 그럴때는, users/id 처럼, 사용자들 중 특정 id로 사용자를 구분해서 사용할 수 있다.
자원(Resource)은 HTTP URI로 표현한다. 예를 들어, http://localhost:4000/users/1 이런식으로 작성하며, 이 URI를 이용하여 원하는 자원(Resource)에 접근할 수 있다.
행위(Verb)
REST API에서 말하는 행위(Verb)는 자원에 대한 행위를 말한다. 즉, HTTP Method를 사용해서 자원을 얻거나, 만들거나, 변경하거나, 삭제하는 등의 행위를 할 수 있다.
HTTP Method 중 대표적으로 자주 사용되는 메서드는 다음과 같다.
GET : 서버 자원을 가져오고자 할 때 사용한다.(Retrieve: 모든/특정 자원을 조회)
POST : 서버에 자원을 새로 등록하고자 할 때 사용한다.(Create: 자원을 생성)
PUT : 서버의 자원을 새로 요청한 자원으로 변경하고자 할 때 사용한다.(Update: 자원을 갱신)
표현(Representation)은 자원에 대한 행위의 내용을 말하는데, 이때 내용은 서버에 요청할 때 무엇인가를 새로 생성하거나, 변경할 때 필요한 내용을 말한다. 이때, HTTP Message인 payload를 사용한다.
서버 자원에 무언가 새로운 것을 생성할 때, HTTP Method 중 POST와 함께 payload를 같이 요청한다. 예를 들어, 사용자들에 대한 정보가 있는 users에 새로운 사용자 정보를 생성하고 싶다면, 이 새로운 사용자에 대한 정보를 새로 만들어서 추가해줘야 하는데, 이것을 payload라고 한다.
자바스크립트의 문제점을 보완하기 위해 typescript을 사용한다. 그러나, typescript으로 작성한 파일은 브라우저에서 동작하지 않는다. 따라서, typescript로 작성한 파일을 자바스크립트로 변환해야 하는데, 이를 트랜스파일링 또는 컴파일이라고 한다. 트랜스파일링을 하기 위해서는 typescript 컴파일러를 설치하여 사용하는 typescript 개발환경을 구축해야한다.
typescript 컴파일러 설치 방법
다음과 같이 typescript를 전역에 설치한다.
1
npm install -g typescript
설치가 완료되면, typescript의 버전 체크를 하여, typescript 컴파일러 설치가 제대로 되었는지 확인한다.
1
tsc -v
typescript 컴파일러로 트랜스파일링 하기
typescript로 작성된 파일(.ts)을 자바스크립트 파일로 트랜스파일링 하기 위해서는, 위에서 설치한 typescript 컴파일러(tsc)를 사용한다.
1개의 파일 트랜스파일링 하기
아래의 코드를 작성하고, 확장자를 .ts로 하는 typescript 파일로 만든다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class Cafe { private name: string;
constructor(name: string) { this.name = name; }
greeting() { return "Welcome to" + this.name; } }
const cafe = new Cafe('Starbucks'); console.log(cafe.greeting());
위 typescript 파일을 트랜스파일링하여 자바스크립트로 만들기 위해서는 아래의 명령어를 작성하면 된다.
1
tsc cafe
tsc 다음에 위 파일(cafe.ts)의 이름(cafe)을 입력하면 된다.
그러면, 트랜스파일링이 되어, 또 하나의 자바스크립트 파일이 생성된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
"use strict"; exports.__esModule = true; var Cafe = /** @class */ (function () { function Cafe(name) { this.name = name; } Cafe.prototype.greeting = function () { return "Welcome to" + this.name; }; return Cafe; }()); exports.Cafe = Cafe; var cafe = new Cafe('Starbucks'); console.log(cafe.greeting());
그런데, 트랜스파일링된 자바스크립트 파일은 ES3 버전으로 생성되는데, 이는 트랜스파일링해서 생성되는 기본 버전이 ES3이기 때문이다.
target 컴파일 옵션을 사용해서 원하는 버전으로 트랜스파일링 하기
만약 원하는 버전으로 트랜스파일링 하고 싶다면, typescript 컴파일 옵션중 –target또는 -t를 사용하면 된다.
typescript는 자바스크립트에서 좀 더 확장된 언어로, 자바스크립트의 문법을 포함하면서 자바스크립트가 가지고 있는 문제를 보완하기 위한 문법을 가진 언어이다. 2012년에 마이크로소프트에서 발표한 오픈소스로써, C#을 개발한 아네르스 하일스베르가 개발하였다.
위 그림과 같이, 타입스크립트는 ES5, ES6를 모두 포함하는 자바스크립트의 상위집합이기 때문에, 타입스크립트에서 기존의 자바스크립트 문법을 그대로 사용할 수 있다.
또한, 타입스크립트는 아직 ECMAScript 표준에 포함되지는 않았지만(2018년 7월 기준), ECMAScript의 업그레이드에 따른 새로운 기능(스펙)을 계속 추가하기 때문에, ECMAScript의 표준을 따라가는 것처럼 보인다.
typescript를 왜 사용할까?
C나 JAVA와 같은 C-family 언어와는 다른 자바스크립트만의 특성이 있다.
프로토타입 기반 객체지향 언어
스코프와 this
동적 타입 언어
이와 같은 특성들은 클래스 기반 객체지향 언어(C, JAVA 등)에 익숙한 개발자에게는 혼란스럽다. 또한, 할당하는 값에 따라 타입이 바뀌는 문제도 있어, 꼭 타입 체크를 해줘야 하는 점도 있다.
이런 문제들을 보완하기 위해, 타입스크립트에는 클래스, 정적 타이핑 등이 포함되어있다.
자바스크립트의 프레임워크인 Angular는 주력 언어로 타입스크립트를 채용했기 때문에, Angular를 사용하는 개발자는 타입스크립트를 이해하는 것이 필수적이다. 즉, Angular는 타입스크립트 뿐만 아니라, 자바스크립트, Dart 등으로도 작성이 가능하지만, Angular 사이트에 나와있는 문서나 커뮤니티 활동에서도 가장 많이 사용되고 있어, Angular를 사용하고 싶다면 타입스크립트를 아는 것이 좋다.
이 명령어를 작성하게 되면, 글제목 폴더와 글제목.md 파일이 만들어진다. 이미지는 글제목 폴더에서 관리하고, 글의 내용은 글제목.md 파일에서 관리한다. 만약, 글제목 폴더가 만들어지지 않는다면, _config.yml에서 post_asset_folder: true를 추가하면 된다.
이때, option에는 ‘post’ 또는 ‘draft’가 올 수 있다.
만약 작성한 글을 바로 배포하려면 ‘post’라고 쓴다.
1
hexo new post 글제목
바로 배포하지 않고, 초안으로 보관만 하려고 할 때는 ‘draft’라고 쓴다.
1
hexo new draft 글제목
draft 글을 배포하기 위해서 _posts 폴더로 이동시킨다.
‘draft’를 사용하여 명령어를 입력하게 되면, source/_drafts 폴더에 저장된다. 이 폴더에 저장이 되면, 배포 대상에서 제외되기 때문에, 원래 사용하던 ‘hexo server’로는 확인할 수 없고 ‘–draft’라는 옵션을 추가해여 로컬 서버에서 확인이 가능하다.
1
hexo server --draft
초안이 다 완성이 되어 배포를 하고 싶을 경우, 해당 파일과 폴더가 source/_posts 폴더에 있어야 한다. 이때, 아래와 같은 명령어를 입력하면 해당 파일과 폴더과 source/_posts로 이동하게 된다.
1
hexo publish post 글제목
_posts 폴더에 있는 글을 블로그에 배포한다.
최종적으로, source/_posts안에 있는 모든 글들을 배포하기 위해 아래의 명령어를 입력한다.
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.