기본 콘텐츠로 건너뛰기

console.log 보다 더 좋은 console

 개발을 하다가 디버깅을 하기 위하여 console.log를 사용 합니다. 뭐 물론 console.log만을 사용하여 개발을 할 수도 있고, 틀린방향이 아닙니다. 하지만, 조금 더 편하게 개발을 해보자구요.  1. console.error / console.warn  이 정도는 다들 사용 하고 있는 함수들일 것 입니다. 뭐 물론 console.warn은 사용 빈도가 그렇게 많지는 않을 것 입니다. 그래도 에러가 나서 로그를 작성해야 하는 경우 console.error로 작성 해주는 것이 다른 개발자들 혹은 오래된 코드에서 문제가 발생한 것을 확실히 알 수 있게 해주어 오류를 파악하기 쉽기 때문에 매우 추천하는 바입니다.  console.log는 검은색 / console.warn은 노란색 / console.error는 빨간색으로 표기 된다.  2. console.time / console.timeEnd  만약에 이 함수를 모른다면 특정 코드가 얼마나 걸렸는지 확인을 하기 위하여 이렇게 사용 하였을 것 입니다.   뭐 물론 이렇게 하더라도 얼마나 오래 걸리는 함수를 확인하는 대에는 큰 문제가 없을 것 입니다.  하지만 위의 코드에는 두가지 문제가 있지요. 1. 1ms 미만으로 걸리는 작업에 대해서 확인이 불가능 하다. 2. startTime, endTime을 다른 개발자나 혹은 자기자신이 테스트를 하기위한 코드였는지 까먹는 것 입니다.  여기서 대안이 console.time / console.timeEnd 입니다.    3. console.table  데이터를 다루다 보면, 배열을 많이 다루게 됩니다.  console.table은 말처럼 배열과 같은 데이터를 table형태로 노출 시켜줍니다.  각각의 필드를 클릭하여 정렬도 가능하니, 데이터를 확인하는 것에도 꽤 편합니다.  4. console.trace  자바스크립트에서 함...

Shadow DOM - 사용해보기

 지난 포스팅에 Shadow DOM이 어떠한 것인지 소개까지는 하였지만, 정작 사용법에 대해서는 언급을 하나도 하지 않았다. 이번 포스팅은 사용법 위주로 소개를 할 것이다.   기본 사용법 기본 사용법은 매우 간단한 편이다. <html lang ="en" > <head></head> <body> <div id ="app" > loading... </div> <script> setTimeout (() => { const app = document . getElementById ( 'app' ) const appTemplate = document . createElement ( 'div' ) appTemplate. innerHTML = ` <h1>Hello World!</h1> ` const shadowRoot = app. attachShadow ({ mode : 'open' }) shadowRoot. append (appTemplate) } , 3000 ) </script> </body> </html>  엘리먼트에 attatchShadow함수는 실행하게 ShadowRoot의 인스턴스를 리턴한다.  ShadowRoot는 DocumentFragment를 상속 받는데, DocumentFragment는 우리가 사용하는 window.document의 클래스인 Document와 유사한 클래스라고 보면 된다.  간단하게 append 함수를 이용하여 컨텐츠를 채워줄 수 있다. attatchShadow함수의 필수 속성은 mode로 'open', 'closed'양자 택일이다. 차이점이라고 하면 외부 스크립트에서 element.shadowRoot가 closed면 null, open이면 접근 가능하다 정...

