기본 콘텐츠로 건너뛰기

라벨이 javscript인 게시물 표시

옛날 코드 다시 읽기 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/...

메서드 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을 가져올 수 없게 되었다. 해당 내용이 의아 할 수 있는데, 간단하...

웹에 제스처 적용해보기 ( hammerjs )

 스마트폰이 나오고 나서 모바일에서 사용하는 유저의 액션은 엄청 늘어나기 시작했다. 간단하게 마우스 클릭과 유사한 탭 부터 마우스 휠에 대응 되는 핀치, 스프레드, 터치가능한 디바이스에서만 가능한 투탭(두손가락으로 터치) 이상의 행위들...  우리는 사용자의 경험에 맞게 개발을 하여야 한다. 무슨말이냐 하면, 모바일기기에 휠이 없다고 해서 확대해 가면서 보아야 하는 컨텐츠를 마우스를 무조건 연결하여 보아야 하는 것은 말이 안된다는 뜻이다.  Hammerjs  여기서 우리의 개발을 편하게 만들어 줄 수 있는 라이브러리가 있다. Hammerjs가 지원하는 제스처는 아래와 같습니다. Tap : 클릭과 같습니다. Press : 일정시간 이상 같은곳을 누르고 있습니다. Pan :  포인터가 특정위치를  클릭후 한 방향으로 이동시 발생 합니다. Swipe : 포인터가 특정위치를  클릭후 한 방향으로 특정시간 정도 특정거리 이상 이동시 발생합니다. Pinch : 두개 이상의 포인터가 특정방향에서 멀어지거나 가까워질때 발생 합니다. Rotate : 두개 이상의 포인터가 원을 그리게 되면 발생합니다.  위에서 보면 pinch와 rotate의 경우에는 두개이상의 포인터가 필요하여 마우스 만으로는 불가능한 액션이지만, 나머지는 하나의 포인터만으로 가능한 제스처이기에 충분히 마우스만으로 구현이 가능한다.  사용해보기  모바일과 PC에서 같이 사용해볼수 있는 Swipe 제스처를 사용해 보도록하자.  위 처럼 간단하게 스와이프 제스처를 추가해볼 수 있다. 이것저것 사용해보면 트렌디한 웹사이트를 만드는데에 꽤나 도움이 될 것 이다.

자바스크립트 이모저모

 1. Javascript Prototype 자 아래의 코드를 보고 이상한 점을 찾아보자. function Human ( name ) { this . name = name this . sayHello = function () { console . log ( ` 안녕하세요 . ${ this . name } 입니다 .` ) } } const sejiwork = new Human ( 'sejiwork' ) const sejinjja = new Human ( 'sejinjja' ) sejiwork . sayHello () //output: 안녕하세요 . sejiwork 입니다 . sejinjja . sayHello () //output: 안녕하세요 . sejinjja 입니다 . console . log ( sejiwork . sayHello === sejinjja . sayHello ) // output: false Human으로 만들어지 sejiwork, sejinjja객체에는 같은 동작을 하는 sayHello 함수가 각각 자신의 객체에서 정의가 되었다. 결과적으로 똑같은 일을 하는 함수임에도 불구하고, 불필요한 일을 하게 된 것이다. 위의 코드를 prototype을 이용하여 수정해보자. function Human ( name ) { this . name = name } Human . prototype . sayHello = function () { console . log ( ` 안녕하세요 . ${ this . name } 입니다 .` ) } const sejiwork = new Human ( 'sejiwork' ) const sejinjja = new Human ( 'sejinjja' ) sejiwork . sayHello () //output: 안녕하세요 . sejiwork 입니다 . sejinjja . sayHello () //output: 안녕하세요 . sejinjja 입니다...

알면 쓸만한 자바스크립트 배열 함수

 1. 배열에서 중복 데이터 제거. const data = [ 'sejiwork' , 'sejinjja' , 'sejinjja' , ' 홍길동 ' , ' 홍길동 ' , ' 홍길동 ' , ' 홍길동 ' ] const uniqueData = Array . from ( new Set ( data )) console . log ( 'uniqueData' , uniqueData ) const uniqueAlpha = Array . from ( new Set ( 'sadfsdafas' )) console . log ( 'uniqueAlpha' , uniqueAlpha )  위 처럼 Set은 생성자의 인자로 iterable 객체를 받을 수 있고, 해당 데이터에서 중복이 없어지는 특징 을 같고 있고,   Array.from은 length속성과 인덱싱된 요소를 같는 유사배열객체와, map과 set처럼 순회가능한 객체를 이용하여 배열을 만들 수 있기 때문에 간단하게 두가지를 이어서 중복을 제거 할 수 있다. 2. 배열 자르기 (앞에서) const data = [ 'sejiwork' , 'sejinjja' , 'sejinjja' , ' 홍길동 ' , ' 홍길동 ' , ' 홍길동 ' , ' 홍길동 ' ] data . length = 3 console . log ( data ) 배열의 길이를 변경만 해주었을 뿐인데, 앞에서 3개만 남았다. const stringData = 'abcde' stringData . length = 2 console . log ( stringData ) 아쉽게도 문자열은 지원하지 않는다. https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Gl...

