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); // undefined
javascript 함수는 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 drum
Ref
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")); // true
Ref
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
사실 너무너무 정신없고 바쁘게 지나갔던 한 주다. 어째 매주 이럴 것 같지만! 쉴 틈 없이 작업하는 와중에도 토이 프로젝트와 스터디, 친구들을 모두 포기하지 못하는 사람… 😑 또 머리하면서 코딩했다. 근데 잠 좀 일찍 자자. 아무튼 유튜브는 전보다 덜 보는 것 같은데, 매일 늦게 자니 얼굴하고 몸이 구려졌다 😬 하루에 당충전도 너무 많이 하고… 오래, 멀리 가기 위해서 몸 정신 다 신경 써서 챙겨야 할 듯하다.