유지보수 어렵게 프로그래밍 하기

  자 우리는 왜 유지보수를 어렵게 만들어야 하는가? 우리는 우리의 코드의 보안을 유지 할 필요가 있다. 그 중에서 가장 큰 이유로는 동료 및 고용주에게 인정을 받기 위함이 클 것이다. 내가 짠 코드를 나만 수정을 할 수 있게 되면 고용주는 나를 해고 하기 어려워지며, 동료들에게는 실력의 격차를 겸허하게 받아들이게 할 수 있을 것이다. 또한 소스가 유출이 된다고 하더라도, 꽤나 시간이 걸려서 해석을 할 수 밖에 없을 것이다.  이 포스팅을 따르게 된다면 단점으로는 동료들에게 수많은 수정 요청을 받아서 회사에서 나만 일하게 되는 상황이 벌어질 테니 주의 바란다.   변수명으로 장난치기  변수명으로 장난치는 것은 꽤나 전통적인 놀이이다. 실제로 당했던 변수명으로는 그 당시에 유행 하였던 아이돌 이름일 것이다.  아이돌 이름 function GirlsGeneration() { let taeyeon let sunny ... }  자 위와 같은 함수를 받아들였다고 치자. 과연 이것을 유지보수 하는 사람은 어떤 정보를 알 수 있을까? 당연하게도 함수 작성자의 취향이다.  하하하하 아주 좋은 변수명이다.  변수명에 그렇게 많은 정보를 넣을 수 있다니 대단 하다.  한 글자 변수 let g = this  이것 또한 참 재미있는 변수명 짓기 이다. 자 여기서 g는 뭐의 약자 일까? 가장 자주 쓸만한 단어는 global일 것이다. 만약에 저 코드에서 this가 window를 가리키고 있다면 global이라는 단어는 꽤 그럴싸 할 수 있다. 한 글자로 변수를 짓는 것은 소스를 컴파일없이 불러와야  하는 브라우저 입장에서는 조금이라도 빠르게 페이지를 로드 할 수 있게 해준다.  뭐 물론 아이돌 이름을 쓰지 말라고 한 동료 개발자에 억압에 못이겨서 girlsGeneration의 약자로 g를 쓴 것일 수 있다.  동의어의 반복  동료 개발자들...

Shadow DOM (웹 컴포넌트 캡슐화)

  우리는 지난 시간 customElement를 생성하는 방법을 확인하였다. 하지만 지금까지 포스팅한 내용만 가지고는 웹 컴포넌트을 만들기에는 역부족 일 것이다.  가장 첫번째 문제로 직면할 내용이 위처럼 외부 css 정의 역시 내부 엘리먼트에 영향을 끼친다는 것이다. 이는 css를 작성함에 있어서 커스텀 엘리먼트의 하위 속성인지 전부 확인하며 피해서 css정의를 해야 한다는 게 큰 문제이다.  => 이는 당연하게도  document . getElementsByTagName ( 'div' )  와 같은 dom을 셀렉트하는 과정에서도 영향을 받는다.  이 내용은 컴포넌트를 만드는데에 있어서 큰 문제이다. 웹 컴포넌트를 만드는 입장에서도 외부에서 절대로 사용 안 할 만한 class, name, id등을 정의 하여야 한다.   DOM tree  브라우저는 우리가 작성한 html tag들을 가지고 DOM tree를 생성한다. 예시는 아래와 같다. <html> <head></head> <body> <div> div 1 </div> <div> div 2 <div> div 2 - 1 </div><div> div 2 - 2 </div><div> div 2 - 3 </div></div> </body> </html>  위와 같이 우리가 작성한 html은 위와 같이 브라우저가 해석하여 DOM tree를 만들고 해당 tree를 근거로 자식 노드들, 부모 노드, 형제들을 판단한다. TreeWalker . parentNode () TreeWalker . firstChild () TreeWalker . lastChild () TreeWalker . previousSibling () TreeWalker . nextSibling () Tr...

