Front-end Developer

0%

REST(Representational State Transfer)

2000년도에 로이 필딩 (Roy Fielding)의 박사학위 논문에서 최초로 소개된 개념

  • REST: HTTP를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처
  • REST API: REST를 기반으로 서비스 API를 구현한 것

REST API의 구성

  • 자원(RESOURCE) - URI
  • 행위(Verb) - HTTP METHOD
  • 표현(Representations) - 페이로드

REST API 설계 원칙

  1. 자원의 위치를 나타내는 URI는 리소스를 표현해야 한다. 리소스를 식별할 수 있는 이름은 명사형으로 사용한다.
  2. 리소스에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다. 클라이언트가 서버에게 요청의 종류와 목적(리소스에 대한 행위)를 알리는 방법을 말한다.
1
2
3
4
5
6
7
8
URI는 리소스를 표현하는 데 중점을 두고 있으므로 명사형으로 명시
`delete`처럼 리소스에 대한 행위를 표현하면 안된다.

GET /weathers/delete/1 -> X

리소스에 대한 행위는 가장 앞에 있는 `GET`과 같은 HTTP Method로
어떠한 행위를 할 것인지를 표현한다.
GET /weathers/1 -> O
  1. HTTP Method(GET, POST, PUT, DELETE)
    리소스에 대한 정의는 다음의 HTTP 요청 메소드를 이용하여 CRUD를 한다. CRUD는 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말이다. 사용자 인터페이스가 갖추어야 할 기능(정보의 참조/검색/갱신)을 가리키는 용어로서도 사용된다.

    | HTTP Method | 종류 | 목적 | 페이로드 |
    | :————-: | :——————: | :———————: | :———: |
    | GET | index/retrieve | 리소스 조회/취득 | X |
    | POST | create | 리소스 생성 | O |
    | PUT | replace | 리소스 전체교체 | O |
    | PATCH | update | 리소스 일부 수정 | O |
    | DELETE | delete | 리소스 삭제 | X |

URI 설계 시 주의사항

  1. 슬래시(/)는 계층 관계를 나타낼 때 사용
  2. URI 마지막 문자로 슬래시(/)를 포함하지 않는다.
  3. 하이픈(-)은 URI 가독성을 높이는데 사용
  4. 밑줄(_)은 URI에 사용하지 않는다.
  5. URI 경로에는 소문자가 적합하다.
  6. 파일 확장자는 URI에 포함시키지 않는다.

리소스 간의 관계를 표현

/리소스명/리소스 ID/관계가 있는 다른 리소스명

ex) GET : /users/{userid}/devices
(일반적으로 소유 ‘has’의 관계를 표현할 때)

서브 리소스에 명시적으로 표현
ex) GET : /users/{userid}/likes/devices
(관계명이 애매하거나 구체적 표현이 필요할 때)

자원을 표현

컬렉션과 도큐먼트로 URI에 표현

  • Collection: 문서 또는 객체들의 집합. 컬렉션은 복수형으로 사용
  • Document: 문서

ex) http_://restapi.example.com/sports(collection)/soccer(Document)/players(collection)/13(Document)

HTTP 응답 상태 코드

  1. 정상적인 수행
    200: 클라이언트의 요청을 정상적으로 수행함.
  2. 클라이언트 에러 응답
    404: 요청받은 리소스를 찾을 수 없음.
  3. 서버 에러 응답
    500: 서버가 처리 방법을 모르는 상황. 서버에 문제가 있다.
  4. 리다이렉션
    301: 요청한 리소스의 URI가 변경되었음

References
TOAST
CRUD
MDN
poiemaweb

Ajax(Asynchronous Javascript And XML)

자바스크립트를 사용하여 브라우저가 서버에게 비동기 방식으로 데이터를 요청, 서버가 응답한 데이터를 수신하여 웹페이지를 동적으로 갱신하는 프로그래밍 방식. 서버와 통신하기 위해 XMLHttpRequest 객체를 사용하는 것.

이전 웹페이지는 완전한 HTML을 서버로부터 전송받아 웹페이지 전체를 처음부터 렌더링하는 방식으로 동작했다. 따라서 화면이 전환되면 또 웹페이지 전체를 처음부터 다시 렌더링하게 된다. 이렇게 되면 굳이 변경할 필요가 없는 부분도 서버로부터 전달받는 불필요한 데이터 통신이 발생하고, 화면의 순간적으로 깜빡거리는 현상이 발생한다. 또한 서버로부터 응답을 받기 전까지 블로킹되는 문제가 발생한다. Ajax가 등장하면서 굳이 데이터를 변경하지 않아도 되는 부분은 그대로 두고, 서버에서 필요한 데이터만 전송받아 변경이 필요한 부분만 렌더링할 수 있고, 화면의 전환도 부드러워졌다.

JSON(JavaScript Object Notation)

javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반 표준 포맷으로 웹 어플리케이션에서 데이터를 전송할 때 일반적으로 사용한다.

클라이언트와 서버 간의 HTTP 통신을 위한 텍스트 데이터 포맷
객체 리터럴처럼 키와 값으로 구성된 순수한 텍스트

  • 키는 반드시 큰따옴표로 묶어야 한다.
  • 값도 문자열인 경우 반드시 큰따옴표로 묶어야 한다.
  • 순수한 데이터 포맷이므로 프로퍼티만 담을 수 있고, 메서드는 담을 수 없다.

JSON parse() / stringify()

request.responseType = ‘json’;

위와 같이 응답 타입이 json이면 편리하지만 json 문자열을 그대로 받아서 객체로 변환시키거나, 네트워크에 전송할 때 객체를 JSON 타입으로 변환시켜야 하는 경우가 흔하다. 이는 아래와 같은 방법으로 변환한다.

JSON.parse

서버 -> JSON 데이터(문자열) -> 클라이언트 -> JSON.parse(역직렬화) -> 객체(화)

JSON 문자열을 매개변수로서 수용하고, 일치하는 자바스크립트 객체로서 변환.

JSON.stringify

클라이언트 -> 객체 -> JSON.stringify(직렬화) -> 문자열 -> 서버

stringify(): 객체를 매개변수로서 수용하고, JSON 문자열 형태로 변환.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const obj = { name: "lee", job: "web developer" };
console.log(typeof obj); // object

// 객체를 문자로 변환
const objToJson = JSON.stringify(obj);
console.log(typeof objToJson, objToJson);
// string {"name":"lee","job":"web developer"}

const json = objToJson;
console.log(typeof objToJson, objToJson);
// string {"name":"lee","job":"web developer"}

//문자를 객체로 변환
const jsonToObj = JSON.parse(objToJson);
console.log(typeof jsonToObj, jsonToObj);
// object {name: "lee", job: "web developer"}

XMLHttpRequest

XMLHttpRequest -> XMLHttpRequestEventTarget -> EventTarget

브라우저는 주소창이나 HTML의 form 태그 또는 a 태그를 통해 HTTP 요청 전송 기능을 기본 제공한다. 자바스크립트를 사용하여 HTTP 요청을 전송하려면 XMLHttpRequest 객체를 사용한다. XHR 객체는 서버와 상호작용하기 위해 사용되므로, 전체 페이지의 새로고침 없이도 URL로부터 데이터를 받아 올 수 있다.

  1. XMLHttpRequest 객체 생성