this는 누구인가

 this... 객체지향 프로그래밍을 배우다 보면 객체 자기 자신을 지칭하는 키워드 이다. 즉 한번 결정 되면 객체 자기 자신만 지칭을 하고 변하지 않는데...  과연 자바스크립트에서도 그럴까? function Person (name) { this . name = name } Person . prototype . introduce = function () { console . log ( `My name is ${ this . name } ` ) }  위와 같이 적당히 객체지향 언어처럼 Person클래스를 만들고 메소드로 introduce를 추가해줬다. this.name이 어떻게 행동되는지 보시면 되겠다.    여기까지는 예상하는봐와 같이 각각을 잘 소개 하는 것을 볼수 있다.  자 상황을 바꾸어 보자 객체가 생성되고 최소 2초가 지난 후에 자기소개를 하는 코드를 만들어 보자.    코드를 보면 위와 다른 점이라고는 setTimeout을 통해서 호출 하는 것만 바뀌었지만... 둘다 이름을 잃어 버린걸로 보인다.  setTimeout에 introduce 바로 넣어 주는가와 함수를 한번 감싸서 넣어 주는 것과의 차이이다.  왜 그럴까?  첫번째 예제는 setTimeout에 sejiWork.introduce 함수 그 자체를 인자로 넘겨 주었다. 코드로 보면... setTimeout ( function () { console . log ( `My name is ${ this . name } ` ) } , 2000 )  위와 같은 코드로 볼 수 있다. 하지만 그 아래의 코드는 sejiWork객체가 introduce함수를 실행 시키는 코드이다.  즉 this는 호출자에 의해 결정 된다고 볼 수 있다.