htmlString 을 dom으로 변경

 html string을 dom으로 간혹 만들어야 하는 경우가 있을 것이다.  예를 들면  1. ckEditor와 같이 게시판을 만들때, 에디터를 적용 해야 하는 경우, html을 검색을 하게 하는게 아니라, 해당 내용에 적혀 있는 텍스트만을 기준으로 해야 하기 때문에 html에서 태그를 제외한 내용을 따로 저장을 해둬야 하는 경우도 있다.  2. html string을 분석하여 특정 처리를 해야하는 경우도 있을 것이다. 예를 들면 검색후 매칭 되는 글자의 하이라이트 처리나, 해당 html 문자열이 단 하나의 부모만 있는지 등...  뭐 위의 내용 말고도 필요한 경우는 있을 것이다. 뭐 옛날에는 xml을 파싱 해야 했을 때도 있었지만...   innerHtml function htmlStringToNodeList (htmlString) { const tempNode = document . createElement ( 'div' ) tempNode. innerHTML = htmlString return tempNode. childNodes }  위 처럼 현재 document에 문서에 연결되지 않은 dom을 하나 생성 후 innerHTML로 htmlString을 세팅을 하게 되면, 모든 자손을 제거하고 htmlString을 html로 파싱하고, 생성된 노드로 대체 되는 특성을 사용 한 것이다. 사용법이 매우 심플하고, 널리 쓰고 있는 방법이기에 꽤 추천 하는 코드이다. * 텍스트만 뽑고 싶다면 아래 처럼 return만 변경 해주면 된다. return tempNode. innerText 출처: https://developer.mozilla.org/ DOMParser function htmlStringToNodeList (htmlString) { return ( new DOMParser ()) . parseFromString (htmlString , 'text/html' ) ...