const xhr = new XMLHttpRequest();

생성자는 XMLHttpRequest 를 초기화하며, 다른 모든 메소드 호출 이전에 호출되어야 한다.

  1. HTTP 요청 전송

XMLHttpRequest.prototype.open

  • xhr.open(요청메서드, 요청을 전송할 url, 비동기요청여부 - 기본값 true)
  • XMLHttpRequest.prototype.open 메서드로 HTTP 요청을 초기화한다.
  • 필요에 따라 XMLHttpRequest.prototype.setRequestHeader 메서드로 특정 HTTP 요청의 헤더 값을 설정한다.

XMLHttpRequest.prototype.send

XMLHttpRequest.prototype.send 메서드로 HTTP 요청을 전송한다.

  • GET: 데이터를 URL의 일부분인 쿼리 문자열(query string)로 서버에 전송
  • POST: 데이터(페이로드)를 요청 몸체(request body)에 담아 전송
  • GET, DELETE는 페이로드 X
  • POST, PUT, PATCH는 페이로드 O
  • 페이로드가 개체일 경우 반드시 JSON.stringify를 사용한 후 전달한다.

XMLHttpRequest.prototype.setRequestHeader

특정 HTTP 요청의 헤더 값을 설정한다. setRequestHeader 메서드는 반드시 open 메서드를 호출한 이후에 호출

  1. HTTP 응답 처리
    XMLHttpRequest 객체가 발생시키는 이벤트를 캐치하여 처리하는데, send 메서드를 통해 서버에 전달된 HTTP 요청이 서버로부터 클라이언트에 언제 도달할 지 알 수 없으므로 이벤트를 캐치하여 현재 상태를 확인해야 한다.
    • readystatechange 이벤트: HTTP 요청의 현재 상태를 나타내는 readyState 프로퍼티 값이 변경된 경우 발생
    • onload 이벤트: HTTP 요청이 성공적으로 완료된 경우 발생한다. 따라서 load 이벤트를 캐치하는 경우 xhr.readyState가 XMLHttpRequest.DONE인지 확인할 필요가 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// {...}
xhr.onreadystatechange = () => {
// readyState 프로퍼티는 HTTP 요청의 현재 상태를 나타낸다.
// readyState 프로퍼티 값이 4(XMLHttpRequest.DONE)가 아니면 서버 응답이 완료되지 상태다.
// 만약 서버 응답이 아직 완료되지 않았다면 아무런 처리를 하지 않는다.
if (xhr.readyState !== XMLHttpRequest.DONE) return;

// status 프로퍼티는 응답 상태 코드를 나타낸다.
// status 프로퍼티 값이 200이면 정상적으로 응답된 상태이고
// status 프로퍼티 값이 200이 아니면 에러가 발생한 상태다.
// 정상적으로 응답된 상태라면 response 프로퍼티에 서버의 응답 결과가 담겨 있다.
if (xhr.status === 200) {
console.log(JSON.parse(xhr.response));
// {userId: 1, id: 1, title: "delectus aut autem", completed: false}
} else {
console.error("Error", xhr.status, xhr.statusText);
}
};

