티스토리 뷰

반응형

# 자바스크립트

## 변수와 .

프로그래밍 언어는 서양사람들이 만들었다. 그래서 그들의 문화, 철학, 사상이 녹아있다.

논리, 합리주의를 중요시함.

그런 측면으로 프로그래밍 언어도 구성되어 있다.

기저에 절대불변의 원칙을 세워두고 (공리) (. 1+1=2)

이것들을 기반으로 하나씩 차곡차곡 쌓아간다.

 

자바스크립트에서 '값'이라고 정의한 녀석들은 변수에 넣을수 있다.

var x = 10;
let y = 10;
const z = 10;

 

자바스크립트에서는 함수도 이라고 정의함.

function foo() {

}

let y = foo;

그래서 함수를 변수에 대입 가능하다.

 

자바스크립트는 모든 함수가 값을 반환한다고 정의함.

return 으로 반환하거나, return 없으면 undefined 반환.

new 호출하면 새로운 객체 반환.

 

변수에 대입하는 함수명은 이름이 의미 없다. (함수 바깥에서 접근 불가하기 때문에) 그래서 보통 생략한다.

 

함수를 값으로 취급할때엔 아래처럼 이름을 생략할 있다.

(function() {

})()

 

이렇게 괄호로 감싸면 함수를 값으로 쓰겠다는

뒤에 괄호() 실행하겠다는것.

이걸 즉시 실행 함수(IIFE, Immediately Invoked Function Expression)라고 한다.

프로그램을 처음 실행할때 한번만 호출하기 위한 .

 

함수는 값이기 때문에 인자로도 전달 가능하다. (콜백함수)

전달받은 함수를 호출 가능하고, 또 함수를 리턴 가능하다.

function foo(x) {
  x();
  return function() {

  };
}

const y = foo(function() {})() // 함수를 리턴받아서 그 함수를 바로 실행

 

일반 프로그래밍에서는 위 코드처럼 함수를 실행해서 함수를 리턴받는 것을 함수 합성이라고 한다.

함수를 인자로 받고 함수를 리턴받는 함수를 일급함수, 하이오더펑션이라고 한다.

 

함수표현식(변수에 대입하는 함수) 만들  위에서는 이름이 의미없다고 했지만, 재귀 함수 경우 이름이 있어야 호출 가능하다.

const foo = function foo () {
  foo();
}

 

## ES6에서 변형된 문법

arrow fcuntion 화살표 함수 

한줄 함수, 람다 함수 라고도 부른다.

const foo = function () {};
const bar = () => {};

 

모든 자바스크립트 코드는으로 나눌 있다.

 

실행한 결과가 값으로 마무리 되면

그래서 함수 호출은

실행해도 값이 안나오면

if, switch, while, for 등등

몇개없다.(함수 선언문, 컨디셔널문, 반복문)

마지막에 세미콜론이 있냐 없냐로도 구분 가능. (뒤에는 세미콜론 X)

 

화살표 함수는 이름이 없기 때문에 재귀 호출 불가~!

 

## this

new 연산자로 호출할때 생성되는  객체

function foo() {
  // this로 동적 바인딩 가능.
  this.name = 10;
}
const y = new foo();

 

new 연산자로 함수를 호출하면 새로운 객체를 반환한다. 그것을 인스턴스 객체라고 한다.

if (y instanced foo) {
  // y가 foo의 인스턴스인지 확인.
}

 

new 객체를 생성하는것도 일종의 위임이다.

개발자들이 객체를 사용할 때, 어떤 객체인지 판단하기 위해 해당 객체가 인스턴스인지 확인함으로써 신용이 보장 된다.

그리고 명시적인게 좋기 때문에 new 써주는것도 있음.

 

class

class 신택스 슈가라고 폄훼하는 사람들이 있지만 지금은 많이 달라짐. 새로운 기능들이 많이 추가됨.

function Foo() {
  this.name = 10;
}

class bar {
  constructor() {
    this.name = 10;
  }
}

 

Foo 함수는 new 붙여서도 호출 가능하고 붙이지 않아도 호출 가능하다.

그래서 함수명 앞글자를 대문자로 지정하면 new 호출하게끔 컨벤션을 지정하는 처절한 시절이 있었음.

class new 호출 안하면 오류남.

 

 

## 실행컨텍스트

const person = {
  name: ‘김민태’
  getName() {
    return this.name;
  }
}

console.log(person.getName());

 

호출하는 소유자를 실행컨텍스트라고 한다.

여기서는 person

 

그러나 실행컨텍스트를 판단하기 어렵게 만드는 경우가 아래와 같은 경우

const man = person.getName; // 소유자가 벗겨진다.
console.log(man()); // 여기서는 전역객체(window)가 실행컨텍스트가 된다.

위와 같은 상황이 발생하는 대표적인 예가 브라우저의 이벤트 시스템이다.

 

브라우저가 제공하는 이벤트 시스템은 UI 개발을 위해 필요하다.

유저가 언제 버튼을 누를지 모르기 때문에 "함수를 줄테니 버튼이 눌리면 실행해줘" 라고 하면서 전달되는것이 콜백 함수.

button.addEventListener(‘click’, person.getName);

이렇게 보내면 소유자가 벗겨진채로 함수가 전달된다.

 

이 때 소유자를 보존하기 위해 아래와 같은 방법을 사용한다.

button.addEventListener(‘click’, person.getName.bind(person));

bind 모든 함수가 제공하는 헬퍼 함수.

전달받은 객체를 this 설정한다.

 

bind와 비슷한 함수로 callapply가 있다.

person.getName.call(person);

person.getName.apply(person);

call apply 단지 파라미터 전달 방식에 차이가 있다. MDN 문서 참고

 

class 내에서 화살표 함수를 사용하면 this 변하지 않는다.

 

