JS 코드 트릭
구조 분해 할당
객체에서 필요한 것만 꺼내 쓰는 것이 좋음.
const person = { name: 'Lee Sun-Hyoup', familyName: 'Lee', givenName: 'Sun-Hyoup' company: 'Cobalt. Inc.', address: 'Seoul', } const { familyName, givenName } = person;
비구조화 할당
함수에 객체를 넘길 경우 필요한 것만 꺼내 쓸 수 있음.
const makeCompany = ({ name, address }) => { // serviceName은 무시됩니다. return { name, address } }; const cobalt = makeCompany({ name: 'Cobalt. Inc.', address: 'Seoul', serviceName: 'Present' }); console.log(cobalt); //{ name: 'Cobalt. Inc.', address: 'Seoul' }
동적 속성 이름
ES6에 추가된 기능으로 객체의 키를 동적으로 생성 할 수 있음.
const nameKey = 'name'; const emailKey = 'email'; const person = { [nameKey]: 'Lee Sun-Hyoup' [emailKey]: 'kciter@naver.com' }; console.log(person); // { // name: 'Lee Sun-Hyoup' // email: 'kciter@naver.com', // }
!! 연산자를 사용하여 Boolean 값으로 바꾸기
!! 연산자를 이용하여 0, null, 빈 문자열, undefined, NaN을 false로 그 외에는 true로 변경할 수 있음.
function check(variable) { if (!!variable) { console.log(variable); } else { console.log('잘못된 값'); } } check(null); // 잘못된 값 check(3.14); // 3.14 check(undefined); // 잘못된 값 check(0); // 잘못된 값 check('Good'); // Good check(''); // 잘못된 값 check(NaN); // 잘못된 값 check(5); // 5
HTML 5
- 구조와 의미만을 담는 것이 좋음.
- 영상, 음성을 처리하기 위한 멀티미디어 요소가 추가됨. ex) audio, video, canvas
- 구조적인 요소 추가 ex) header, nav, article, section, aside, footer...
- 표현을 담당하던 태그는 삭제하고 의미를 담은 태그가 추가됨
- s → del
- b → strong
CSS
- 브라우저간 다른 CSS를 잡아줌 👉Normalize.css
- 레퍼런스 삼기 좋음 👉codepen
DOM
- Document Object Model
- 여기서 모델이란 모델링, 추상화를 거쳐 만들어진 객체를 말함.
- 추상적인 개념의 HTML 태그를 모델링하여 객체로 만들어진 것. 따라서 트리구조로 이루어짐.
- Dom Tree 순회는 preorder로 이루어짐.