// load 이벤트는 HTTP 요청이 성공적으로 완료된 경우 발생한다.
xhr.onload = () => {
// status 프로퍼티는 응답 상태 코드를 나타낸다.
// status 프로퍼티 값이 200이면 정상적으로 응답된 상태이고
// status 프로퍼티 값이 200이 아니면 에러가 발생한 상태다.
// 정상적으로 응답된 상태라면 response 프로퍼티에 서버의 응답 결과가 담겨 있다.
if (xhr.status === 200) {
console.log(JSON.parse(xhr.response));
// {userId: 1, id: 1, title: "delectus aut autem", completed: false}
} else {
console.error('Error', xhr.status, xhr.statusText);
}

References
MDN
MDN
MDN
poiemaweb

호출 스케줄링

함수를 명시적으로 호출하지 않고, 일정 시간이 경과된 이후 호출되도록 타이머 함수를 사용하여 함수 호출을 예약한다.

  • 타이머를 생성할 수 있는 함수: setsetTimeout,setInterval
    • 일정 시간이 경과된 이후 콜백 함수가 호출되도록 타이머 생성. 생성된 타이머가 만료되면 콜백함수가 호출됨.
    • setTimeout: 이 함수가 생성한 타이머는 단 한번동작. 타이머 만료시 단 한번호출.
    • setInterval: 이 함수가 생성한 타이머는 반복 동작. 타미어 만료될 때마다 반복호출.
  • 타이머를 제거할 수 있는 함수: clearTimeout, clearInterval

setTimeout()

지정된 시간이 경과 한 후 특정 코드 블록을 한 번 실행.

  • 필요한 파라미터

    • 실행할 함수 또는 다른 곳에 정의 된 함수 참조.
    • 코드를 실행하기 전에 대기 할 밀리세컨드 단위의 시간 간격 (1000밀리세컨드는 1 초)을 나타내는 숫자. 값을 0으로 지정하면(혹은 이 값을 모두 생략하면) 함수가 즉시 실행된다.
    • 함수가 실행될 때 함수에 전달해야할 파라미터를 나타내는 0이상의 값.
  • 매개변수
    setTimeout () 내에서 실행되는 함수에 전달하려는 모든 매개변수는 setTimeout () 매개변수 목록 끝에 추가하여 전달해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 익명함수 실행
let myGreeting = setTimeout(function () {
alert("Hello, Mr. Universe!");
}, 2000);

// setTimeout()에 함수 참조를 전달.
// timeout 함수와 이벤트에 의해 중복 호출되는 함수를 사용하려면 이 방법이 유용할 수 있다.
// 이 방법은 코드라인을 깔끔하게 정리하는 데 도움을 준다.

// With a named function
let myGreeting = setTimeout(function sayHi() {
alert("Hello, Mr. Universe!");
}, 2000);

// With a function defined separately
function sayHi() {
alert("Hello Mr. Universe!");
}

let myGreeting = setTimeout(sayHi, 2000);

clearTimeout()

타임아웃이 생성되면(setTimeout()이 실행되면) 특정시간이 경과하기 전에 clearTimeout()을 호출하여 타임아웃을 취소할 수 있다. clearTimeout()은 setTimeout()콜의 식별자를 매개변수로 setTimeout()에 전달한다.


setInterval()

지정된 시간이 경과 후, 두 번째 매개 변수에 주어진 시간까지 반복적으로 실행됨.

1
2
3
4
5
6
7
function displayTime() {
let date = new Date();
let time = date.toLocaleTimeString();
document.getElementById("demo").textContent = time;
}

const createClock = setInterval(displayTime, 1000);

clearInterval()

위와 같이 별다른 중지 사항을 명시하지 않으면 계속 반복해서 실행됨. 아래와 같이 setInterval()에 의해 반환된 식별자를 clearInterval()에 전달하여 작업을 취소할 수 있다.

1
2
3
4
5
6
7
8
9
10
function displayTime() {
let date = new Date();
let time = date.toLocaleTimeString();
document.querySelector(".clock").textContent = time;
}

displayTime();
const createClock = setInterval(displayTime, 1000);
// clearInterval 사용 시 setInterval 작업 취소
clearInterval(createClock);

Preferences
poiemaweb
MDN

프로그래밍

컴퓨터에게 실행을 요구하는 일종의 커뮤니케이션

프로그래밍 언어: 컴퓨터가 이해할 수 있는 언어(기계어)

사람 -> 프로그래밍 언어 -> 기계어 -> 컴퓨터
리터럴 -> 자바스크립트 -> 인터프리터(정적언어는 컴파일러)-> 2진수 변환 -> 메모리에 저장

자바스크립트

시작: 넷스케이프 커뮤니케이션즈가 웹페이지의 보조적인 기능을 수행하기 위해 브라우저에서 동작하는 경량 프로그래밍 언어를 개발 -> 브랜던 아이크의 자바스크립트: 모카로 명명

표준화
MS에서도 자바스크립트의 파생버전 JScript를 개발하면서 넷스케이프와 경쟁구도. 자사 브라우저에서만 작동하는 기능을 추가하기 시작하면서 호환되지 않는 문제가 생겨남(크로스 브라우징 이슈). 따라서 표준화에 대한 필요성 대두.

ECMAScript
1997: 표준화된 자바스크립트 초판(ECMAScript 1) 사양(specification)이 완성되었고, 상표권 문제로 자바스크립트는 ECMAScript로 명명
1999: ECMAScript 3(ES3)
2009: ECMAScript 5(ES5)는 HTML5와 함께 출현한 표준 사양
2015: ECMAScript 6(ECMAScript 2015, ES6)는 let/const 키워드, 화살표 함수, 클래스, 모듈 등과 같이 범용 프로그래밍 언어로서 갖춰야 할 기능들을 대거 도입


자바스크립트의 발전 과정

렌더링 -> AJAX(XMLHttpRequest) -> jQuery -> V8 -> Node.js -> 프레임 워크

초창기는 웹페지이의 보조기능을 수행하면서 브라우저에 단순 렌더링하는 역할, AJAX의 등장으로 비동기 처리가 가능해지면서 성능이 빨라지고 화면전환이 부드러워짐.

HOW?

  • 기존방식: <html></html>의 완전한 html을 서버에서 전송받아 웹페이지 전체를 렌더링, 화면 전환 시 이 과정이 처음부터 다시 이루어지면서 화면이 깜빡이는 현상이 발생.
    불필요한 데이터 통신, 성능도 좋지 않음.

  • AJAX: 변경필요 없는 부분은 그대로 두고, 서버에서 필요한 데이터만 전송받아 변경이 필요한 부분만 렌더링.

JQuery
DOM을 쉽게 제어할 수 있고, 크로스 브라우징 이슈도 해결. 배우기 쉽고 직관적.

V8 자바스크립트 엔진
구글에서 개발. 자바스크립트가 웹 어플리케이션 개발 프로그래밍 언어로 정착하게 함. 웹 서버에서 수행되던 로직이 클라이언트 사이드로 이동.

Node.js
라이언 달. V8로 빌드된 자바스크립트 런타임 환경. 브라우저의 자바스크립트 엔진에서만 동작하던 js를 다른 환경에서도 동작할 수 있도록 함.

프레임워크
Angular, React, Vue.js, Svelte 등

ECMAScript: 자바스크립트의 표준 사양인 ECMA-262를 말하며, 프로그래밍 언어의 값, 타입, 객체와 프로퍼티, 함수, 표준 빌트인 객체(standard built-in object) 등 핵심 문법을 규정

javascript: 웹 브라우저에서 동작하는 유일한 프로그래밍 언어. 인터프리터 언어.


  • ECMAScript: core역할, 표준화, spec관리 등등.
  • Node.js: host APIs(server-side javascript). 브라우저 외부에서 js 개발 환경을 제공하는 것이 주된 목적. DOM api 제공 안함. 파일을 create/read/update/delete할 수 있는 파일 시스템을 기본 제공.
  • javascript: client-side. 화면 렌더링이 주된 목적. DOM api 제공. 파일을 create/read/update/delete할 수 있는 파일 시스템을 기본 제공안함.

변수

  • 변수 선언: 값을 저장하기 위한 메모리 공간을 할당, 주소값을 연결하여 값을 저장할 수 있도록 한다.
  • 초기화: 선언 후 값을 할당하지 않았을 때 undefined가 암묵적으로 할당된다.

변수 호이스팅
변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작. 런타임 이전에 변수 선언문을 찾아 실행한 후 런타임 때 할당이 이루어짐.

1
2
console.log(result); //undefined
var result;

할당 할 때, undefined로 초기화 된 값을 지운 후 그 자리에 값을 할당하는 것이 아니라, 새로운 메모리 공간을 확보한 후 그 곳에 값을 저장한다. 재할당의 경우도 마찬가지이다. 재할당이 이루어지면 기존의 변수는 가비지 컬렉터에 의해 언젠가 메모리 해제된다.

식별자 네이밍 규칙

  • 변수나 함수의 이름: 카멜 케이스를 사용. (ex. var firstName;)
  • 생성자 함수, 클래스의 이름: 파스칼 케이스를 사용 (ex. var FirstName;)

표현식과 문

표현식
값으로 평가될 수 있는 문. 표현식이 평가되면 값을 생성하거나 참조한다.
become a value. 값이 생성되거나 문의 일부가 될 수 있다.


perform action. 값이 생성되지 않고, 실행문이나 코드블록의 action을 컨트롤할 뿐이다.
프로그램을 구성하는 기본 단위, 최소 실행 단위. 여러 토큰들로 구성된다. 특정 액션을 수행하는 역할을 한다.문은 반드시 세미콜론으로 끝나야 하는데, 중괄호로 묶은 코드 블록 뒤에는 세미콜론을 붙이지 않는다. ex. if문, for문, 함수 등)

1
2
3
4
문: 실행되거나 특정한 action을 수행할 수 있는 코드의 조각을 말한다.
표현식: 평가되어 값을 생성할 수 있는 코드의 조각을 말한다.
표현식인 문: 값으로 평가될 수 있는 문. ex.변수 할당문
표현식이 아닌 문: 값으로 평가될 수 없는 문 ex.변수 선언문

데이터 타입

원시타입 / 객체 타입

데이터 타입은 메모리 공간을 확보하고 참조하기 위해 필요하다. 변수에 할당되는 값의 데이터 타입에 따라 확보해야 할 메모리 공간의 크기가 결정되기 때문이다.

  • 정적 타입: 명시적으로 어떤 타입인지 사전에 선언해야 하고, 컴파일 시점에 타입체크를 수행한다.

  • 동적 타입: 값을 할당하는 런타임에 변수의 타입이 결정되고, 언제든지 변경할 수 있다.

reverseString Pseudocode

  1. string를 배열로 만든다.
  2. 배열 method를 사용하면 array 내부의 요소의 순서를 뒤집는다.
  3. 순서가 뒤집힌 배열을 다시 string로 변환한다.

example
“hello” -> [‘h’, ‘e’, ‘l’, ‘l’, ‘o’] -> [‘o’, ‘l’, ‘l’, ‘e’, ‘h’] -> ‘olleh’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function reverse(str) {
console.log(str); //hello

const splits = str.split("");
console.log(splits); // ["h", "e", "l", "l", "o"]

const reversed = splits.reverse();
console.log(reversed); // ["o", "l", "l", "e", "h"]

const result = reversed.join("");
console.log(result); //olleh

return result;
}

