4-1 뽀개 버리기

i do as i say·2020년 2월 13일
0

내가 뽀개질지도 모르지만 뽀개 버리겠습니다.

Achievement Goals 💥

  • Review: 함수형 프로그래밍의 특징을 이해할 수 있다

    • 함수를 인자로 넘기는 방법에 대해 이해할 수 있다.
    • callback 이라는 용어에 대해 이해할 수 있다.
    • callback을 실행하는 함수를 만들 수 있다.
/* 함수를 인자로 넘기는 방법? -> 콜백 함수.
콜백 함수는 배열 메소드에서 많이 보이는데, (물론 아닌 경우도 훨씬 많지만 일단 지금까지의 내 상황에서는 그러했음.) filter나 map 등, 순환하는 메서드에서 해야 될 일을 담아 인자로 넘겨진다. */
function callback(number) { return 4 > element }

let lottoNumber = [12, 34, 1, 15, 26, 11];
lottoNumber.filter(callback); // [1]

/* 콜백이란? 말 그대로 call 하면 back 하는 함수라고 말하면 조금 양아치처럼 보이려나. 함수를 하나 만들어 놓고, 사용자가 원하는 적재적소에 넣을 수 있는 게 콜백 함수인데, 약간 의미는 다르지만 축구 벤치 선수라고 생각하면 편하다. 보통, 음, 어떠한 함수에서 다시 콜백 함수를 쓸 땐, 사용자에게 어떠한 행위를 할 것인지에 대한 권한을 넘겨 준다고 봤었던 것 같다. 그러니까, 저 필터 함수를 사용하려고 했을 때 콜백 함수가 들어오게 되는 궁극적인 뜻은, 걸러지는 게 어떠한 것인지 너에게 맡기겠다,는 뜻이 된다. 맵이나 리듀스, 이벤트 핸들러도 마찬가지이다. 콜백 함수는 이름을 붙여도 되고, 붙이지 않아도 된다. 만들어서 사용할 수도 있고, 일회성으로 사용하고 버릴 수도 있다.*/

let button = document.getElementById(btn);
button.addEventListener('click',hello);

function hello() { console.log('hello, world!') }
  • 비동기 호출

    • 비동기 호출의 code 패턴을 작성할 수 있다
    • setTimeout 등의 비동기 호출 함수를 이용할 수 있다
      (Advanced) JavaScript 엔진이 어떠한 형태로 비동기 호출을 하는지 그 원리를 이해할 수 있다
/* 생활 코딩에서 비동기 호출에 대한 예시를 조금 들었었는데, 어떠한 페이지를 사용할 때, 작은 알림 페이지를 띄운다든지 하는 게 비동기적 호출이고, 페이지를 띄우는 게 동기적 호출이라고 나왔었다. 매우 이해가 빠른 예시였다. */

//동기적 호출은 짱구가 초코비를 받고 먹을 때까지 철수는 아무것도 하지 못한 채 짱구의 뒤에서 기다려야 한다.
1. 짱구가 초코비를 주문한다.
2. 초코비를 찾는다.
3. 초코비를 가져다 준다.
4. 짱구가 초코비를 먹는다.
5. 철수가 라무네를 주문한다.
6. 라무네를 찾는다.
7. 라무네를 가져다 준다.
8. 철수가 라무네를 먹는다.

//비동기적 호출은 짱구와 철수의 주문은 막힘이 없고, 그들의 주문은 뒤에서 찾은 후, 주문에 대한 요구 조건이 충족이 되면 짱구와 철수를 부른다.
1. 짱구가 초코비를 주문한다.
1-1. 초코비를 찾는다.
1-2. 초코비를 찾게 되면, 짱구를 부른다.
1-3. 짱구가 초코비를 먹는다.
2. 철수가 라무네를 주문한다.
2-1. 라무네를 찾는다.
2-2. 라무네를 찾게 되면, 철수를 부른다.
2-3 철수가 라무네를 먹는다.

/* 동기적 호출을 코드로 작성 */
function waitSync(ms) {
  var start = Date.now();
  var now = start;
  while(now - start < ms) {
    now = Date.now();
  }
}// 딜레이 함수
  
let kiz = [
  { name: '짱구', request: '초코비' },
  { name: '철수', request: '라무네' }
  ];

function orderSnack (snack) {
  console.log(snack + '를 주문받았습니다.');
  waitSync(2000);
  return snack
}
  
function eat (name, snack) {
  console.log(name + ' 는' + snack + '를 먹습니다.');
}
  
  //주문하는 과정
kiz.forEach(function(child) {
  let snack = orderSnack(child.request);
  eat(child.name , snack);
});