DOM 선택
- getElementById
- getElementByClassName
- getElementByIdTagName
- querySelector
- querySelectorAll
- window.[id]
DOM 탐색
- parentNode
- children
- firstElementNode, LastElementNode
- nextElementSibling
- previousElementSibling
DOM 조작
- class 접근 - className, classList로 class 속성을 불러오고 변경할 수 있음.
- hasAttribute - 속성 유무 확인 가능.
- getAttribute - 선택한 요소 노드에서 속성 값을 반환. 없다면 null 반환. ex)data- 정보
- setAttribute - 속성 정의.
- removeAttribute - 속성 제거.
- textContent - 선택한 요소 노드에서 텍스트 노드에 접근, 변경 가능.
- innerHTML - 선택한 요소 노드 내부 HTML을 직접 수정. XXS 위험 있음.
- appendChild - 선택한 요소 노드 마지막 자식 요소를 추가함.
- createElement - 요소 노드 생성.
- removeChild - 선택한 요소 노드 자식 노드 중 해당하는 요소 제거.
Virtual DOM
- DOM 수정, 조작할 때마다 브라우저 렌더링이 일어난다는 문제를 보완함.
- 실제 DOM tree를 JS 객체로 만들어 필요한 정보만 담음.
- 이벤트, 돔이 수정되는 한 팀 내에 직접 돔을 수정하지 않고 가상 돔이 바뀌는 부분만 수정하면 브라우저 렌더링 프로세스를 줄일 수 있음.
- React와 vue에서 사용됨.
React는 DOM보다 빠른건 아님! 유지보수에 용이한 APP을 만들고 대부분의 유스케이스에 빠를 뿐임. 오히려 가상 돔과 진짜 돔으로 두 번 탐색하기 때문에 브라우저 렌더링 횟수를 줄여줄 뿐 속도나 메모리는 더 안좋음. 하지만 성능 최적화보다 개발 편의성이 더 필요한 경우가 많음.
반복적인 query 선택 개선하기
🤔 명령을 할 때마다 DOM 객체를 찾아서 일일히 event를 걸어줘야할까?
→ 각 DOM 객체에 custom된 속성을 넣어주고, forEach와 getAtrribute로 뽑은 값으로 이벤트를 걸어주면 됨.
//기존의 반복적인 코드 <div class="toolbar"> <button class="bold">bold</button> <button class="italic">italic</button> </div> //index.html (() => { document.querySelector(".bold").addEventListener("click", () => { document.execCommand("bold"); }) document.querySelector(".italic").addEventListener("click", () => { document.execCommand("italic"); }) })(); //app.js //개선한 코드 <div class="toolbar"> <button data-command="bold">bold</button> <button data-command="italic">italic</button> </div> //index.html (() => { document.querySelectorAll(".toolbar button").forEach((element) => { element.addEventListener("click", (e) =>{ const command = e.target.getArribute("data-command"); document.execCommand(commnad); }) }) })(); //app.js
평가와 일급
평가
- 1은 1로, [1, 2, [3, 4]]는 [1, 2, Array(2)] 등 코드가 계산되어 값을 만드는 것을 말함.
일급
- 값으로 다룰 수 있음.
- 변수에 담을 수 있음.
- 함수의 인자로 사용될 수 있음.
- 함수의 결과로 사용될 수 있음.
const a = 10; //1~2 const add10 = a => a + 10; //3~4 const r = add10(a); console.log(r)
일급 함수
- 함수를 값으로 다룰 수 있음. const add = a ⇒ a+5;처럼 함수에 변수를 담을 수 있다는 뜻.
- 조합성과 추상와의 도구.
- 함수형 프로그래밍에서는 함수가 일급이라는 성질을 이용해 많은 조합성을 만들고 추상화의 도구로 사용함.
고차 함수
함수를 값으로 다루는 함수.
- 함수를 인자로 받아 실행하는 함수(applicative 프로그래밍).
//예시 1 const apply1 = f => f(1); //f함수를 받아 f함수에 1을 적용함. 함수가 함수를 받는 형태. 함수를 인자값으로 받기때문에 고차함수임. const add2 = a => a+2; console.log(apply1(add2)) //3. f => (a=> a+2)(1)과 동일함. console.log(apply1(a => a-1)); //0 //예시 2 const times = (f,n) => { let i = 0; while(i++ < n) f(i); }; times(a => console.log(a),3); //0,1,2
- 함수가 함수를 만들어 리턴하는 함수 (클로저를 만들어 리턴하는 함수).
const addMaker = a => b => a + b; const add10 = addMaker(10); console.log(add10); // b => a+b console.log(add10(5)); //15 console.log(add10(10)); //20
ES6에서의 순회와 이터러블
기존과 달라진 ES6에서의 리스트 순회
//기존 순회 for(var i =0; i<list.length; i++) { console.log(list[i]); } //ES6에서의 순회 for(const a of list) { console.log(a); }
이터러블/이터레이터 프로토콜
- 이터러블 : 이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값.
- 이터레이터 : {value, done} 객체를 리턴하는 next()를 가진 값.
- 이터러블/이터레이터 프로토콜 : 이터러블을 for..of, 전개 연산자 등과 함께 동작하도록한 규약.
Array, Set, Map은 왜 for..of로 순회될까?
내장 이터러블인 Set과 Map이 이터러블, 이터레이터 프로토콜을 따르고 있는 for..of문과 어떻게 동작하며 순회가 이루어지는지.
//이터러블이라면 cosnt arr = [1,2,3]; arr[Symbol.iterator] = null; //에러를 발생시킴 for(const a of arr) { console.log(arr) } //따라서 (array, set map)(이터러블)은 symbol.iterator를 가지고 이터레이터를 return함. //map은 keys(), values(), entries() 함수가 이터레이터를 반환함. const map = new Map([['a',1], ['b',2], ['c',3]]); for(const a of map.keys()) { console.log(a); //a b c } for(const a of map.values()) { console.log(a); //1 2 3 } for(const a of map.entries()) { console.log(a); //[ 'a', 1 ] [ 'b', 2 ] [ 'c', 3 ] } //반환된건 다시 symbol.iterator를 가지고 있기 때문에 //다시 자기자신을 next()로 불렀을 때 values로 만든 iterator가 호출됨. const map = new Map([['a',1], ['b',2], ['c',3]]); const it = map.values(); const it2 = it[Symbol.iterator](); console.log(it.next()); // { value: 1, done: false } console.log(it.next()); // { value: 2, done: false }
결국 for..of문과 array, set, map은 이터러블, 이터레이터 프로토콜을 따름.
따라서 for..of문을 사용했을 때 iterator.next()로 반환되는 value값을 변수에 담아 출력하는 것임.
사용자 정의 이터러블
이터러블, 이터레이터 프로토콜의 속성을 구현해보자.
const iterable = { [Symbol.iterator]() { let i = 3; return { next() { return i == 0? {done:true} : {value : i--, done:false}; }, [Symbol.iterator]() {return this;} //well formed iterator } } }; let iterator = iterable[Symbol.iterator](); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); /* { value: 3, done: false } { value: 2, done: false } { value: 1, done: false } { done: true }*/ let iterator = iterable[Symbol.iterator](); for(const a of iterable) { console.log(a); } //3 2 1
- well formed iterator : 다시 한번 for.. of 문에 들어가는 등 어디에서든 [Symbol.iterator]로 만들었을 때, 이전까지 진행되어있던 자신의 상태에서 next를 할 수 있도록 만들어진 것. → iterable 자체 또는 iterator란 변수를 넣어 순회할 수 있도록 만든 것 && 일정 부분 iterator를 진행한 후에 실행해도 순회되도록.
for(const a of document.querySelectorAll('*')) {console.log(a);}
로 모든 DOM 객체를 출력할 수 있음 → [Symbol.iterator]로 만들어졌기 때문.
전개 연산자
- 이터러블, 이터레이터 프로토콜을 따름.
const a = [1,2]; a[Symbol.iterator] = null; //TypeError: a is not iterable을 출력하며 실행되지 않음. console.log([...a, ...[3,4]]);
제너레이터와 이터레이터
제너레이터
- 제너레이터 : 이터레이터이자 이터러블을 생성하는 함수. well formed iterator를 반환함.
- yield를 통해 몇 번의 next로 값을 꺼내줄 것인지 정함.
- 제너레이터의 실행결과가 이터레이터이자 이터러블이기 때문에 for..of로 순회할 수 있음.
- JS는 다형성이 높음. 제너레이터로 값을 순회할 수 있다는건 어떠한 값도 순회할 수 있는 형태로 조작할 수 있으며, 제너레이터를 통해 다양한 값을 순회할 수 있는 iterable 로직을 쉽게 만들고 순회시킬 수 있음.
function *gen() { yield 1; yield 2; // if(false) yield 2라고 작성하면 해당 값을 제외하고 순회함. yield 3; return 100; } let iter = gen(); console.log(iter[Symbol.iterator]() == iter); //true console.log(iter.next()); //{ value: 1, done: false } console.log(iter.next()); console.log(iter.next()); console.log(iter.next()); //{ value: undefined, done: true } //gen()에 return 값 설정시 { value: 100, done: true } 단 순회시 return 값은 포함되지 않음. for(const a of gen()) {console.log(a);}
odd
제너레이터를 이용한 홀수 순회 구현하기.
function *infinity(i = 0) { while(true) yield i++; } //next를 할때마다 무한한 숫자 생성(무한 수열) function *limit(n, iter) { for(const a of iter) { yield a; if(a == n) return; } } function *odds(n) { for(const a of limit(n, infinity(1))) { if(a % 2) yield a; } } for(const a of odds(10)) { console.log(a); //1 3 5 7 9 }
for...of, 전개 연산자, 구조 분해, 나머지 연산자
- 이터러블, 이터레이터로 활용할 수 있는 문법과 기능들이 많음을 알 수 있음.
- 많은 라이브러리, 함수들도 이터러블, 이터레이터를 따른다면 조합성 높은 프로그래밍을 만들 수 있음.
//위 코드와 연결 console.log(...odds(10)); console.log([...odds(10), ...odds(20)]); const [head, ...tail] = odds(5); console.log(head); console.log(tail); const [a, b, ...rest] = odds(10); console.log(a); console.log(b); console.log(rest); /* 1 3 5 7 9 [ 1, 3, 5, 7, 9, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ] 1 [ 3, 5 ] 1 3 [ 5, 7, 9 ]*/
Follow Up Tasks
CSS에서 id와 class의 차이점. 만약 id가 여러 개 있다면?
CSS 선택자 종류 알아보기
document.createDocimentFragement가 하는 일 → 정말 빠른 성능이 필요해 가상 돔이 아닌 최적화가 필요한 경우.