reverse("hello");

split()

str.split([separator[, limit]])

string을 구분자를 이용하여 여러 개의 문자열로 나눈다.

  • 매개변수: separator, limit 두 가지를 전달할 수 있다.
    • separator: 끊어야 할 부분을 나타내는 문자열로 실제 문자열이나 정규표현식을 받을 수 있다.
    • limit: 끊어진 문자열의 최대 개수를 나타낸다. limit이 존재하면, 배열의 원소가 limit개가 되었을 때 split메소드가 중지된다.
  • 반환값: 원본 문자열을 separator마다 끊은 문자열의 결과를 담은 배열을 반환한다.

    • separator가 빈문자열(‘’)일 때: 원본 문자열을 한 글자씩 분리한 배열이 반환됨.
    • separator가 공백이 있는 문자열(‘ ‘)일 때: 원본 문자열을 공백으로 구분한 배열이 반환됨.
    • separator로 아무것도 주어지지 않았을 때: 원본 문자열 전체를 담은 배열이 반환됨.
1
2
3
4
5
6
7
8
9
10
11
12
const hi = "hello there";
hi.split(); // ['hello there']
hi.split(""); // ['h', 'e', 'l', 'o', 'o', 't', 'h', 'e', 'r', 'e']
const result = hi.split(" "); // ['hello', 'there']
console.log(result[1]); // there
hi.split(" ", 3); // ['h', 'e', 'l']

// 정규 표현식 사용
var myString = "Hello 1 word. Sentence number 2.";
var splits = myString.split(/(\d)/);

console.log(splits); // [ "Hello ", "1", " word. Sentence number ", "2", "." ]

reverse()

a.reverse()

배열의 순서를 반전하고, 반환값은 순서가 반전된 배열이다.

join()

배열의 모든 요소를 하나의 문자열로 만든다.

arr.join([separator])

  • 매개변수: separator. 배열의 각 요소를 구분할 문자열을 지정한다.
    • separator가 빈문자열(‘’)일 때: 공백이 구분되지 않은 문자열이 반환됨.
    • separator가 공백이 있는 문자열(‘ ‘)일 때: 단어 간 공백이 있는 문자열이 반환됨.
    • separator로 아무것도 주어지지 않았을 때: 쉼표(,)로 구분된 문자열이 반환됨.
    • separator로 특정 문자가 주어졌을 때: 특정 문자가 삽입된 문자열이 반환됨.
  • 반환값: 배열의 모든 요소를 연결한 하나의 문자열 반환. arr.length가 0이면 빈 문자열 반환되고, 요소가 undefined나 null이면 빈 문자열로 변환됨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const elements = ["Fire", "Air", "Water"];

console.log(elements.join());
// expected output: "Fire,Air,Water"

console.log(elements.join(""));
// expected output: "FireAirWater"

console.log(elements.join(" "));
// expected output: "Fire Air Water"

console.log(elements.join("-"));
// expected output: "Fire-Air-Water"

const emptyArray = [];
emptyArray.join(); //''

const nullInArray = [null];
nullInArray.join(); //''

const undefinedInArray = [undefined];
undefinedInArray.join(); //''

method chaining

return str.split(“”).reverse().join(“”);

이렇게 method를 연결하여 한줄로 구현할 수도 있지만, 문자열에 grapheme clusters가 있을 경우, 유니코드 플래그를 설정해도 오류를 일으킬 수 있어서 esrever 등의 라이브러리를 쓰는 것이 권장된다.


만약 reverse()를 쓰지 않고 reverseString를 구현해야 한다면?

  1. for문을 이용
1
2
3
4
5
6
7
8
9
10
function reverse(str) {
let res = "";

for (let i = 0; i < str.length; i++) {
const char = str[i];
res = char + res;
}
return res;
}
reverse("hello");

argument로 전달된 ‘hello’의 length는 5이고, 총 5번 반복문을 돈다. 원리는 다음과 같다. ‘hello’가 있다면, h를 캐치하여 res의 첫번째 요소로 보내고, 그 다음 e를 캐치하여 res의 첫 번째 요소로 보낸다. 이를 구현하기 위해 res = char + res;로 코드를 구현한다. 이 코드에 따라 hello가 ‘olleh’가 될 때까지 반복문을 돈다.

‘hello’ + ‘’
‘ello’ + ‘h’
‘llo’ + ‘eh’
‘lo’ + ‘leh’
‘o’ + ‘lleh’
‘’ + ‘olleh’

  • 1회차
    char = h;
    res = h + ‘’ -> h가 된다.
  • 2회차
    char = e;
    res = e + h -> eh가 된다.
  • 3회차
    char = l;
    res = l + eh -> leh가 된다.
  • 4회차
    char = l;
    res = l + leh -> lleh가 된다.
  • 5회차
    char = o;
    res = lleh + 0 -> olleh가 된다.
  1. reduce method 이용하기
1
2
3
4
5
6
function reverse(str) {
return str.split("").reduce((output, char) => {
output = char + output;
return output;
}, "");
}

reduce()

arr.reduce(callback[, initialvalue])
[0,1,2,3,4].reduce(function(accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue;
});

배열의 각 요소에 대해 주어진 reduce 함수를 실행하고, 결과값을 반환한다. reduce함수는 아래와 같이 네 개의 인자를 가지는데, 함수의 반환 값은 누산기에 할당되고, 누산기는 순회 중 유지되고, 최종 결과는 하나의 값이 된다. 이때 원본 배열은 변경되지 않는다. accumulator, currentValue를 제외한 나머지 매개변수는 option이다.

  1. 누산기 accumulator (acc)
    콜백의 반환값을 누적한다.
  2. 현재 값 currentValue (cur)
    처리가 필요한 현재 요소
  3. 현재 인덱스 currentIndex (idx)
    처리할 현재 요소의 인덱스. initialValue가 있으면 0 혹은 1로 시작.
  4. 원본 배열 array (src)
    reduce()를 호출한 배열.
  • initialValue

callback의 최초 호출에서 첫 번째 인수에 제공하는 값. 빈 배열에서 초기값 없이 reduce()를 호출하면 오류가 발생한다.

  • initialValue가 있는 경우: 인덱스 0에서 시작. accumulator = initialValue(콜백의 최초 호출 시)
  • initialValue가 없는 경우: 인덱스 1에서 시작, 첫 번째 인덱스는 건너뛴다.

    • accumulator !== initialValue
    • accumulator = array[1]
    • accumulator = currentValue의 두 번째 값
  • 반환 값: 누적 계산의 결과 값이다.

    • initialValue가 없는 경우 반환값
      • 빈 배열에서 reduce()를 사용하면 TypeError 발생
      • 배열의 요소가 1개: 위치와 상관없이 단독 값을 callback 호출 없이 반환
    • initialValue가 있는 경우 반환값
      • initialValue가 있는데 빈 배열이 주어졌을 때 단독 값을 callback 호출 없이 반환
1
2
3
4
5
6
var maxCallback = (acc, cur) => Math.max(acc.x, cur.x);

