February 20, 2021 • ☕️☕️☕️ 15 min read
우테코 3주차 기록
잡담(?)이 많았는데, 기억 나는 내용 하나. 우테코 10개월 동안 꼭 배웠으면 좋겠는 것은, 누군가 javascript를 물어봤을 때, 쉬지 않고 계속해서 떠들 내용이 있을 만큼 그 언어에 애정이 있었으면 좋겠다고 하셨다.
사실 vanilla js를 잘 알기도 전에 react.js를 시작하여 그냥 대충대충 페이지를 찍어내는 데 급급했었는데, 훌륭한 개발자까진 아니더라도 좋은 개발자가 되기 위해서, 그리고 자신 있게 ‘javascript 개발자’라고 말하기 위해서는 누구한테나 정말 필요한 자세인 것 같다. 늘 염두에 두어야겠다.
DOM & BOM 주제의 첫주차 테코톡을 진행헀다. 첫 주자라 긴장되고 떨렸을 텐데, 생각지 못했던 내용들까지 세심하고 꼼꼼하게 준비하여 테코톡 발표를 진행하셨다.
새롭게 알게 되거나, 헷갈렸던 내용 정리!
document 객체는 html 파일마다 한 개씩 새로 생성된다.getElementsByTagName, getElementsByClassName 사용 시 리턴되는 형태다.Array.from()으로 HTMLCollection으로부터 배열을 생성해서 배열 내장 메서드(.map, .forEach 등)를 사용할 수 있다.element.childNodes 프로퍼티나 document.querySelectorAll 메서드로 반환되는 노드의 모음이다.Node.childNodes의 NodeList는 라이브 콜렉션으로, DOM의 변경사항을 실시간으로 반영한다. 반면 document.querySelectorAll()의 NodeList는 정적 콜렉션으로, DOM이 변경되어도 collection의 내용에는 영향을 주지 않는다.forEach는 기본적으로 사용할 수 있다.Ref https://devsoyoung.github.io/posts/js-htmlcollection-nodelist
+ 크롬 개발자 도구에서 javascript 성능을 확인하는 방법을 알았다. 😮 신기
리뷰어와의 적극적인 토론 및 리액션하기. 이모지도 리액션이다 👀
class와 instance의 의미 생각해보기. ES6에 class가 도입되어 무조건 class를 쓰기보다는, 객체를 생성할 필요가 없는 경우에는 함수를 쓰는 것도 고려해 보자.
단수/복수 네이밍에 유의하자.
인덱스를 통해 찾는 방법은, 추후에 변경될 여지가 많이 있기 때문에 지양해야 한다.
객체의 데이터는 직접 접근하기보다는 요청하자. getter를 활용해도 좋다.
빠른 실패(early return)를 사용하면 코드를 간결하고 직관적으로 작성할 수 있다.
하나의 함수는 한 가지 기능만 수행하도록 하자. validation에서 alert 메시지를 넣는 것은 함수가 2가지 기능을 하게 된다.
isValid 등 is가 붙은 것은 ‘flag 변수’라고 하는데, flag만 하지 않고 alert까지 하는 것은 좋지 않은 패턴이다.filter, map 등 javascript의 chaining methods를 활용하면 코드가 더욱 간결해지고 가독성이 높아진다.
구조 분해 할당을 많이 활용하자! DOM을 가져올 때도 사용할 수 있다
const [thisBtn, thatBtn, otherBtn] = document.getElementsByTagName("button");일반 for문 대신 Array method(forEach 등)를 사용하자. for문에는 인덱싱의 조건 등 실수할 수 있는 여지가 들어가기 때문이다.
no-prototype-builtins(eslint) - Object.prototype의 builtin으로 제공되는 메서드를 객체에서 직접 호출하지 않도록 하자.
getRandomNumber와 같은 순수함수는 다른 객체에서도 쓸 수 있게 분리하거나,this를 사용할 필요가 없다면 static으로 선언하는 방법도 있다.Array의 메소드를 활용하자click 이벤트에 대한 콜백함수의 네이밍은, handleRestartButtonClick()보다는 handleRestartButton()과 같은 형태로 쓰는 것이 좋다.on, handle 등의 prefix가 붙는 것은 좋다.Object()를 상속 받기 때문에, 프로토타입 체이닝을 통해 거슬러 올라간 Object()의 prototype에서도 속성을 찾을수 없다면 undefined를 반환한다.this 키워드는 함수를 포함한 객체를 참조한다. 이때 this의 값은 함수가 호출되는 컨텍스트에 따라 결정된다.this는 객체 멤버의 컨텍스트가 바뀌는 경우에도 언제나 정확한 값을 사용하게 해준다.👉 javascript는 클래스 기반이 아닌, 프로토타입을 가진 객체 기반의 언어 👉 프로토타입 - 객체지향 언어가 아닌 javascript가 객체지향과 비슷한 특징들을 가질 수 있게 해준다.
DOM object를 가져오기 위해 사용했던 document.querySelector('div')와 같은 코드도, Document 객체의 인스턴스가 가진 메소드를 활용한 것이다.
웹페이지가 로딩될 때 Document 인스턴스가 만들어지고, 전체 웹 페이지 구조와 컨텐츠 그리고 URL같은 기능들을 제공하는 document가 호출되는 것이다.
그동안 사용해왔던 다른 내장 객체/API(Array, Math 등등)들도 마찬가지! 😮
function doSomething() {}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
console.log(doSomeInstancing);
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log(doSomeInstancing);
console.log(doSomeInstancing.foo); // bar
console.log(doSomeInstancing.prop); // some value
console.log(doSomething.foo); // undefined
console.log(doSomething.prototype.foo); // bar
console.log(doSomething.prop); // undefinedjavascript 함수는 prototype 프로퍼티를 가지고 있다.
new 연산자를 통해 생성한 인스턴스는 __proto__라는 프로퍼티를 갖고 있으며, 이는 constructor의 prototype을 참조한다. 이때__proto__는 생략이 가능하도록 구현되어 있다.
이때 prototype은 객체 인스턴스가 갖고 있는 것이 아니라, Object 즉 객체 그 자체가 갖고 있는 속성이다.
즉 doSomething.prototype은 가능하지만, doSomeInstancing.prototype은 불가능하다.
여기서 doSomeInstancing은 __proto__를 타고 올라가 doSomething의 foo 속성에 접근할 수 있다.
인스턴스의 __proto__는 생략할 수 있기 때문에, doSomeInstancing을 통해 doSomething의 prototype 속성에 접근하려면, 단순하게 그 속성값을 작성해주면 된다. (여기서는 foo)
프로토타입 체이닝을 통해 자동으로 거슬러 올라가 찾아주기 때문이다.
😯 이때 prototype에 정의한 모든 것은 모든 인스턴스가 효과적으로 공유한다는 뜻이며, 심지어 프로토타입의 일부를 나중에 변경하다고 해도 이미 생성되어 있는 인스턴스는 필요한 경우 그 변경 사항에 접근할 수 있다.
또한 doSomething의 인스턴스인 doSomeInstancing에서 생성한 속성 prop은 doSomething에서는 찾을 수 없다.
function Graph() {
this.vertexes = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function (v) {
this.vertexes.push(v);
},
};console.log(g)의 실행 결과는 다음과 같다.
g는 vertexes 와 edges를 속성으로 가지는 객체이며, g.addVertex()를 실행하면, 프로토타입 체이닝을 통해 Graph의 addVertex()를 호출할 수 있다.
ES5에는 Object.create()라는 방식도 도입되었다고 하지만, 여기선 패스!
대신 ES6에서 등장한 class를 통해 객체를 생성할 수 있다.
Mixin은 javascript에는 없는 클래스 복사 기능을 흉내 낸 것이다. Mixin은 특정 행동을 실행해주는 메서드를 제공하는데 단독으로 쓰이지 않고, 다른 객체에 행동을 더해주는 용도로 사용된다.
// mixin
let someMixin = {
greets() {
alert(`Hello ${this.name}`);
},
study() {
alert(`${this.name} is now studying`);
}
play() {
alert(`${this.name} is playing drum`);
}
};
// create object
class Person {
constructor(name) {
this.name = name;
}
}
// copy method
Object.assign(Person.prototype, someMixin);
new Person("Zig").play(); // Zig is playing drumRef
DocumentFragment를 사용하여 DOM 조각을 새롭게 생성하는 것이, 기존의 createElement보다 성능이 좋다. append를 하더라도 reflow가 발생하지 않기 때문이다.
DocumentFragment는 DOM tree에 영향을 미치지 않는다. (따라서 reflow가 발생할 때에도 document에 영향을 미치지 않는다!)
위 내용을 공부하며 innerText와 innerHTML에 더해 textContent라는 것도 알게 되었다.
innerText는 사람이 읽을 수 있는 요소만 가리키며, innerHTML은 말 그대로 html을 가져온다.
Node 인터페이스에서 사용되는 textContent는 노드의 모든 자식을 주어진 문자열로 이루어진 하나의 텍스트 노드로 대치한다.
Ref
isNaN은 값이 Number 타입이 아니거나 Number 타입으로 변환될 수 없을 때 true를 리턴한다. (값을 먼저 Number로 형변환한다)
isNaN = function (value) {
Number.isNaN(Number(value));
};Number.isNaN은 값이 NaN 타입인지 확인한다. 기존부터 존재한 isNaN의 조금 더 엄격한 버전이다.
😯 NaN 값은 산술 연산이 정의되지 않은 결과 또는 표현할 수 없는 결과를 도출하면 생성된다.
isNaN("zigsong"); // true
isNaN(NaN); // true
isNaN(undefined); // true
isNaN("zig" / "song"); // true
Number.isNaN("zigsong"); // false
Number.isNaN(NaN); // true
Number.isNaN(undefined); // false
Number.isNaN("zig" / "song"); // true따라서 Number.isNaN의 인자에 Number.parseInt 등으로 감싼 NaN 타입을 넣어주면, true를 리턴하게 된다.
Number.isNaN(Number.parseInt("zigsong")); // trueRef
Ref https://developer.mozilla.org/ko/docs/Web/API/CustomEvent/CustomEvent
$element.checked로 가져올 수 있다.#(해시) prefix를 붙여 private 메소드 또는 프로퍼티를 선언할 수 있다.submit이라는 이벤트 하나로 묶을 수 있다. 그동안 eventListener에 아무 생각 없이 click만 주구장창 써왔던 나 자신 반성하자😬required, min, max 값 등을 넣어 자체적으로 제공되는 validation을 활용할 수 있다.$element.toggleAttribute라는 내장 메소드를 활용하여 해당 DOM 객체의 속성을 넣었다 뺐다할 수 있다. 😮div를 남발하지 말고, section 등의 태그가 필요하진 않은지 생각하자.Ref https://ko.wikipedia.org/wiki/YAGNI
built-in Objects prototypes을 변경하지 말자
Array.prototype.insert = function (index, item) {
this.splice(index, 0, item);
};라이브러리가 제공하는 자체 메소드와 충돌이 날 위험이 있고, 추후에 위와 같이 customize한 메소드의 동작을 변경해야 할 때 유지보수가 힘들어진다.
필요한 함수는 따로 분리하여, import해서 사용하자
Ref https://flaviocopes.com/javascript-why-not-modify-object-prototype/
Ref https://woowabros.github.io/interview/2021/02/16/2021-interview.html
사실 너무너무 정신없고 바쁘게 지나갔던 한 주다. 어째 매주 이럴 것 같지만! 쉴 틈 없이 작업하는 와중에도 토이 프로젝트와 스터디, 친구들을 모두 포기하지 못하는 사람… 😑 또 머리하면서 코딩했다. 근데 잠 좀 일찍 자자. 아무튼 유튜브는 전보다 덜 보는 것 같은데, 매일 늦게 자니 얼굴하고 몸이 구려졌다 😬 하루에 당충전도 너무 많이 하고… 오래, 멀리 가기 위해서 몸 정신 다 신경 써서 챙겨야 할 듯하다.