기본 콘텐츠로 건너뛰기

라벨이 javascript인 게시물 표시

Void 다시 돌아보기.

  옛날 코드에서는 void라는 키워드를 자주 보았을 것이고, 리턴 타입을 정의해야하는 언어를 사용하는 개발자라면, 수도 없이 보았을 만한 키워드이다.  하지만, 자바스크립트 기준으로 생각을 해보자. void function test () { console . log ( 'called test' ) } test()  위와 같은 코드르 보자, 자바스크립트를 배우지 않았지만, c라이크 언어를 배운 사람이라면, 아 test함수에는 반환값이 없구나 하고, 넘어갈 코드이다. 하지만....  Uncaught ReferenceError: test is not defined  저 코드에는 test자체가 존재 하지 않는다. 옛날의 자바스크립트에서는 undefined가 읽기 전용 이 아니라, 쓰기가 가능한 변수였다. 그래서 undefined를 재정의 할 수 있었기에, undefined = void 0 ; function foo (undefined) { var a ; console . log ( a === undefined ) } foo ()  위 처럼 void가 평가가 항상 undefined인 것을 고려하여, 위와 같이 undefined를 안전하게 관리하거나, 함수의 가장 마지막 인자를 항상 undefined로 이름으로 정의하여, undefined를 안전하게 관리 하였다.  이젠, undefined를 재정의 할 수 없으니, 절~~대 사용하면 안되는 방식이다.  그렇다면, 이제 void 키워드는 더 이상 쓰지 않을만한 내용일까? https://sejiwork.blogspot.com/2021/10/javascript-pseudo-protocol.html  a 태그 사용 시 click 이벤트만 사용 할 때에 사용 할 수 있긴 하지만.... 이걸 써야 할 까? 이 생각은 머리에서 떠나지 않는다. button태그가 있는데 굳이?  우리는 자바스크립트 사용자라면, function ...

arguments 파해치기.

 사실 arguments는 그리 자주 쓰는 객체는 아니다. 하지만 화살표 함수( arraow function )를 배우는 사람이라면 화살표 함수( () => {} ) arguments가 없다는 설명을 들은 적은 있을 것이다.  오늘은 arguments가 어떤 속성을 가지고 있는지, 또 어떤 상황에서 사용 할 수 있을지 확인 해보도록 하자. 예제 코드를 위주로 다룰 터이니 한 번 살펴보고 적절한 상황에서 사용해보자.  arguments? function foo (a , b) { console . log (a , b) // 1 2 console . log (arguments) // Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ] } foo ( 1 , 2 )  일반 함수(function)에서 사용 할 수 있는 객체로 함수 호출시의 인자들을 확인 할 수 있다.  => a, b는 매개변수(parameter) foo( 1, 2 ) 인자(argument)라고 보면 된다.  함수 호출 시의 값을 알 수 있기에,  function foo (a , b) { console . log (a , b) // 1 2 console . log (arguments) // Arguments(2) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] } foo ( 1 , 2 , 3 )  위와 같이 정의 되지 않은 매개변수도 받을 수 있다.  arguments.length  arguments는 길이를 가지고 있다. 인자의 갯수를 알려준다. 하지만 배열은 아니다. 정확히는 키와 값을 가지고 있는 Map에 더 가까운 구조를 가지고 있다. 아래의 JSON.stringify만 보더라도 확인이 가능하다. function foo (a , b) { console . l...

reduce?

 reduce는 함수형 프로그래밍을 공부하면, 항상 보게 되는 함수이다. 처음 reduce라는 함수를 마주쳤을 때, 굳이 이런 함수를 사용해야 하나, 이런생각도 해보기도 하고, 왜 감소하다라는 뜻을 갖고 있는 reduce이지? 이런생각을 해보기도 했다.  reduce는 reducer 함수에 의한 결과를 누적 해 주는 함수이다. 누적이라는 말에서 accumulate라고 불러야 하는거 아닌가? 하고 아직도 생각 하고 있는 함수이다.  reduce의 함수 reduce ( reducer : (accumulator: Any , current: Any ) => Any , initialValue: Any ) => accumulator: Any  javascript에는 Array가 이미 reduce를 지원을 하고 있기에, 아래와 같이 사용이 가능 하다. [ 1 , 2 , 3 ]. reduce ( (accumulator , current) => accumulator + current , 0 ) // 6  구현을 해보자 한다면, 아래와 같이 간단하게 구현이 가능하다. function reduce ( arr , reducer , initValue ) { let accumulator = initValue for ( let idx = 0 ; idx < arr. length ; idx++ ) { accumulator = reducer( accumulator , arr[idx] , idx , arr ) } return accumulator }  Array.reduce와 마찬가지로 사용이 가능 하다. reduce ([ 1 , 2 , 3 ] , (accumulator , current) => accumulator + current , 0 ) // 6  reduce로 만들어보기  reduce는 기본적으로 반복을 하기 때문에 forEa...

자바 스크립트 희소 배열.

  희소 배열이라고 들어보았나? 학부생 때 교양 혹은 전공으로 선형대수를 배웠다면, 희소 행렬이라고는 들어보았을 것이다. 들었지만 아마 기억에는 없을 수도 있겠다. 행렬에 0이 비교적 많은 행렬을 희소 행렬이라고 부른다. 0이 많다는 것은 데이터가 없다는 것으로 볼 수 있다.  뭐 물론 프로그래밍을 하면서 배열에 0이 많다고 해서 희소 배열이라고 부르지는 않을 것이다.  희소 배열  아마 알고리즘 연습을 하는 사람들은 아래와 같이 배열의 개수를 초기화하는 코드를 작성 해본 사람이 있을 것이다. let a = [] a. length = 30  인풋이던 아웃풋이던 30개로 고정되어야 하는 상황 같은 때 말이다. 위의 결과는 무엇일까? 아마도 위와 같은 코드를 작성해본 사람이라면 알 것이다.  empty가 30개 있다고 한다. 일단 난 희소 배열의 정의를 empty가 하나라도 있는 상황을 희소 배열이라고 부르겠다.  희소 배열을 만드는 방법은 아래처럼 더 있다. delete를 사용 한다던가 일부러 초기화를 안 하는 경우다. let a = [ 1 , 2 , , 4 ] delete a[ 1 ]  empty?  그래 희소 배열이 존재 하는 것은 알았다. 그러면 왜 알아야 하는가? 이것이 궁금할 수도 있다.  일단 하나만 집고 넘어가자 empty는 값도 아니고, 예약어도 아니다. 저장할 수도 없고, 읽을 수도 없다. 우리에게는 데이터가 없다는 표현으로 undefined가 있다.  하지만 empty와 undefined는 다르다! 자 아래 실험을 보자. let a = [ 1 , , 3 ] a[ 0 ] = a[ 1 ]  분명 empty의 값을 갖고 있는 1번 인덱스에서 값을 가져와 0번 인덱스에 값을 삽입 하였으나, undefined가 되어버렸다.  이는 자바스크립의 배열 객체에서 1번 인덱스를 읽는 상황에서 undefined를 리턴 하였기 때문 이라 추측 된다. ...

타입 배열 만들기. (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...

나는 내가 아니다.

  나는 특이한 문제를 좋아하는 편이다. 오늘은 최근에 본 특이한 문제를 소개 한번 해보도록 하겠다.  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 ...

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 이나 ...

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이 되었을 때 호출이 ...