// initialValue 없이 reduce()
[].reduce(maxCallback); // TypeError
[{ x: 22 }].reduce(maxCallback); // { x: 22 }
[{ x: 22 }, { x: 42 }].reduce(maxCallback); // 42

reduce() 작동 방식

1
2
3
4
5
6
7
8
9
10
11
[0, 1, 2, 3, 4].reduce(function (
accumulator,
currentValue,
currentIndex,
array
) {
return accumulator + currentValue;
});

// 화살표 함수를 사용
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr);
1
2
3
4
5
6
7
8
function reverse(str) {
return str.split("").reduce((output, char) => {
output = char + output;
return output;
}, "");
}

reverse("hello");

위의 함수는 아래의 구조와 같고, 아래와 같이 작동한다.

1
2
3
4
5
6
7
8
function reverse(str) {
const array = str.split(""); // ["h", "e", "l", "l", "o"]
return array.reduce((output, char) => {
// return ["h", "e", "l", "l", "o"].reduce((output, char) => {
output = char + output;
return output;
}, "");
}

구체적인 작동방식을 살펴보면 아래와 같다.

  1. initialValue:””가 주어져 있으므로, index 0에서 시작한다.
  2. 주어진 array는 [“h”, “e”, “l”, “l”, “o”]이다.
  3. callback은 주어진 array의 length만큼 호출된다. 예제인 [“h”, “e”, “l”, “l”, “o”]의 경우 length는 5이다.
  4. 반환값은 accumulator에 할당 되고 순회하면서 accumulator + currentValue의 연산이 이루어진 최종값이 반환된다. 예제의 경우 최종적으로 반환되는 값은 olleh이다.
callback accumulator currentValue currentIndex return
1번 째 “” h 0 h
2번 째 h e 1 eh
3번 째 eh l 2 leh
4번 째 leh l 3 lleh
5번 째 lleh o 4 olleh

Preferences
Array.protorype.split()/MDN
Array.prototype.reverse()/MDN
Array.prototype.join()/MDN
Array.prototype.reduce()/MDN
KodingKevin

브라우저 structure

browser components
[사진출처 - html5rocks]

  1. user interface: 유저가 볼 수 있는 모든 것. 요청한 페이지가 표시되는 창을 제외한 모든 부분(주소창, 책갈피 메뉴 등)을 말한다. 유저는 함부로 조작할 수 없고, ui backend와 함꼐 일한다.

  2. browser engine: 유저 인터페이스와 렌더링 엔진 사이의 mediator

    • 브라우저에서 새로고침을 누르면 브라우저 엔진은 명령을 실행하고 웹페이지를 새로 렌더링한다.
  3. rendering engine: 요청된 컨텐츠를 parse하여 화면에 렌더링한다.

  • networking: https나 http 요청을 하는 부분으로 networking layer 리소스가 로드되어 있는지 확인한다.
  • javasscript interpreter: javascript 코드를 parse하고 실행한다.
  • ul backend: basic widgets를 그리는 데 사용된다.
  1. data persistence: 자료를 저장하는 layer이다. 쿠키와 같은 모든 종류의 데이터를 로컬에 저장하거나 localStorage, IndexedDB, WebSQL 및 FileSystem과 같은 스토리지 메커니즘을 지원한다.

이처럼 브라우저는 굉장히 많은 layer로 구성되어 있으나 렌더링 엔진에만 주목하여 렌더링 과정을 살펴보려 한다. 기본 렌더링 엔진 플로우는 다음과 같다.

브라우저의 렌더링 flow

parsing -> render tree -> layout -> paint

유저가 웹사이트를 열면 렌더링 엔진이 먼저 시작되고 파싱된다. 파싱이 끝나면 트리가 렌더되고, 트리도 렌더링이 끝나면 레이아웃이 실행된다. (브라우저에 따라서 레이아웃 혹은 리플로우라고 부른다.) 참고로 렌더 트리는 rectangles을 포함하는데 이는 색상, 치수 등의 visual attributes를 포함하는 것이며, 화면에 표시되는 올바른 순서를 의미한다. 레이아웃은 각 노드에게 화면에 표시 될 정확한 좌표를 제공한다는 의미이다. 이 단계를 거쳐 마지막으로 paint라는 단계에서 렌더 트리가 순회되고, 각 노드가 ul backend layer를 사용하여 painting된다. 이렇게 모든 단계를 거치면 일종의 색칠 된 object가 나오는 것이다.

parsing

만약 parser를 개발한다면 이는 두 가지 타입으로 구성된다.

  1. conventional : css and javascript
    파싱은 document를 code가 사용할 수 있는 structure로 해석하는 것을 의미한다.

1 + 2 *3 -> parsing -> someting like tree structure

documents를 코드가 사용할 수 있는 structure로 translate한다.

  1. unconventional: html
    html document type definition(DOCTYPE)

render tree

돔트리가 생성되는 동안 생성된다.

  • visual elements in the order which they are going to be displayed.
  • elements in the render tree are called renderer or render objects.
    브라우저에 따라서 renderer 혹은 render object라고 불릴 수 있는데 이는 트리를 구성하는 작은 요소이다. 중요한 것은 렌더 오브젝트가 rectangle이라는 것이다.
  • render object is a rectangle.

layout

  • calculates position and size
  • most of the time possible to compute geometry in one path
  • recursive process begins at the root object()

  • dirty bit system
    html 태그에 있는 루트 객체가 가지고 있는 것.
    a system that makes sure that browsers don’t need to do the full
    layout on every interaction.
    노드나 돔 엘리먼트를 수정했을 때 전체 트리를 모두 다 리렌더 하는 것이 아니라, 수정이 발생한 그 부분만 리렌더 되는 것. 하지만 글로벌 또는 incremental layout도 존재한다.

  • global and incremental layout

    • global : affects all renders(font size), screen size
    • incremental layout: 기본적으로 dirty bit system을 사용하여 일부를 렌더링한다.

paint

Render object인 rectangles를 색상으로 채우면 페인트 레이어가 페인트를 하는 것이다.

render tree is being traversed and the paint() method is used to display content on the page.

페인트는 렌더 트리를 통해 기본적으로 페인트 메소드를 재귀적으로 실행한다. 페인트도 역시 lobal and incremental paint로 구성된다. 글로벌 페인팅이 필요하다면 전체페이지가 리페인팅 되고, incremental painting도 같은 dirty bit system으로 진행하되 일부 필요한 부분에 대해서만 리페인팅을 진행하는 것.

reduce the effort of painting the while thing.(dirty bit system)

  • painting order
  1. backgroud color
  2. background image
  3. border
  4. children
  5. outline

브라우저의 렌더링 과정

브라우저의 핵심 기능은 필요한 리소스를 서버에 요청하고 서버의 응답을 받아 응답받은 리소스를 파싱하여 브라우저에 시각적으로 렌더링 하는 것이다. 위에서 살펴본 브라우저 렌더링 flow를 핵심기능에 따라 다시 분류하자면 아래와 같다.

  • Fetch: network layer
  • Process
    • 렌더링 엔진
    • 자바스크립트 엔진
    • ui backend
  • display
    • user interface
    • 브라우저 엔진
  • storage: data persistence

