기본 콘텐츠로 건너뛰기

함수형 프로그래밍 겉핥기.

 1년 전에 작성한 포스팅 중에  Lodash fp 사용하기.  포스팅을 작성한 내용이 있다. 함수형 프로그래밍에 대해서 언급을 했지만, 함수형 프로그래밍을 설명되지 않아 작성을 해본다.  뭐 겉핥기이니, 절차적 프로그래밍 vs 객체지향 프로그래밍 vs 함수형 프로그래밍 중에 뭐가 좋아요? 이 질문에 답변을 해본다면 절대 해당 프로그래밍 방식들은 비교대상이 아니다. 뭐 간단하게 C++로 구구단 출력을 작성한다고 생각해보자.  1. main 메서드에서 for문으로만 구구단을 절차적 프로그래밍으로 작성 할 수 있을 것이다.  2. GuguClass를 작성하여, 객체지향 프로그래밍으로 작성 할 수 있을 것이다.  3. C++11버전 부터 사용가능함 람다표현식으로 함수형 프로그래밍을 작성 할 수 있을 것이다.  위의 예제에서는 구구단만 노출 하면 되는 것이니, 1번이 제일 낫겠다 볼 수 있을 있지만, 객체지향 프로그래밍이 각광받았던 이유가 대형 서비스를 구축할 때 절차적 프로그래밍의 한계 때문에 각광 받았다.  하지만 생각해보라. Class로 쪼갤 뿐이지, Class 내부에서 복잡한 메서드를 작성하게 될 때, 결국 함수를 호출 할 것이니, 절차적 프로그래밍이다.  이 처럼 우리가 만들 서비스에 일부분은 절차적, 객체지향, 함수형 프로그래밍은 상황에 따라서 유용한 방식이 있을 뿐이다. 앞설이 길었으니, 함수형 프로그래밍을 소개해보자.  함수형 프로그래밍  일단 함수가 무엇일까? 프로그래밍 용어가 아닌 함수 말이다. 사실 당신은 중학교 수학 시간에 함수라는 단어를 들었다. 아래의 이미지를 보면 아! 할 것이다.  함수형 프로그래밍에서의 함수는 이 수학적 함수를 말하고 있다. 수학적 함수와 우리가 사용하는 함수의 차이는 수학적 함수에는 레퍼런스 참조가 없다는 점과 외부의 값에 의존하지 않는다. 뭐 더 수많은 차이가 있겠지만, 위키를 작성 중인 것은 아니니 그렇...

옛날 코드 다시 읽기 3 (XMLHttpRequest)

  ajax라는 단어를 아는가? Asynchronous JavaScript And XML의 약자이다. xml은 json과 마찬가지로 데이터의 포맷 중 하나이다. 요즘이야 일반적으로 사용하지 않는 데이터 형태라서 익숙하지 않을 수 있지만, 뭐 아예 찾아볼 수 없을 정도로 사라진 데이터 형태는 아니다.  하지만 우리가 axios, fetch, $.ajax등으로 비동기 호출을 할 때, 웬만하면 호출과 응답을 json형태로 보내지 xml 형태로 결과를 받거나 요청 시에 데이터형태로 사용하는 경우는 드믈다. 결론은 XML이라고 표기 되어있지만, 1999년 3월에 처음 만들어진 용어이고, json을 본격적으로 사용 한 건은 2000년대 초이기 때문에, 그저 네이밍의 실패 정도일뿐 xml을 굳이 알아야 할 필요는 없다고 본다.  XMLHttpRequest  XMLHttpRequest는 서버와 상호작용 할때 사용하는 수 있는 브라우저 내장객체이다. 2000년대 초에 처음 도입 되었다.  XMLHttpRequest에서의 xml 또한 ajax처럼 xml이란 단어가 거의 의미가 없어졌다. XMLHttpRequest 서버 호출시 json형태로 호출하는 것이 지금은 지배적이다. 뭐 물론 직접적으로 사용해 본 적이 없는 개발자도 많을 것이다. 특히나 $.ajax가 나온 후부터는 웬만해서는 직접 호출 사용할 일 없었던 객체이다.  그 이유는 사용법이 꽤나 불편하기 때문인데, 아니 반대로 $.ajax로 호출하는 것이 편했기 때문일 수도 있다. 이건 예시를 보여줄 테니 그때 확인해보자.  하지만 여러 라이브러리에서 XMLHttpRequest를 사용한다.  위의 이미지는  https://github.com/jquery/jquery/blob/main/src/ajax/xhr.js  코드의 일부분이다.  위의 이미지는  https://github.com/axios/axios/blob/...