/* 비동기적 호출을 코드로 작성 */

function waitAsync(callback, ms) {
  setTimeout(callback, ms); // 특정 시간 이후에 callback 함수가 실행되게끔 하는 브라우저 내장 기능입니다
}
  
let kiz = [
  { name: '짱구', request: '초코비' },
  { name: '철수', request: '라무네' }
  ];

function orderSnack (snack, callback) {
  console.log(snack + '을 주문받았습니다.');
  waitAsync(function() {callback(snack)}, 2000); //주문 일단 받고 나중에 나머지들을 실행하렴
}

function eat (name, snack) {
  console.log(name + '는 ' + snack + '를 먹습니다.');
} //그 나머지들은 얘네가 될 거야

//주문하는 과정
kiz.forEach(function(child) {
  orderSnack(child.request, function callback(snack) {
    eat(child.name, snack)})
})

/*비동기 호출 함수*/
//앞에는 꼭 함수가 들어가야 함.

setTimeout(function() {console.log('a = 100')}, 3000);
// 몇 초 뒤에 찍히는 함수

setInterval(function() {console.log('a = 100')}, 1000);
// 몇 초 뒤에 찍히는 함수가 계속 반복

clearTimeout(id) / claerInterval(id)
//위의 함수들을 정지시켜 줌. 인터벌 같은 경우엔 뒤에 초를 붙이면 그 초까지만 인터벌이 되고, 다음부터는 되지 않음.

//이 함수들은 항상 this가 window이다.
//그렇기에 클로저를 사용할 때 원하지 않는 값이 나올 수 있다.
//그것은 .bind()로 해결이 가능하다.
  • 서버 요청하기

    • 클라이언트와 서버의 개념을 이해할 수 있다
    • fetch를 이용한 HTTP 요청을 통해 서버에 있는 정보를 가져올 수 있다.
/* 클라이언트는 주문하는 사람이고, 서버는 주문한 것을 전달해 주는 곳? 사람까지는 아니고, 장소? 자판기 같은 느낌? 정보를 모아 놓고 있는 곳. 게임이라고 생각을 해 볼 수도 있겠다. 클라이언트는 유저이고, 서버는 말 그대로 게임의 서버. 닫힐 수도 있고, 열릴 수도 있다. 게임 안에 있는 모든 정보들은 서버 안에 있다. 유저는 싸우고 싶다거나, 퀘스트를 받고 싶다거나 하는 등 서버에게 요청을 하고, 서버는 그 요청을 처리한다. 그렇게 게임이 진행된다. */

//fetch를 이용한 HTTP 요청
//랜덤 유저 생성기를 이용한 fetch 활용하기
/* fetch에 대한 설명이 되게 잘 되어 있는 글.
https://justmakeyourself.tistory.com/entry/fetch-api */

fetch('https://randomuser.me/api/?results=10')
//?results=숫자 를 쓰면 원하는 사람의 수만큼 가지고 올 수 있음.
.then(function (response) { return response.json() })
.then(function (json) { console.log(json) })

/*
fetch는 술책, 가져옴이라는 뜻인데, 개발 언어가 진짜 직관적이라는 걸 다시 깨닫는다...
fetch에 가지고 오고 싶은 api 주소를 작성한다. 그렇게 되면 promise라는 게 뜨는데, 말 그대로 약속이다. 가져다 달라고 한 것에 대한 응답. 비동기 호출이기 때문에 정보를 수집하는 데에 늦을 수도 있기 때문에 그러한 용어를 쓰지 않았을까 하는 생각이 있다.
뒤의 .then 문구를 두 번 쓰면 정보를 가지고 오는 건 끝난다. 받아온 정보(response)를 어떻게 다룰지 정하고 return response.json() (여기에는 html이 들어올 수도, 다른 게 들어올 수도 있음.)
변환한 정보를 콘솔 로그에 찍어 보았다. 이제 이것을 가지고 활용하면 된다.
*/
  • this keyword (optional)

    • execution context가 언제 생성되며, 어떤 내용을 담고 있는지 이해할 수 있다
    • this 키워드에 값이 바인딩되는 다양한 형태를 이해할 수 있다
    1. global this
    2. function invocation
    3. method invocation
    4. construction mode
    5. .call(), .apply() / 이건 함수 메소드 할 때 같이