브라우저의 렌더링 과정은 다음과 같다.

  1. html, css, javascript 등 렌더링에 필요한 리소스를 요청, 서버로부터 응답을 받는다.
  2. 서버로부터 응답된 html과 css를 파싱, dom과 cssom을 생성하여 이를 결합한 render tree를 형성한다.
  3. javascript는 서버로부터 응답된 javascript를 파싱, AST(abstract syntax tree)를 생성하고 바이트 코드로 변환하여 실행한다. 이때 javascript는 DOM API를 통해 dom과 cssom을 변경할 수 있고, 변경된 사항이 다시 render tree에 결합된다.
  4. render tree를 기반으로 html 요소의 레이아웃을 계산하고, 브라우저 화면에 html 요소를 페인팅한다.

브라우저의 렌더링 과정은 다음과 같은 경우 반복해서 레이아웃 계산과 페인팅이 재차 실행되는 리렌더링이 발생한다. 이는 성능에 악영향을 주는 것이므로 리렌더링이 자주 발생하지 않도록 주의해야한다.

  • 자바스크립트에 의한 노드 추가 또는 삭제
  • 브라우저 윈도우의 리사이징에 의한 뷰포트(viewport) 크기 변경
  • HTML 요소의 레이아웃(위치, 크기)에 변경을 발생시키는 width/height, margin, padding, border, display, position, top/right/bottom/left 등의 스타일 변경

요청과 응답 (주소창을 통해 요청)

요청: 브라우저의 주소창에 url을 입력하고 엔터를 누르면 루트 요청이 서버로 전송되는데, 루트 요청시 명확히 리소스를 요청하지 않으면 암묵적으로 index.html을 응답하도록 기본 설정되어 있다. 이때 url의 호스트 이름은 dns를 통해 ip주소로 변환되고 이 ip 주소를 갖는 서버에게 요청을 전송한다.

HTTP 1.1과 HTTP 2.0

HTTP: 웹에서 브라우저와 서버가 통신을 하기 위한 프로토콜(규약)이다.

  • HTTP 1.1: 커넥션 당 하나의 요청과 응답만을 처리하는 단방향 구조이다. 따라서 여러 개의 리소스를 요청해도 개별적으로 전송되고, 응답 역시 마찬가지로 개별적으로 전달된다.
  • HTTP 2.0: 다중 요청/응답이 가능하여 커넥션 당 여러 개의 요청과 응답을 전송할 수 있다. 따라서 1.1에 비해 페이지 로드 속도가 빠르다.

HTML 파싱과 DOM 생성

브라우저 요청에 의해 서버가 응답한 HTML 문서는 문자열로 이루어진 순수한 텍스트이다. 따라서 이를 브라우저에 시각적인 픽셀로 렌더링하려면 HTML 문서를 브라우저가 이해할 수 있는 자료구조인 객체로 변환하여 메모리에 저장해야 한다. 그러면 브라우저의 렌더링 엔진은 파싱된 HTML문서로 브라우저가 이해할 수 있는 자료구조인 DOM을 생성한다.

HTML 파싱되어 DOM이 생성되는 과정(CSSOM을 생성하는 것을 제외하면 css 파싱과정도 동일하다.)
바이트 -> 문자 -> 토큰 -> 노드 -> DOM

  • 브라우저가 요청한 HTML파일을 읽어 들여 메모리에 저장한 후 메모리에 저장된 바이트(2진수)로 응답한다.
  • 브라우저는 2진수 형태로 전달받은 HTML 문서를 문자열로 변환한다. 문자열로 변환시 html 파일 내부의 <meta charset="UTF-8">의 인코딩 방식을 따른다.
  • 이렇게 문자열로 변환된 html 문서를 토큰으로 분해한다. 토큰은 문법적인 의미를 갖는 코드의 최소 단위를 의미한다.
  • 각 토큰들을 객체로 변환하여 노드를 생성한다. 노드는 DOM을 구성하는 기본 요소이다.
  • html 문서는 html 요소들의 집합으로 이루어므로 중첩 관계를 갖는다. 즉 부자 관계를 형성하고 이를 반영한 노드들은 트리 자료구조를 구성한다. 이를 DOM이라 한다.
  • 즉 DOM은 html문서를 파싱한 결과물이다.

렌더 트리 생성

렌더링 엔진은 서버로부터 응답받은 html과 css를 파싱하여 DOM과 CSSOM을 생성하는데, 이는 렌더링을 위해 render tree로 결합된다. 렌더링은 위한 자료구조이기 때문에 화면에 렌더링되지 않는 노드는 제외된다. 이 렌더 트리는 레이아웃의 위치와 크기를 계산하는 데 사용되고, 브라우저 화면에 픽셀을 렌더링하는 페인팅 처리에 입력된다.


자바스크립트 파싱과 실행

자바스크립트 코드에서 Dom이 제공하는 DOM API를 통해 이미 생성된 DOM을 동적으로 조작할 수 있다. 렌더링 엔진이 html 코드를 한 줄씩 순차적으로 parsing하며 dom을 생성하다가 자바스크립트 파일을 로드하는 script 태그나 자바스크립트 코드를 콘텐츠로 담은 script 태그를 만나면 dom 생성을 일시적으로 중단하고, 자바스크립트 엔진에게 제어권을 넘긴다. 제어권을 넘겨받으면 자바스크립트 엔진은 자바스크립트의 코드를 파싱하여 AST를 생성하고, 이를 기반으로 인터프리터가 실행할 수 있는 중간 코드인 바이트코드를 생성하여 실행한다. 이렇게 자바스크립트 파싱과 실행이 종료되면 제어권은 다시 렌더링 엔진으로 넘겨지고 html 파싱이 중단된 지점부터 다시 파싱을 시작하여 dom 생성을 재개한다. 브라우저는 이처럼 순차적으로 html, css, 자바스크립트를 파싱하고 실행한다. 따라서 자바스크립트 엔진이 dom api를 사용하는데, dom이나 cssom이 생성되기 이전이라면 에러가 발생할 수 있다.script 태그의 위치를 body 요소의 가장 아래에 위치시키면 예기치 못하게 발생할 수 있는 에러를 방지할 수 있다.

자바스크립트 파싱과 실행과정은 다음과 같다.

자바스크립트 소스코드 -> 토크나이징 - 토크나이저 -> 토큰 -> 파싱 - parser -> AST -> bytecode generator - 바이트코드 생성 -> 바이트코드 -> execution -> 인터프리터

  • 토크나이징: 문자열인 자바스크립트 소스코드를 문법적 의미를 갖는 코드의 최소 단위인 토큰들로 분해한다.
  • 파싱: 토큰을 분석하여 AST(추상적 구문 트리)를 생성하는데 토큰에 문법적 의미와 구조를 반영한 트리 구조의 자료 구조를 말한다.
  • 바이트 코드 생성과 실행: 파싱의 결과물로 생성된 AST가 인터프리터가 실행할 수 있는 중간 코드인 바이트코드로 변환되고 실행된다.

리플로우와 리페인트