## 클로저

function foo(x) {
  return function bar() {
    return x;
  }
}

const f = foo(10);
console.log(f()); // 10 출력

위 코드를 통해 클로저를 찾아본다면...

  1. foo 함수 스코프가 생긴다.
  2. bar 함수 스코프에서 foo 스코프 영역에 접근 가능하다.
  3. foo 함수 스코프가 사라졌을때 bar 함수가 여전히 foo 스코프를 기억하고 있는것이 클로저.
  4. 값 x는 bar 접근 가능.
const person = {
  age: 10,
}

function makePerson() {
  // age값을 private하게 만들기 위해 클로저를 이용하는 코드
  let age = 10;
  return {
    getAge() { return age; },
    setAge(x) {
      age = x > 1 && x < 130 ? x : age;
    }
  }
}

 

논리머신들은 하나의 개념을 이리저리 응용하는것 뿐이기 때문에 형태에 현혹되지 말고 하나하나 찬찬히 뜯어보시길 바람.

 

 

## 비동기

function foo(x) {
  console.log(‘앗싸’)
}

setTimeout(function (x) {
  console.log(‘앗싸’);
  setTimeout(function(y){
    console.log(‘읏싸’);
  }, 2000);
}, 1000);

 

뎁스가 깊어지면 콜백 탄생.

해서 탄생한게 프로미스~!

프로미스

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // 여기 안에서만 resolve 함수에 접근 가능. 이것도 클로저. 
    resolve(‘응답’);
  })
  reject();
});

 

위 코드에서 p1 전달받는 객체 안에는 then이라는 메소드가 있음.

p1.then(function(r) {
  console.log(r);
}).catch(function() {
  // 에러 처리
})

 

resolve 호출하면 then 넘겨준 함수가 실행되고 reject 호출하면 catch 넘겨준 함수가 실행된다.

 

그러나 then 계속 연결되면 이것도 복잡해짐.

async await 함수가 등장한다.

async ~ await

const delay = ms => new Promise(resolve => setTimeout(resolve, ms))

async function main() {
  console.log(‘1’);
  // 여기서 3초 딜레이 하려면?
  await delay(3000);
  console.log(‘2’);
}

main();

 

위 코드에서 일반적으로 3초를 딜레이하기 위해서는 콜백함수 사용안하고는 불가능.
그러나 await는 매우 간단하게 인간의 일반적인 사고방식대로 동작해준다.

await promise객체가 resolve 실행해서 반환하는 값을 기다렸다가 전달해준다.

async~await 백그라운드에는 프로미스가 있다!

reject 되면 try~catch문에서 catch 잡힌다.

 

 

* 커링 인자를 쪼개서 함수를 호출할수 있도록 하는 기법 - 클로저를 이용한 것이다.

// 일반적인 함수
function foo(a, b, c) {}

// 커링 함수
function foo(a) {
  return function(b) {
    return function(c) {}
  }
}

 

 

# 리덕스

스토어에 모든데이터를 넣어두고 데이터가 바뀌면 모든 컴포넌트가 업데이트된다.

모든 컴포넌트 업데이트는 매우 느리고 비효율적.

리액트에서는 virtual dom으로 컴포넌트의 diff 관리하기 때문에 변경된 부분만 업데이트 해준다. 

(데이터가 바뀌면 새로운 버전의 VDOM 만들고 그걸 기존버전이랑 비교)

## 리덕스 실습

store 단순히 말해 객체.

 

리덕스에 저장된 데이터(상태) 절대 컴포넌트가 건드릴수 없도록, immutable하게 유지되도록 한다.

컴포넌트는 단순히 전달받은 상태를 그리도록.

그래서 클로저로 감춘다.

 

리덕스는 개발자들을 믿지 못하기 때문에 상태 리턴해줄때 무조건 새로운 객체로 만들어서 리턴.

 

리덕스 스토어 상태를 바꿔주는것이 리듀서

네이밍이 개똥같다.

 

리덕스가 정한 약속 2가지

  1. 리듀서 형식
  2. 리듀서에서 제출하는 값은 무조건 새로운 객체 (직접 변경 X)
//index.js

import { createStore } from ‘./redux’;

const INCREMENT = ‘increment’;
const RESET = ‘reset’;

function reducer(state = {}, action) {
  if (action.type === ‘increment’) {
    return {
      …state,
      count: state.count ? state.count + 1 : 1
    };
  } else if (action.type === RESET) {
    return {
      …state,
      count: action.resetCount,
    }
  }
}

const store = createStore(reducer);

function update() {
  // 리듀서로 스토어값이 바꼈을 때 호출됨.
  console.log(store.getState());
}

store.subscribe(update);

function actionCreator(type, data) {
  return {
    …data,
    type: type
  }
}

function increment() {
	store.dispatch(actionCreator(INCREMENT));
}

function reset() {
	store.dispatch(actionCreator(RESET));
}

store.dispatch({ type: ‘increment’ }); // 1
store.dispatch({ type: INCREMENT }); // 2
store.dispatch(actionCreator(INCREMENT)); // 3
increment(); // 4

console.log(store.getState());

 

// redux.js

export function createStore(reducer) {

  let state;
  const listeners = [];
  
  const getState = () => ({ …state });
  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach((fn) => fn());
  }
  
  const subscribe = (fn) => {
  	listeners.push(fn);
  }

  return {
  	getState,
  };

}

 

용어 정리

리듀서 함수를 호출하기 위해 원쿠션으로 한번 감싸서 바깥에서 쓸수있게 만든 함수가 dispatch

 

액션타입 : dispatch 할때 마다 type 입력 귀찮으니 모두 상수화 한 것.

actionCreator : 타입 지정 객체를 리턴해주는 .

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함