/* execution context? -> 실행 컨텍스트
실행 컨텍스트에 대해서 많이.. 듣지 않았지만, 아무튼, 찾아 보면 엄청나게 많은 정보들이 나온다. 음, 일단 이 실행 컨텍스트와 this를 동일시하게 보는 혹자들도 있다. (다르긴 하지만) 나도... 그렇게 생각을 한다. 일단 이 실행 컨텍스트라는 건, 함수를 하나 생성할 때마다 생성이 된다. 함수를 1 개 만들었다면 실행 컨텍스트도 1 개 생성이 된다. 실행 가능한 코드를 담는 환경이라고 생각하면 편하다.

함수 1 개에 담겨 있는 메모리가 생성이 되었으니, 당연히 메모리를 담는 칸도 1 개가 생성이 되어야 짝이 맞다. 정각병이나 정시병, 짝수병을 앓고 있는 많은 한국인들의 니즈를 충족시킬 수 있다. (??)

음, 실행 컨텍스트가 코드를 실행시키려면 몇 가지의 정보를 알고 있어야 된다.
1. 변수와 스코프 지역 내의 변수 및 함수
2. 전달 인자
3. 호출된 근원
4. this

자바스크립트 엔진은 이를 형상화하고 구분하기 위해 실행 컨텍스트(의 정보들)를 물리적인 객체의 형태로 저장을 한다.

어떠한 것을 실행시킬 때, 콜스택이라는 곳에 실행 컨텍스트가 들어왔다가 실행이 되고, 다 쓴 것들은 소멸이 되는 방식으로 엔진이 작동한다.
제일 아래에서부터 차근차근 쌓아 올린 다음, 위에서부터 해결하는 것이다. 우리가 콘 아이스크림을 먹는 것처럼.

실행 컨텍스트를 자세하게 작성한 블로그.
https://poiemaweb.com/js-execution-context

this?
디스는 실행 컨텍스트가 실행되면 자동으로 생기는 특수한 식별자인데, 걍걍 집주인이다. 집은 곧 집주인 거니까, 집주인이 누구인가에 따라서 세입자들의 운명이 갈리는 것처럼.. ^^ 비슷하다. 집주인은 집에 대한 권리만을 행사할 수 있으므로 해당 실행 컨텍스트 안에서만 유효하다. 그러니까, 그 집(호출자)이 어떠한 것인 가에 따라서 집주인(디스)의 성격이 바뀐다.

this에는 다섯 가지 패턴이 있다..지만 1,2,3은 똑같은 것 같은 느낌이. ^^ㅎ

1. this는 원래부터 window의 것이다. 왜냐하면, 공기처럼 은연 중에 깔리는 전역객체(window)가 있기 때문에 this는 window의 것이다.

2. function invocation. 함수를 호출해도.. this는 window의 것이다. 왜냐하면, fn(){console.log(this===window);}를 작성할 때 우리는 항상 앞의 window.를 생략하고 쓰기 때문이다.

함수도 엄밀히 따지면 window.fn()처럼, 윈도우의 메서드가 된다.

3. method invocation. 만일.. 함수 안의 메서드처럼 실행을 시켰다면? this는 그 함수의 것이 된다. 2 번에서 말했던 것처럼, this는 부모를 따라서 가기 때문에, fn(){ f: function(){console.log(this===fn) }를 하게 되면 fn이 this의 값이 된다.

만약, 여러 번 중첩이 되어 있는 경우라면?
직계 부모만 따라서 간다. 완전 마마보이, 마마걸 디스 ^-^

4. 가장 많이 쓰는 컨스트럭션 모드.
생성자 함수를 쓸 때 이 this를 많이 쓰는데, 사실 누구나 다 알고 있는.. 거니까.. ㅎㅎ.. 배웠으니까 설명은 넘어가고, 대신 코드로 작성. (ES6 기준)

this에 대해서 알기 쉽게 설명한 블로그
https://blueshw.github.io/2018/03/12/this/
*/
class Sanrio {
  constructor (name, color) {
    this.name = name; //여기서의 this는 sinamoroll이 된다.
    this.color = color;
  }
  action() {
    console.log(this.name + '이 애교를 부립니다.');
  }
}

let sinamoroll = new Sanrio ('시나모롤', 'blue');
sinamoroll; // {name:'시나모롤', color:'blue'}
sinamoroll.action(); // 시나모롤이 애교를 부립니다.
  • 함수 메소드 (optional)
  1. .call(), .apply() /this의 값을 할당
  • .call(), .apply() 메소드 호출의 이유를 알 수 있다.
  • .bind() 메소드를 어느 때에 사용하는지 이해할 수 있다.
  • 각각의 경우 this 가 어떤 식으로 취급되는지 이해할 수 있다
//.call과 .apply .bind 모두 this의 값을 명시적으로 할당해 주는 함수 메소드이다.
function plusNumber (num1, num2) {
  this.result = num1 + num2;
  console.log(this.result);
}
let obj1 = {result:0};