자바스크립트 코드에 DOM API가 사용되었다면 DOM이나 CSSOM이 변경된다. 이때 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 거쳐 브라우저의 화면에 다시 렌더링한다. 이를 리플로우(reflow), 리페인트(repaint)라 한다.

  • 리플로우: 레이아웃 계산을 다시 하는 것을 말하며, 노드 추가/삭제, 요소의 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 한하여 실행된다.
  • 리페인트: 재결합된 렌더 트리를 기반으로 다시 페인트를 하는 것을 말한다.

References

How Do Web Browsers Work?
Kruno: How browsers work | JSUnconf 2017
html5rocks
poiemaweb

WHAT HAPPENS TO CSS WHEN WE LOAD UP A WEBPAGE?

  1. LOAD HTML
    user가 웹페이지를 오픈했을 때, html은 initial html file을 load하는 starting point가 된다.

  2. parse HTML
    이 단계에서 html head를 포함한 stylesheet를 찾아서 load하고 parse하기 시작한다. 즉 html 코드가 load되면 parse하기 시작하고, 코드를 line by line으로 decode한다. 그리고 css를 load하고 parse 한다.

    • LOAD CSS & PARSE CSS
      • cascade: 충돌하는 css 선언을 해결한다. (resolving conflicting css declaractions)
      • process final css
  3. RENDER TREE = DOM + CSSOM
    위의 과정을 거쳐 브라우저는 DOM을 build하고 전체 web document가 생성된다.

    • DOM(Document Object Model): decoding 된 전체 html code가 저장되는 곳이다.
    • CSSOM(Css Object Model): css parse가 끝나면 final css가 tree-like structure인 이 곳에 저장된다.

CSS PARSING PHASE

1
2
3
4
.my-class {
color: blue;
font-size: 20px;
}
  • selector: .my-class 부분
  • Declaration Block: css rules. color: blue;와 같이 Declaration으로 구성되어 있다. DeclarationPropertycolorDeclared value20px로 구성되어 있다.

CASCADE

서로 다른 stylesheets[different css sources: author, user, browser(user agent)]와 css rules와 declarations의 충돌을 해결하고 결합하는 과정으로 어떤 속성이 가중치가 있는지 체크하는 것이고, 특정 element에는 1가지 이상의 rule이 적용된다. cascade를 체크할 때 가장 중요한 것은 css rule이 어떠한 source를 기반으로 하는 것인지와 관련되어 있다.

different css sources

  • User-Agent: 브라우저가 elemets에 제공하는 기본 스타일이며, 브라우저 마다 스타일이 다소 다르게 보여질 수 있다. css resets를 사용하여 user-agent styles를 override하는 방법을 쓰는 것이 이러한 차이를 상쇄시키는 방법 중 하나이다.

  • User: 브라우저 사용자에 의해 정의되고 제어된다. 보통 style을 override하거나 웹사이트 접근성을 추가하기 위한 것으로, 모든 사람이 가지고 있는 것은 아니다.

  • Author: HTML document에 선언된 css를 말한다. 일반적으로 프론트엔드 개발자가 작성하여 제어할 수 있는 것을 말한다.

그런데 css rules와 declarations의 충돌을 어떻게 해결한다는 것일까?

which one takes precedence?
importance(weight), specificity, source order

  • importance(weight): 선언된 위치(css source)에 근거하여 각 선언(declaration)에 서로 다른 중요성을 부여하는 것으로 시작한다.
1
2
3
4
5
1. user `!important` declarations
2. author `!important` declarations
3. author declarations
4. user declarations
5. default browser declarations

그런데 만약 importance가 모두 같다면?

  • specificity: 선언된 selector의 specificity를 비교하고 계산한다.
1
2
3
4
1. inline styles
2. IDs
3. classes, pseudo-classes, attribute
4. elements, pseudo-elements

우선순위인 1번부터 차례로 다음과 같이 (inline, IDs, classes, elements)의 순서로 비교한다. 만약 비교한 결과가 (0,0,0,1), (0,1,0,1)이라면 전자가 specificity가 더 높은 것이다.

그런데 만약 specificity가 모두 동일하다면?

  • source order: 코드의 마지막 선언은 다른 모든 선언을 override하고 적용된다. 만약 3rd-party stylesheets를 사용한다면 author stylesheet는 늘 가장 마지막에 위치해야한다.

내가 React project를 했을 때의 경험을 예시로 들어보겠다. 당시 SlidingPane이라는 라이브러리를 사용하여 팝업창을 구성했는데, 기본 설정된 배경색을 다른 색으로 변경했어야 했다. 그러나 이 라이브러리는 몹시 간결한 것이어서 그러한 변경에 대한 방법이 따로 설명되어 있지 않았다. 그래서 선택한 방법은 css파일에 변경해야 할 부분을 작성한 후 원래 있던 코드를 background: #D9DBE0;로 작성한 후 override하는 것이다.

1
2
3
4
5
6
7
8
9
10
11
/* 원래 코드: react-sliding-pane.css */
.slide-pane {
display: flex;
flex-direction: column;
background: #fff;
min-width: 100px;
height: 100%;
box-shadow: 0 8px 8px rgba(0, 0, 0, 0.5);
transition: transform 0.5s;
will-change: transform;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/* 내가 작성한 author 코드: Cart.css */
.slide-pane {
display: flex;
flex-direction: column;
background: #d9dbe0;
min-width: 100px;
height: 100%;
box-shadow: 0 8px 8px rgba(0, 0, 0, 0.5);
transition: transform 0.5s;
z-index: 80;
will-change: transform;
position: relative;
}

이렇게 작성 후 react로 작성된 Cart.js 파일의 상단에서 다음과 같은 순서로 import한다.

import ‘react-sliding-pane/dist/react-sliding-pane.css’;
import ‘./Cart.css’;

이렇게 하면 마지막에 import 된 Cart.css가 원래 존재하던 파일을 override하게 되기 때문에 배경색이 #fff에서 내가 설정한 #D9DBE0으로 변경된다.

CSS Selector Specificity

CSS Selector Specificity를 비교하는 과정을 예시를 통해 보다 자세히 알아보겠다.

1
2
3
4
5
<nav id="nav">
<div class="pull-right">
<a class="button button-danger" href="link.html">Don't click here!</a>
</div>
</nav>

예시에서 .buttona는 specificity가 낮은 편이기 때문에 다른 속성에서 우선순위에 밀려 배경색이 나타나지 않는다. 하지만 specificity가 낮더라도 !important를 선언하면 다른 어떤 속성보다도 우선순위를 갖고, 즉각 배경색이 버튼에 표시된다. 하지만 !important는 최소 한 번 사용하거나 되도록 쓰지 않는 것이 권장된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
body {
padding: 50px;
}

/* 클래스 1개. low specificity */
.button {
font-size: 20px;
color: white;
background-color: blue;
}

/* 가장 specificity가 낮음 */
a {
background-color: purple;
}

/* hover를 제외하면 이 선언이 세가지 중에 가장 우선순위가 높다. */
#nav div.pull-right a.button {
background-color: orangered;
}

#nav a.button:hover {
background-color: yellow;
}