타입 배열 만들기. (proxy)

 정적타입의 언어를 사용한다면, int arr[]; 이와 같이 정수만 들어가는 배열을 만들 수 있다. 하지만 javaScript는 동적 타입의 언어이다. 뭐 물론 정적타입이 필요하면 typeScript를 사용하는 것은 꽤 좋은 선택이다.  하지만, 지금 제안할 내용은 자바스크립트에서 간단하게 타입이 제한된 배열이 필요할 때 사용할 수 있는 방법을 소개하고자 한다.  Proxy  혹시라도 해당 단어를 처음 보는 분을 위해서 단어 뜻을 말하면 대리인 정도로 해석 하면 된다. 뭐 개발자라면 프록시 서버라는 말은 자주 들어봤을 거라고 생각한다.  기본적인 사용법은 아래와 같다. const target = [] const proxy = new Proxy (target , {}) proxy. push ( 1 ) proxy. push ( 2 ) proxy. push ( 3 ) proxy. push ( 'a' ) console . log (proxy. join ( ', ' )) // 1, 2, 3, a console . log (target. join ( ', ' )) // 1, 2, 3, a  proxy변수에 행해지는 행위가 target에 전달된다고 보면 된다. 지금은 proxy가 아무런 행위도 하지 않기 때문에, target을 직접 핸들링하는 것과 다르지 않다.  get 트랩  proxy에서 값을 읽을 때, 값을 읽을 때 실행 되는 트랩으로 기본 값을 특정값으로 쓰고 싶거나, 중간에 형변환이 필요할 때 사용 할 수 있다.  get(target, property, receiver): get메서드는 프로퍼티를 읽으려고 할 때 동작을 가로챈다.  target: 동작을 전달할 객체로 new Proxy의 첫 번째 이다.  property: 읽으려고 하는 속성의 이름이다.  ( 주의: proxy[0]과 같이 숫자를 전달해도 문자열 '0'이니 참조하기 바란다. ...