CustomElement (2)

 전 시간에 CustomElement를 만드는 방법에 대해서 확인해보았다. 이번 시간부터는 조금더 상세하게 확인해보도록 하자. 정의요소 class MyElement extends HTMLElement { constructor () { super () // element 생성 } connectedCallback () { // document 에 element 가 추가 되면 브라우저에서 호출이 된다 . } disconnectedCallback () { // document 에 element 가 제거 되면 브라우저에서 호출이 된다 . } static get observedAttributes () { return [ /* 모니터링 될 속성의 이름 . */ ] } attributeChangedCallback (name , oldValue , newValue) { // observedAttributes 에서 나열되어있는 속성중 하나의 속성이라도 값이 변경되면 호출 된다 . } adoptedCallback () { // 해당 엘리먼트라 다른 document 로 이동될 시 호출 된다 . } }  customElement를 정의하게 되면 위의 메서드들을 정의할 수 있다. 각각의 메서드들 중 constructer를 제외 하고는 처음 보는 것들일 것이다. 각각의 속성에 대해서 설명을 해보겠다. constucter  당연 하게도, new MyElement()를 호출하게 되면 constructer가 호출되는 것은 당연하게 여길 것이다. 그 외에 엘리먼트로써 생성되는 경우가 두가지가 있다.  html 본문에 태그로 작성 되어있는 경우 customElements.define이 되어있다면, 해당 태그가 해석 될 때 constructer가 호출 되고, customElements.define가 태그 해석이 완료 후에 호출된다면, define이 되었을 때 호출이 ...

CustomElement

 프런트엔드 개발자라면 프레임워크등을 사용하여 컴포넌트를 만드는 것은 익숙 할 것이다. 뭐 물론 백엔드 개발자라고 하더라도, custom tag를 정의 해 본 사람도 있을 것이다. 오늘은 프레임 워크없이 우리가 컴포넌트라고 부를수 있을 만한 custom element를 정의를 해볼 것이다. Window.customElements  window의 기본객체에는 위와 같은 객체가 있다. 이름만 보더라도 아 새로운 element를 등록하기 위해서 만들어진 것이구나 생각 할 수 있을 것이다. 그러면 지원하는 함수들을 한번 확인해보자. define, get, upgrade, whenDefined  define: 우리가 이번 포스트에서 주로 살펴볼 함수이다. 커스텀 엘리먼트를 정의 하는 함수라고 볼수 있다. * document.registerElement와 유사한 행위를 하지만 document.registerElement는 deprecated이니 사용 하지 말자.  get: 특정이름으로 정의 된 커스텀 엘리먼트의 클래스를 반환한다.  upgrade: 특정 dom의 트리를 정의한 커스텀 엘리먼트로 업그레이드 한게 된다.  whenDefined: 특정이름의 컴포넌트가 정의 될때 알 수 있도록 promise를 제공한다. => 이는 미리 html을 로드후 정의 되지 않은 엘리먼트를 특정 시점에 upgrade를 하거나 대치 할 수 있도록 정의 필요 할 것으로 보인다. Window.customElements.define  window의 기본객체에는 위와 같은 객체가 있다. 이름만 보더라도 아 새로운 element를 등록하기 위해서 만들어진 것이구나 생각 할 수 있을 것이다. 그러면 지원하는 함수들을 한번 확인해보자.  커스텀 엘리먼트를 정의 하는 것은 어렵지 않다. <html> <head> <script> class TestElement ...

메서드 vs 함수

 함수는 무엇일까? 하나 이상의 문장, 식이 특정 하나의 기능을 위해 작성 된 것이라고 표현 할 수 있겠다. 뭐 물론 문장이라고 하였지만, 하나의 식(expression)으로도 표현 가능 할 것이다.  그러면 메서드란 무엇일까? 객체지향 언어를 배우다보면 메서드라는 표현을 처음 듣게 된다. 간단하게 클래스혹은 구조체 내에 정의된 함수라고 표현 하면 될 것 같다.  당연하게도 자바스크립트도 (프로토타입기반) 객체지향 언어이기 때문에 메서드라는 개념이 있다.   (참고 ES6 표준으로 제시된 class는 새로운 객체지향 모델을 지원하는 것이 아니라 기존의 프로토타입 기반의 객체지향을 위한 Syntacitc Sugar일 뿐 오해하지 말자.)  자바스크립트에서의 메서드 const person = { name : 'sejiowrk' , hi () { console. log ( `안녕하세요. ${ this . name } 입니다.` ) } }  자바스크립트에서의 메서드정의는 Java, C++등과 비교하여 간편하다 class를 따로 정의할 필요도 없으며, new 키워드를 사용 하여 인스턴스화 할 필요없이 리터럴 객체를 만들어서 정의할 수 있다. 뭐 물론 필요하다면, class 혹은 function을 이용하여 좀 더 다른 언어들과 유사하게 만들어주는 것도 가능 하므로 선택은 자유이다.  hi 함수는 메서드이기 때문에 자신이 속해있는 객체의 name을 사용할 수 있게 된다. 당연하게도 hi는 메서드이전에 함수이다.   잃어버린 this (person. hi || function () { })() 엄격 모드 사용시에는 name을 찾을수가 없고, 엄격 모드를 사용 하지 않는 경우에는 window가 this를 대체 하였다.  두 경우 모두 hi가 속해 있는 객체 person의 name을 가져올 수 없게 되었다. 해당 내용이 의아 할 수 있는데, 간단하...

팝업이 차단 되었습니다. (회피하기)

  우리는 인터넷을 하다보면, 아래의 그림처럼 팝업이 차단되는 경우가 많이 있다.  브라우저가 팝업을 여는 동안 해당 페이지가 사용자를 괴롭히고 있다고 판단 하는 경우에 노출이 된다. 몇몇 분들은 어렸을 적 친구의 피씨에 설치하였던 무한 팝업을 해본 기억이 있을 것이다. 바로 그것을 막는 것이라 보면 된다.  자 그러면 괴롭히고 있다고 판단한 경우라고 하였는데, 그러면 그것이 무엇일까?  사용자 몰래 띄운 팝업  사용자 몰래 팝업을 띄우는 거는 꽤나 많이 볼 수 있다. <!DOCTYPE html > <html> <head> <meta charset ="UTF-8" > <script> window . open ( 'https://www.google.com' , '_blank' ) </script> </head> <body></body> </html>  위의 코드는 아무런 맥락 없이 해당 페이지에 들어가자 팝업을 열게 하는 코드이다. 저런 상황을 팝업을 차단 하지 않게 된다면, 해당 페이지가 새로운 팝업을 여는 페이지를 열고 또 그페이지는 또 새로운 페이지를 여는 페이지를 열고 계속 반복하게 된다면 사용자를 괴롭히는 것이 될 수 있을 것이다.  공공 사이트에서 예전에 공지사항을 노출시키기 위하여 이러한 행위를 많이 했었고 해당 팝업들은 열심히 차단당했다.  즉 우리는 해당 페이지를 열기 위해서 유저의 행위를 받아야 한다. <!DOCTYPE html > <html> <head> <meta charset ="UTF-8" /> <script> function openNewPage () { window . open ( 'https://www.google.c...

javscript getter, setter

 일반 적으로 자바 C# 등등의 객체지향언어를 이용하여 개발하신 분들이라면 getter, setter는 아주 친숙한 내용일 것이다.  하지만, 자바스크립트에서는 전통적인 방법으로는 private 변수를 지원 하지 않기 때문에 _name 이런식으로 이름만 지어서 내부에서만 사용변수라는 표시만을 하여 내부 데이터이니 읽거나 쓰지 마세요 정도로 사용 하고 있다.  그렇다면 자바스크립트에는 getter, setter가 없을까?  접근자 프로퍼티(accessor property) get, set  getter, setter를 이용하는 이유 중에는 데이터를 신뢰하고, 복잡한 로직을 밖으로 노출 하고 싶지 않아서 일 것이다. 간단한 예를 들어보자. const person = {} person . age = - 3 과연 사람 중에 -3 세인경우가 있을까? 뭐 개념적으로 2000년생의 경우 1997에 몇살이었냐고 물어본다면 가능하겟다만.... 이럴 때 사용 가능 한 것이 get, set이다. 간단하게 코드를 변형 해보자. const person = { get age () { return this . _age } , set age (age) { if (age > 0 ) { this . _age = age } } }  위 처럼 우리는 나이에 대해 정합성 체크를 하여 age속성을 사용 할 수 있게 되었다.  private 변수처럼 사용 해보기  위 처럼 특정 속성에 대해서 정합성이 필요 한경우 특정 데이터를 위한 모델일 가능성이 높다. Person이 필요 할 때마다 literal object로 매번 정의 하는 것은 꽤나 불편한 내용일 것이다. 이때는 class가 유용 하겠지만 사용하기 애매하다면 function또한 꽤 좋은 대체재라고 말하고 싶다.   function Person () { let _a...

new Date() - new Date() (javaScript 형변환)

 우리는두 시간의 차이를 구하기 위하여 new Date() - new Date() 와 같이 분명 Date객체를 가지고 두 값의 차이를 구하는 -연산을 수행 하고 있고, 그리고 그것을 또 해주는 것을 볼 수 있다. 우리는 그런 특성을 보면서 형변환 중 묵시적 형변환이 되었구나, 라고 생각하곤 한다.  묵시적이라는 말의 뜻은 이와 같다.  말이나 행동으로 직접 드러내지 않고 남이 모르는 사이에 뜻을 나타내 보임.  <출처: Naver Korean-English Dictionary>  직접 드러내지 않고 남이 모르는 사이에 바뀌었다는 것인데, 그렇다면 우리 개발자들에게 드러내지 않고 있는 규칙은 무엇일까?   Symbol.toPrimitive  첫번째 규칙이다. obj[Symbol.toPrimitive](hint) 형변환이 필요한 경우 자바스크립트는 해당 객체의 Symbol.toPrimitive의 키를 갖는 함수를 연산을 할 때 필요한 자료형을 요청 하는 것으로 형변환을 수행한다.  자 그러면 형변환이 필요한 경우를 몇개 구성해보자.  첫째로 예제를 들었던 obj1 - obj2 와 같을 것이다. obj1, obj2 두 값과의 차이를 구한다는 것은 숫자일 수 밖에 없을 것이다.  두번째로 alert(obj1) 같이 obj1을 문자열로 표현을 해야 하는 경우가 있을 것이다.  세번째로  "나무" + obj1 , 1 + obj2 와 같이 덧셈 연산이 있을 것이다. 이 때에는 첫번째 연산의 경우 문자열과의 덧셈이기 때문에 obj1이 식혜라는 값이면 "나무식혜"와 같이 문자열로 변환이 필요 하며, 두번째의 경우에는 숫자와의 연산이기 때문에 obj2가 2라면 3과 같이 값이 나와야 할 것 이다.  자 그러면 위의 연산들이 과연 obj[Symbol.toPrimitive] 함수를  호출 할 때 어떤 값을 hint로 제공하는지 확인 해보...