plusNumber.apply(obj1, [3, 3]); //6
plusNumber.call(obj1, 3, 3); //6
//apply과 call의 차이는 배열 형식으로 주느냐, 아규먼트 형식으로 주느냐의 차이.

//.bind는 바로 호출하지 않고 바인딩한 값을 담아 놓는다. 사실 바인드가 제일 어렵다.
let binding = plusNumber.bind(obj1, 3, 3);
binding(); //여기에서 담아 뒀던 것들이 일어난다. 활용 가능한 함수를 하나 더 만든다고 생각하면 편할 것 같다.

//이것을 작성하며 느낀 건데, 생성자 함수를 사용하지 않고 생성한 객체를 생성자 함수에 넣은 것처럼 사용하게 해 주는 함수 같은 느낌이 들었다. obj1은 생성자 함수를 사용해서 생성한 것은 아니지만, this값을 apply나 call을 이용해서 마치 생성자 함수를 사용해 인스턴트를 생성한 것처럼 함수에 넣게 해 줬다. 그러기 위해 이 기능이 만들어진 게 아닐까? this의 직속 부모를 사용자 스스로 설정해도 된다고 하기 위해서.



//함수 메소드 호출의 이유.
//이것을 쓰는 이유 중 하나는, DOM을 활용할 때, HTML에서 어떠한 것을 가져올 때 유사 배열 객체로 가져오게 되는데, 그렇게 되면 배열 메소드를 활용할 수가 없다. 혹은 배열로 이루어진 숫자의 제일 큰 값을 구하려고 할 때 번거로워진다.(이건 this가 들어가지 않지만) 그럴 때 이 함수들을 사용해서 인자들을 넘겨줌으로써 훨씬 수월하게 해결할 수 있다.
let arr = [1, 2, 3, 4, 5];
Math.max.apply(null, arr); //5
//이런 식일 땐 this의 값이 굳이 필요가 없기 때문에 null을 넣는 게 좋다.
function explan(num1, num2) {
  return num1 + num2;
}
explan.call(null, 2, 3); //5
//굳이 이렇게 쓰지 않아도 되지만.. 이렇게 활용할 수도 있다는 것을.. 알려 주고 싶었다.

//bind는 특정 함수가 this 값을 바꿔 버렸을 때에도 사용이 가능하다.
function Ex1 (a, b) {
  this.a = a;
  this.b = b;
  
  this.getNum = function() { return this.a + this.b };
  this.result = function() { console.log(this.getNum()) };
}
let c = new Ex1 (1, 2);

c.result(); //3
//잘 활용이 되지만, 여기에 setTimeout을 먹이면?
setTimeout(c.result, 3000); //error
//왜냐하면? setTimeout는 this의 값을 window로 바꿔서 생각하기 때문이다. 왜 그러는지는 모르겠는데 아주 멍청하고.. 멍청하고.. 이.. 아무튼, 어거지로 바꿔진 this를 다시 c로 바꿔 줘야 한다. 이때, bind가 필요하다. 바로 전환을 하는 apply나 call과는 달리, bind는 함수로 가지고 있기 때문에 c.result.bind(c)자체가 함수가 된다.
setTimeout(c.result.bind(c), 3000);

//bind로 커링 구현하기 (커링이란? 인자를 여러 개 받는 함수를 하나만 받게 하기)
//일단, 바인드로 구현하기 전에 클로저로 커링을 구현해 보자.
//div 클래스 만들기.

function divTemp () {
  let openDiv = '<div>'
  let closeDiv = '</div>'
  
  return function(innerHtml) {
    console.log(openDiv + innerHtml + closeDiv)
  }
} //앞뒤로 div 태그가 붙는 템플릿 구현!

let div = divTemp(); // f(<div> + innerHtml + </div>)
div('안녕하세요? 클로저로 커링 구현합니다.');
// <div>안녕하세요? 클로저로 커링 구현합니다.</div>

//이제 bind로 커링 구현하기
//bind는 함수로 묶어 두기 때문에 재사용이 언제든 가능하다.
function divTemp(name, innerhtml) {
  return console.log('<div>' + name + ', ' + innerhtml + '</div>')
}
let kara = divTemp.bind(null, 'kara'); // <div>카라, + innerhtml + </div>
kara('디트로이트야?'); // <div>카라, 디트로이트야?</div>

let code = divTemp.bind(null, 'code');
code('잠복 수사 중입니다.'); // <div>코드, 잠복 수사 중입니다.</div>

끝났지만 한 번 더 훑고 4-1 끝내겠습니다~

profile
커신이 고칼로리

0개의 댓글