위의 코드에서 button에 마우스를 hover하면 색깔이 yellow로 바껴야 하지만, 아무런 변화가 없다. 그 이유는 pseudo class인 hover는 specificity에서 1으로 카운트되기 때문이다. 그러나 #nav div.pull-right a.button 이 경우 specificity는 id 1개, class 2개를 가지고 있다. #nav a.button:hover도 사실은 id 1개, class 2개를 가지고 있는 것인데, hoverclass가 아니라 class인 것으로 여기는 pseudo class이다. 따라서 전자는 2개의 elements를 가지고 있고, 후자는 1개의 elements를 가지고 있다. 결과적으로 #nav div.pull-right a.button가 훨씬 specificity가 높은 것이다. 따라서 hover는 적용되지 않는다. 만약 hover했을 때 색깔이 변경되도록 설정하고 싶다면 아래와 같이 코드를 바꾸어야 한다.

1
2
3
4
5
6
7
8
9
10
11
#nav div.pull-right a.button {
background-color: orangered;
}

#nav div.pull-right a.button:hover {
background-color: green;
}

#nav a.button:hover {
background-color: yellow;
}

이렇게 코드를 작성하면 #nav div.pull-right a.button에 pesudo class인 hover가 추가되어 hover가 붙지 않은 elements와 비교했을 때 specificity가 높아진다. 따라서 hover했을 때 색깔이 green으로 바뀌는 것이다.


References
How CSS works: Understanding the cascade
Advanced css and sass

HTML

마크업 언어. 웹페이지는 어떻게 구조화되어 있는지를 브라우저에게 알려줌. elements와 tag로 구성되어 있다.

요소(elements)

  • elements: 각 컨텐츠를 감싸고 마크업한다. 엘리먼트 안에는 내용과 내용을 앞뒤로 감싸는 태그(여는 태그, 닫는 태그)가 있다. 엘리먼트 내부는 <p>My cat is <strong>very</stong>grumpy.</p>와 같이 중첩하여 사용할 수 있다.
  • 속성(attributes): 요소에 실제로 나타내고 싶진 않지만 추가적인 내용을 담고 싶을 때 사용. <p class="editor-note">My cat is very grumpy</p>라는 예시에서 class="editor-note"를 말한다.

블럭 레벨 요소 vs 인라인 요소

  • 블럭 레벨 요소
    웹페이지 상에 블록을 만드는데, 앞뒤 요소 사이에 새로운 줄을 만들기 때문에 요소 이전과 이후 요소는 줄을 바꾼다. 블록 레벨 요소는 다른 블록 레벨 요소에 의해 중첩될 수 있지만, 인라인 요소에 중첩될 수는 없다.
  • 인라인 요소
    항상 블록 레벨 요소 내에 포함되어 있다. 문서의 한 단락같이 큰 범위에는 적용될 수 없고, 단어 같은 작은 부분에 대해서만 적용된다. 또한 블록 레벨 요소와 다르게 새로운 줄을 만들지 않는다. 따라서 인라인 요소를 작성하면 작성한 단락 내에 표현된다.

HTML 메타데이터

  • head: 페이지를 열 때 웹 브라우저에 표시되지 않는다. metadata를 포함한다.
  • title: <h1>태그와 헷갈릴 수 있는데, <h1>이 페이지를 열 때 페이지 내용의 제목에 쓰인다면, <title>는 문서의 컨텐츠 내부에 쓰이는 것이 아닌 html 문서 전체의 타이틀을 표현하기 위한 메타데이터를 의미한다. 이 <title>북마크 이름, 검색결과 로 사용된다.

  • meta: 문서의 character 인코딩을 특정하는 것으로 문서에서 허용하는 문자 집합을 의미한다. UTF-8은 다양한 언어들을 포함하는 것이므로 일반적으로 이를 사용하도록 한다.

HTML에 CSS와 JavaScript 적용하기

  • CSS: <link>를 사용하여 적용하는데, 항상 문서의 head 부분에 위치해야한다. <link>에서 rel은 문서가 stylesheet임을 나타내고, href는 이 파일의 경로를 나타낸다.
  • JavaScript: <script> 태그를 사용하여 적용한다. <head>에 들어가도 되지만 꼭 <head>에만 위치해야하는 것은 아니다. 보통은 </body> 태그 바로 앞, 즉 본문의 맨 끝에 넣는 것이 좋다. 또한 <script>태그는 반드시 닫아주어야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>My test page</title>
<link rel="stylesheet" href="my-css-file.css" />
</head>
<body>
<p>This is my page</p>
<script src="my-js-file.js"></script>
</body>
</html>

HTML text fundamentals

시멘틱: 브라우저가 텍스트를 올바르게 표시 할 수 있도록 텍스트 구조와 의미를 제공하는 것. HTML의 주요 작업 중 하나.

3 pillars are responsive design

  • Responsive Design
  • Maintainable and scalable code
  • Web Performance
  1. Responsive Design(or responsive web design)
    build one website that works beautifully across all screens sizes on all devices. responsive design absolutely ‘standard’ today.

fundamentals of responsive web design.

  • Fluid layouts
  • Media queries
  • Responsive images
  • Correct units
  • Desktop-first vs mobile-first
  1. Maintainable and scalable code
    it’s important for the developer and final user of the website.

keywords: clean, reusable

need to care and think about CSS architecture. writing maintainable code.

  • easy to understand
  • future growth
  • how to organize files
  • how to name classes
  • how to structure HTML
  1. Web Performance
    make faster and to make it smaller in size, so that user has to download less data. making as little HTTP requests as possible. but the biggest impact we can have on performance is to actually reduce the use of images.
  • less HTTP requests
  • less code
  • compress code
  • use a CSS preprocessor
  • less images
  • compare images

Reference
Advanced css and sass

CSS in JS

자바스크립트 파일 안에 스타일을 선언하는 방식

Template literal

문자열 안에 특정 js값을 넣어서 조합할 수 있게 해주는 문법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const name = "react";
const message = `hello ${name}`;

console.log(message);

//hello react

//객체는 Template literal로 표현해도
//원하는 결과물이 나타나지 않음.

const object = { a: 1 };
const text = `${object}`;
console.log(text);
//[object Object]

//함수도 마찬가지로 함수의 형태가
// 그대로 나타남.
const fn = () => true;
const msg = `${fn}`;
console.log(msg);

//() => true

Tagged Template Literal

1
2
3
const Box = styled.div`
color: black;
`;

props를 사용했을 때 그 props를 읽기 위하여 사용.

1
2
3
4
5
const StyledDive = styled.div`
background: ${(props) => props.color};
`;

const MyComponent = () => <StyledDiv color="black" />;
1
2
3
4
5
6
7
8
9
10
11
12
const red = "빨간색";
const blue = "파란색";

function favoriteColors(texts, ...values) {
console.log(texts);
console.log(values);
}

favoriteColors`제가 좋아하는 색은 ${red}${blue}입니다.`;

// ['제가 좋아하는 색은', '과', '입니다' , raw: Array(3)]
//['빨간색','파란색']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//또다른 예시
const red = "빨간색";
const blue = "파란색";

function favoriteColors(texts, ...values) {
return texts.reduce(
(result, text, i) =>
`${result}${text}${values[i] ? `<b>${values[i]}</b>` : ""}`,
""
);
}

favoriteColors`제가 좋아하는 색은 ${red}${blue}입니다.`;

//제가 좋아하는 색은 <b>빨간색</b>과 <b>파란색</b>입니다.

Refetences
modern react -velopert