필요한 인자의 개수 구하기 (Math.max.length?)

  함수를 작성하는 사람은 해당 함수의 필요한 인자 개수를 알 수 있다. 또한 해당 함수를 사용하려는 사람도 해당 함수의 정의 코드를 확인하면 인자 개수를 확인 할 수 있을 것이다. 하지만 내장 함수의 경우는 어떠한가?  뭐 물론 아래 처럼 어떤 인자를 받을 수 있는지 확인이 가능할 것이다.  과연 우리가 max함수를 위와 같게 만들 수 있을까? 아니 그게 무슨 소린가? 이 블로그의 주인장은 프로그래밍을 이제 시작한 것인가? 라고 따져 들 수도 있을 것이다. 진짜 무슨 소린지 한번 표준 대로 만들어보자.  표준 <https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-math.max> 자 그러면 표준을 살펴 보자. 표준이 위와 같다. 잘 안보일 것 같으니 내용을 다시 작성해 본다면  Math.max( ...args ) 이 내용만 보면 ...values가 맞는 말이다. 하지만 제일 아래 줄을 보도록 하자.  이 함수의 "length"속성의 값은 2입니다.  자 간단하게 Math.max( ...args )를 만들어 보고 length가 2인지 확인 해보도록 하자. function max ( ...args ) { // 1. Let coerced be a new empty List. const list = [] /* 2. For each element arg of args, do a. Let n be ? ToNumber(arg). b. Append n to coerced. */ for ( const arg of args ) { const n = +arg list. push (n) } // 3. Let highest be -∞ 𝔽 . let highest = - Infinity /* 4. For each element number of coerced, do a. If nu...

두 배열 간의 연산.

 프로그래밍을 하다 보면, 두 배열 간의 연산이 필요한 경우가 많다. A배열에서 B배열에 있는 값을 제거한 C배열, A배열과 B배열에 같은 값만 추려낸 C배열, A배열과 B배열에 있는 값을 모두 갖고 있는 C배열.  차집합, 교집합, 합집합을 떠올렸다면 맞는 말이다. 지난 번에 소개한 lodash에 전부 가능하다.  차집합  1. _.difference  가장 간단한 함수이다. 두 배열 A와 B간의 차집합을 구한다. const a = [ 1 , 2 , 3 ] const b = [ 2 , 4 ] _. difference (a , b) // [1, 3]  A배열에서 B배열의 차집합을 구하기 때문에 1, 3을 구할 수 있다. 해당 함수는 원시값은 가능 하지만 레퍼런스 형에서는 아래처럼 모두 다른 값으로 판단 되기 때문에 전부 리턴한다. const a = [{ x : 1 } , { x : 2 } , { x : 3 }] const b = [{ x : 2 } , { x : 4 }] _. difference (a , b) // [{ x: 1 }, { x: 2 }, { x: 3 }]  2. _.differenceBy  특정 속성의 값을 비교하거나, 특정 값으로 변경하여 비교해야 하는 경우 필요하다. 바로 위와 같은 경우이다.  바로 아래와 같이 x를 확인하게도 만들 수 있다. const a = [{ x : 1 } , { x : 2 } , { x : 3 }] const b = [{ x : 2 } , { x : 4 }] _. differenceBy (a , b , 'x' ) // [{ x: 1 }, { x: 3 }]  또한 아래와 같이 특정 속성값이 아니라, 특정 속성들을 가지고 비교해야 할 수 있다. const a = [{ x : 1 , y : 2 /* ,v: 2*/ } , { x : 1 , y : 4 /* ,v: 4*/ } , { x : 2 , y : 2 /* ,v: 4*/ }] cons...

나는 내가 아니다.

  나는 특이한 문제를 좋아하는 편이다. 오늘은 최근에 본 특이한 문제를 소개 한번 해보도록 하겠다.  x !== x const x = ? if ( x !== x ) { console . log ( 'Hello, world!' ) }  x를 정의해서 'Hello, world!'를 출력 할 수 있을까? !==는 불일치 연산자이다. 값과 타입을 다른지 판별을 한다. 그런데 x가 x가 아니게 만들라니 참 특이한 문제이다.   == 왜 쓰지 말라는 걸까?  물론 위의 문제를 해당 포스트에서 제기하였다. ===(일치연산자)는 만능이 아니다.  x = NaN 이게 된다면, x !== x의 값이 참이되게 된다.  x === x + 1 const x = ? if ( x === x + 1 ) { console . log ( 'Hello, world!' ) }  이 문제는 무엇일까? === 일치연산자인데 x와 x + 1이 현실에서 똑같을리 없다. 뭐 물론 x < x + 1 이 값이 참이 되는 경우는 C언어를 공부하다보면 알게 되었을 것이다. 뭐 그렇다 오버플로우이다.  자바스크립트에서 허용 되는 가장 큰값 Number.MAX_SAFE_INTEGER(9007199254740991)에 1을 더하면 어떻게 될까? 자바스크립트에서는 그냥 더해질 뿐이다. (9007199254740992)  그렇다면  Number.MAX_SAFE_INTEGER(900719925474099 1 )에 2 를 더하면 어떻게 될까? 결과는 900719925474099 2  우리가 계산으로 컴퓨터를 이겼다.    당연히 우리는 900719925474099 3 인 것을 알고있다.  뭐 내용을 따져보면 IEEE-754(부동소수점 어쩌고저쩌고)  Number.MAX_SAFE_INTEGER의 이상의 값에서는 반올림을 하기 때문이라고 한다.  즉, x ...

이벤트 버블링 VS 이벤트 캡처 (이벤트 흐름)

  이벤트 버블링 및 이벤트 캡처는 이벤트의 흐름에 대해 설명 할 때 자주 언급 되는 단어이다. 하지만, 이벤트 캡처의 경우 특별한 설정 없이는 잘 상용 되지 않는 흐름이다 보니 해당 내용은 잘 모를 수 있다.  이번 포스팅에서 이야기 하고자 하는 내용은, 아래의 옵션이다.  addEventListener(type, listener, useCapture ) 이벤트 리스터를 등록 할 때 useCapture인자를 줄 수 있는데, 이건 과연 뭘까? 간단하게 알아보자.  이벤트  이벤트는 무엇일까? 간단하게 말하면 javascript와 html간에 상호작용을 말할 수 있다. 가장 간단한 예로는 click이벤트 가 있을 것이다. html에서 click이 발생 했을때, javascript의 리스너를 통하여 어떤 행위를 하는 것. 뭐 물론 script에서도 event를 발생 시킬 수 있다.   이벤트의 흐름  이벤트의 흐름이라고 하면 이벤트가 발생 되는 순서라고 인지 하면 된다. 기본적으로 window객체에서 이벤트를 발생(트리거) 시켜야 한다. 자 여기서 생각을 해볼 만한 것이 있다. 과연 당신이 이벤트의 흐름을 개발해야 한다고 생각해보자. 이벤트의 시작은 window여야 한다. window에는 document(dom)을 갖고 있다.  간단하게 위와 같은 dom트리에서 DIV를 click하였다고 생각해보자.  그러면 DIV를 window에서 추적을 해보자.  window => document => html => body => div 이렇게 도달하게 된다. 자 그렇게 하고 나서 당신은 div에 연결되어있는 click 리스너를 실행 시켜줄 것이다.  그렇다면 body에도 click리스너가 등록 되어있다면 어떻게 할 것인가? div에 click리스너보다 body의 click리스너를 먼저 호출 할 것인가? div의 이후에 호출 할 것인가?  ...

try catch 더 써보자.

  try...catch는 예외처리를 하기 위한 문법이다. 뭐 문법에 대한 설명을 할 것은 아니니, 필요하다면, 아래의 링크를 열어서 문법을 확인 해보도록 하자. https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/try...catch   예외: 일반적 규칙이나 정례에서 벗어나는 일.  예외라는 말은 위에서 나타나는 것처럼 일반적 규칙에서 벗어난 일을 뜻한다. 하지만, 몇몇 개발자들은 예상이 불가능한 상황을 예외라고 생각하는 버릇이 있는 것 같다. 무슨말이냐 하면...  자신이 예상 가능하여 if...else로 처리 가능한 모든 상황은 예외라고 판단을 하지 않는 것 같다는 말이다. 나의 경험으로는 예전에는 try...catch를 해야 하는 상황을 오류로 인식했었다.  try...catch vs if...else  즉 내가 하고자 하는 말은 아래와 같다. 고객의 정보를 불러오는 api가 있고 거기에서 사용자의 이름을 가져오고자 한다. 그때의 코드를 if...else로만 처리한다면... // 고객 정보 불러오기 . fetch ( '/api/person/100' ). then ((response) => { // 해당 호출이 항상 성공 할 수는 없기에 예외 if (response. status === 200 ) { // 해당 호출의 결과가 JsonString 이 아닐 수 있음 . if (! checkJsonString (response. text ())) { return { errorCode : ` ${response. status } 0` , errorMessage : ' 응답 데이터를 파싱할 수 없음 .' } } else { const res = response. json () // 원하는 데이터는 Object 이나 ...

[ HTML ] tabindex 키보드 포커스

 tabindex는 해당 엘리먼트를 포커스 가능하게 해준다. 이름으로부터 알 수 있듯이, "tab"으로 접근 하게 되는 순서를 결정할 때 사용할 수 있다.  회원가입이나 로그인을 위하여 우리는 tab을 자주 활용한다. 기본적으로 사용자의 입력을 받는 input류의 태그들은 포커스(키보드 입력)를 받을 수 있다.  tabindex를 활용하면 포커스를 지원하지 않는 태그에도 불구하고 해당 엘리먼트에 포커스에 포커스를 지원을 할 수 있다. 마우스를 사용 할 수 없는 사용자에게 악영향을 끼치기 때문에 지양하자.  예/아니오 vs 아니오/예  퍼블리싱을하다보면, 디자인과 태그상에 논리적 순서가 맞지 않는 경우가 생기기도 한다. 예를 들면 나는 취소를 그 예로 들고 싶다.  예/아니오의 순서 논쟁은 꾸준히 있어왔다. 과연 누가 옳은 것인가? 이건 누가 옳다/틀리다를 말할 내용은 아니다. 서로 다를 뿐이다. 세간의 말에 따르면....  "예/아니오"의 경우 긍정을 하는 경우가 더 많으니, 예가 먼저온것이고,  "아니오/예"의 경우 예를 누르기 전에 부정할 수 있는 옵션이 있다고 알려주는 것이라고 한다.  아니오/예  내가 이야기하고자 하는 부분은 "아니오/예"를 개발할 때 생기는 디자인과 논리적 순서상의 오류이다.  간단하게 컨펌창을 퍼블리싱을 한다고 해보자. <div> <div> 어쩌고 저쩌고 동의 ? </div> <div><button> 아니오 </button><button> 예 </button></div> </div>  뭐 태그는 어찌되었든 "아니오/예"를 개발하는 경우 위와 같은 형태가 될 것이다. 개발자라서 정확히 어떠한 이유가 있는지는 몰라도, 디자이너들은 맥을 쓰는 것을 선호한다. 뭐 물론 개발자들도 맥을 선호하는 비중은 꽤나 높다. ...

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이면 접근 가능하다 정...