비동기 코드를 처리 하자

 이번 포스트에서는 비동기처림에 대한 간단한 처리만 해보고 넘어 가고자 한다. callback, promise, async await을 모르는 분만 읽기를 바라며 그저 간단하게 사용법을 소개 하는 포스트이다.  웹 개발뿐만 아니라 네트워크로 통해서 들어오거나 외부 레거시 코드를 실행하는 경우, 즉시 값이 리턴을 받지 않고, 해당 네트워크 혹은 레거시에서 처리후 callback을 통하여 실행 되는 경우가 많다.  이러한 경우를 처리를 해보자. function getDir ( path , callback ) { if ( typeof callback === 'function' ) { setTimeout ( () => { callback( [ 'Documents' , 'Download' , 'Etc' ] ) } , 1000 ) } }  위 처럼 해당 path에 있는 폴더들을 확인 하고 그 폴더들가지로 callback을 호출해주는 코드이다.  우린 위처럼 콜백 함수를 넣어서 순회를 할 수 있다.  예전에 구현해둔 map을 이용해서 적절하게 순회도 가능하다.  자 그렇다면 test 폴더안에서 Etc 폴더를 찾아서 그 안의 폴더인 Donwload 폴더를 찾아보면 어떤 코드가 될까?  위와 같이 표현이 될 수 있다. 그렇다면 점점 더 상세한 폴더가 필요 하게 되면 어떻게 될까?  즉 test/Etc/Download/Download/Download/Download/Download/Download 처럼 말이다.  코드는 점점 안쪽으로 들어가서 코드가 파악하기가 점점 복잡해진다. 위는 그나마 간단한 요구 조건이라서 덜 복잡해보이는 감이 있다.  getDir에다가 Promise를 입혀보자. function getDirPromise ( path ) { return new Promise (resolve => { ...

1000만 개 중에 2개 주세요(게으른 평가)

 요구조건으로 이런것이 왔다고 쳐봅시다.  서비스 개발한 서비스의 사용자의 데이터에서 포인트의 누적을 자신의 가족 수를 곱하고 그 값이 1000점 이상인 사람들 중에서 해당 포인트의 제곱근이 소수점을 버리고 홀 수 인 사람 중에 두사람의 마지막 계산된 포인트를 뽑아달라는 요청이 왔다.  ( 말도 안되는 시나리오지만 아 그렇구나 하고 넘어가자. )  일단 저 2명을 뽑기 위해서 take라는 함수를 구현해봅시다.   const take = ( count , iter ) => { const res = [] for ( const item of iter ) { res. push ( item ) if ( res. length === count ) return res } return res } 잘 동작 합니다. 고객 정보가 없기 때문에 적당히 고객정보를 구현 할 수 있도록 range도 구현을 해봅시다. const range = ( limit ) => { const res = [] let count = 0 while ( count < limit ) { res. push ( count++ ) } return res } 이제 샘플로 사용 할 고객 정보를 임의로 만들 수 있도록 함 수 하나를 만들겠습니다. 위 시나리오상 가족수랑 포인트만 있으면 되겠네요. const genMember = () => { return { family : Math . ceil ( Math . random () * 8 ) , point : Math . ceil ( Math . random () * 8000 ) } } 적당히 만들었습니다. 그러면 이제 1000만명을 만들어서 위의 로직을 돌려보도록 하죠. 저의 PC가 못버티는 관계로... 10만명으로 하겠습니다. const members = go ( range ( 1000000 ) , map ( genMember ) )...

map, filter, reduce (go, curry)

 간단하게 map, filter, reduce를 구현해보자. 1. map은 인자를 두개를 받으며, 첫번째 인자를 받아서 두번째 인자로 평가 후 배열로 리턴해준다. const map = ( iter , func ) => { const ret = [] for ( const item of iter ) { ret. push ( func( item ) ) } return ret }  위와같이 간단하게 짤 수 있다. 2. filter를 구현해보자 map과 두개의 인자를 받으며, 첫번째 인자를 받아서 두번째 인자로 평가 후 값이 있다며 배열로 리턴을 해준다. const filter = ( iter , func ) => { const ret = [] for ( const item of iter ) { if ( func( item ) ) { ret. push ( item ) } } return ret }   3. reduce는 세개의 인자를 받으며, 첫번째 인자를 받아서 두번째 인자로 받은 함수로 평가하며 축적된 값을 리턴을 한다, 이때에 세번째 인자를 초기값으로 이용한다. const reduce = ( iter , func , acc ) => { for ( const item of iter ) { acc = func(acc , item) } return acc }  이와 같이 표현 할 수 있지만, 초기값을 안넣은 경우에는 iter의 첫번째 값을 초기값으로 사용하게 변경 해보자. const reduce = ( ...args ) => { let iter = args[ 0 ] const func = args[ 1 ] let acc = args[ 2 ] if ( args. length < 3 ) { iter = iter[ Symbol . iterator ]() acc = iter. next (). value } ...

for of (feat.iterable)

 ES6부터 새로 생겨난 for of에 대해서 궁금증이 생겨서 학습안 내용을 포스트에 남깁니다. const arr = [ 1 , 2 , 3 , 4 ] for ( const value of arr ) { console . log ( 'value' , value ) } const set = new Set ([ 1 , 2 , 3 , 4 ]) for ( const value of set ) { console . log ( 'value' , value ) } const obj = { 0 : 1 , 1 : 2 , 2 : 3 , 3 : 4 } for ( const value of obj ) { console . log ( 'value' , value ) } Array, Set은 for of 문장으로 반복이 되지만, Object는 반복이 되지 않는가? obj is not iterable 인데, 반복할 수 없다 정도록 해석이 가능 할 것 같다. for of구문을 확인해보면 아래와 같다. iterable이 무엇인가? 간단하게 말하면 iterator를 생성할 수 있는 모든객체를 말 할 수 있다. 그러면 iterator는 무엇인가? 반복자를 말한다. 저 단어는 많은 개발자들이 많이 들어 보셧을 것이기 때문에 이하 생략한다. 여기서 더 중요한것은 for of는 무엇을 반복자로 받아 들이는가? 이다. 이에 대한 내용은 ES6에 추가된  protocol인   iterable protocol 과 iterator protocol을 확인 할 필요가 있다. 이 기준에만 충족을 한다면 자바스크립트의 for of에 적용 할 수 있다. protocol 두가지는 아주 심플하다. iterable protocol: 내용을 살펴 보면 Object 혹은 prototype chain 의 오브젝트 중 하나가 Symbol.iterator key의 속성을 가지며 값이  iterator protocol을 충족 시킬수 있는 값을...