Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[24/08/29-09/04] 안내 및 질문 모음집 #28

Open
minjeongss opened this issue Aug 29, 2024 · 4 comments
Open

[24/08/29-09/04] 안내 및 질문 모음집 #28

minjeongss opened this issue Aug 29, 2024 · 4 comments

Comments

@minjeongss
Copy link
Member

minjeongss commented Aug 29, 2024

📚 분량

20장-24장 

🎤 발표자

이성훈

질문

😮 지난주 추가 질문

프로토타입 기반의 상속이 클래스 기반 상속보다 복잡해서, 클래스를 많이 사용하게 된다고 결론을 지었는데
리액트에선 클래스를 사용하지 않는다고 알고 있습니다.
그렇다면 리액트에서 사용하는 상속 방식은 프로토타입 기반일까요?

???

  • 왜 렉시컬 환경의 구성 요소를 프로퍼티가 아니라 컴포넌트라고 표현하는가? (이성훈)
  • 블록스코프와 함수 스코프는 외부 렉시컬 환경에 대한 참조가 달라지겠지? (이성훈)
    • 실행 컨텍스트는 이걸 어떻게 구분해서 참조를 저장할까?
    • VariableEnvironment와 관련있지 않을까?

22장

  • 화살표 함수와 일반 함수의 'this' 바인딩 차이점과 이러한 차이가 클래스 메서드와 콜백 함수에서 어떤 영향을 미치는지 (김민석)

24장

  • 클로저를 사용하여 프라이빗 변수와 메서드를 구현하는 방법? (김민석)
  • 실 서비스 개발의 경우에서 클로저를 사용하는 경우? (조천산)
  • React에서 클로저 개념을 많이 쓴다고 했는데(전혀 인지 못하고 있었습니다..) 언제 어떤 식으로 활용되는지 같이 알아보면 좋을 것 같습니다. (김주영)
@se0kcess
Copy link
Collaborator

se0kcess commented Sep 4, 2024

프로토타입 기반의 상속이 클래스 기반 상속보다 복잡해서, 클래스를 많이 사용하게 된다고 결론을 지었는데리액트에선 클래스를 사용하지 않는다고 알고 있습니다.그렇다면 리액트에서 사용하는 상속 방식은 프로토타입 기반일까요? (추가 질문)

  • 리액트는 클래스나 프로토타입 기반 상속보다는 합성을 선호함

  • 상속보다는 합성 원칙을 따르기 때문

  • 리액트는 초기에 클래스 기반 컴포넌트를 주로 사용했지만, 현재는 함수형 컴포넌트와 훅을 권장


렉시컬 환경의 구성 요소를 프로퍼티가 아닌 컴포넌트라고 표현하는 이유 (이성훈)

  • 렉시컬 환경의 구성 요소를 컴포넌트라고 표현하는 이유는 ECMAScript 명세의 공식적인 용어로, 단순한 프로퍼티보다 더 복잡하고 구조화된 요소임을 강조하기 위함임

  • 렉시컬 환경은 환경 레코드와 외부 렉시컬 환경에 대한 참조라는 두 가지 주요 컴포넌트로 구성되어 있으며 이들은 단순한 키-값 쌍이 아니라 특정한 동작과 구조를 가진 복잡한 요소들임

블록 스코프와 함수 스코프의 외부 렉시컬 환경 참조 차이 (이성훈)

  • 함수 스코프: 함수가 정의된 위치의 렉시컬 환경을 참조

  • 블록 스코프: 블록이 위치한 가장 가까운 포함하는 함수(또는 전역 스코프)의 렉시컬 환경을 참조

실행 컨텍스트가 이를 구분해서 참조를 저장하는 방법 (이성훈)

  • 실행 컨텍스트는 LexicalEnvironment와 VariableEnvironment라는 두 가지 컴포넌트를 사용하여 구분함

  • LexicalEnvironment: 현재 컨텍스트의 렉시컬 환경을 나타냅니다. 함수 선언, let, const로 선언된 변수를 포함

  • VariableEnvironment: 주로 var로 선언된 변수와 함수 선언을 저장

VariableEnvironment와의 관련성 (이성훈)

  • 함수 스코프에서는 LexicalEnvironment와 VariableEnvironment가 동일한 환경을 가리킴

  • 블록 스코프에서는 새로운 LexicalEnvironment가 생성되지만, VariableEnvironment는 함수의 시작 부분에서 생성된 환경을 계속 참조함

  • 이를 통해 JavaScript 엔진은 var로 선언된 변수의 함수 스코프 특성과 let, const로 선언된 변수의 블록 스코프 특성을 모두 지원할 수 있음


화살표 함수와 일반 함수의 'this' 바인딩 차이점과 이러한 차이가 클래스 메서드와 콜백 함수에서 어떤 영향을 미치는지 (김민석)

일반 함수와 화살표 함수의 'this' 바인딩 차이

  • 일반 함수

    • 'this'는 함수가 호출될 때 동적으로 결정
      호출 방식에 따라 'this'가 달라집니다 (예: 객체 메서드, 일반 함수 호출, call/apply/bind 사용 등).
  • 화살표 함수:

    • 'this'는 함수가 생성될 때 렉시컬적으로 결정
      자신만의 'this'를 생성하지 않고, 외부 스코프의 'this'를 그대로 사용

  • 클래스 메서드: 일반적으로 프로토타입 메서드로 정의되는 일반 함수를 사용하지만 메서드를 다른 컨텍스트에서 호출해야 하는 경우 화살표 함수가 유용할 수 있음
  • 콜백 함수: 대부분의 경우 화살표 함수를 사용하는 것이 'this' 바인딩 문제를 피할 수 있어 편리

클로저를 사용하여 프라이빗 변수와 메서드를 구현하는 방법 (김민석)

기본적인 사용방법

function createObject() {
  // 프라이빗 변수들
  let privateVar = 0;

  // 프라이빗 메서드
  function privateMethod() {
    console.log('This is a private method');
  }

  // 반환되는 객체 (public interface)
  return {
    // 퍼블릭 메서드들
    publicMethod: function () {
      privateVar++;
      console.log(privateVar);
      privateMethod();
    },
  };
}

const obj = createObject();

ES6 클래스와 private 필드를 사용

class BankAccount {
  #balance; // private 필드

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  deposit(amount) {
    if (this.#validateAmount(amount)) {
      this.#balance += amount;
      return true;
    }
    return false;
  }

  withdraw(amount) {
    if (this.#validateAmount(amount) && this.#balance >= amount) {
      this.#balance -= amount;
      return true;
    }
    return false;
  }

  getBalance() {
    return this.#balance;
  }

  #validateAmount(amount) {
    return typeof amount === 'number' && amount > 0;
  }
}

실 서비스 개발의 경우에서 클로저를 사용하는 경우 (조천산)

  • 모듈 패턴
const myModule = (function () {
  let privateVar = '비밀';
  return {
    publicMethod: function () {
      console.log('비밀 번호: ' + privateVar);
    },
  };
})();
myModule.publicMethod(); // '비밀 번호: 비밀' 출력
  • DOM 이벤트 핸들러나 AJAX 요청의 콜백에서 특정 상태나 변수를 유지해야 할 때

  • 사용자 인증 토큰과 같은 민감한 정보를 안전하게 저장하고 관리할 때

  • 함수의 일부 인자를 미리 설정하여 새로운 함수를 만드는 데

  • Promise나 async/await를 사용할 수 없는 환경에서 비동기 작업을 관리할 때


React에서 클로저 개념을 많이 쓴다고 했는데(전혀 인지 못하고 있었습니다..) 언제 어떤 식으로 활용되는지 같이 알아보면 좋을 것 같습니다. (김주영)

리액트 훅을 사용할 때 클로저의 개념이 중요하게 사용됨

  • useState
function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

이 코드에서 increment함수는 count와 setCount를 기억하고 있는 클로저 함수임

  • 이벤트 핸들러
function Form({ onSubmit }) {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();
    onSubmit({ name, email }); // name과 email을 클로저로 캡처
  };

  return <form onSubmit={handleSubmit}>{/* form fields */}</form>;
}

handleSubmit 함수는 name과 email state를 클로저로 캡처

@joarthvr
Copy link
Collaborator

joarthvr commented Sep 4, 2024

  1. 리액트에서는 전통적인 의미의 '상속'을 거의 사용하지 않음
    대신, 리액트는 컴포넌트 기반 아키텍처와 '합성(Composition)' 원칙을 중심으로 코드를 구성
    합성 - > 예) 컴포넌트 합성: 리액트는 작은 컴포넌트들을 조합하여 더 큰 컴포넌트를 만드는 방식을 사용함

  2. '컴포넌트'라는 용어는 주로 다음과 같은 맥락에서 사용됌
    1. 사용자 인터페이스 (UI) 구성 요소
    2. 소프트웨어 아키텍처의 모듈화된 부분
    3. 리액트와 같은 프레임워크에서의 재사용 가능한 UI 요소
    렉시컬 환경을 설명할 때 '컴포넌트'라는 용어를 사용하면 혼란을 줄 수 있으므로, 대신 '구성 요소', '부분', '요소' 등의 용어를 사용하는 것이
    더 명확함

함수 스코프: 함수가 선언된 외부 환경을 참조합니다.
블록 스코프: 블록이 위치한 직접적인 외부 환경을 참조합니다.

실행 컨텍스트의 구분:
VariableEnvironment: 함수 스코프 변수(var)를 저장
LexicalEnvironment: 블록 스코프 변수(let, const)를 저장

실행 컨텍스트는 이러한 방식으로 블록 스코프와 함수 스코프를 구분하여 관리
각 스코프에 맞는 외부 렉시컬 환경 참조를 유지함.

    1. 클래스 메서드
      클래스의 this는 클래스가 빈 객체를 생성한 후 이것을 프로토타입으로 연결한다 왜냐하면 클래스는 생성자 함수이기 때문이다
      그러므로 일반 함수든 화살표 함수던 클래스에 연결된 프로토타입을 this로 연결한다

    2. 콜백함수
      일반 함수 -> 전역객체 탐지 내부 함수던 뭐든 전역객체
      화살표 함수 - > 렉시컬 스코프 따라서 제일 가까운 스코프로 감싸인 녀석 지칭

  1. 클래스 get set

  2. 훅의 원리가 클로저

@kimjuyoung99
Copy link
Member

kimjuyoung99 commented Sep 4, 2024

프로토타입 기반의 상속이 클래스 기반 상속보다 복잡해서, 클래스를 많이 사용하게 된다고 결론을 지었는데 리액트에선 클래스를 사용하지 않는다고 알고 있습니다. 그렇다면 리액트에서 사용하는 상속 방식은 프로토타입 기반일까요?

답변 : 리액트는 클래스 기반 컴포넌트를 사용하지 않고 함수형 컴포넌트를 주로 사용하는 것은 맞다. 하지만 이는 상속이랑 직접적인 관련이 없다고 한다.

  • 합성방식 권장 : 즉, 프로토타입 기반이나 클래스 기반의 상속을 사용하지 않고, props를 통해서 데이터와 동작을 전달하는 방식을 사용한다.

22장

왜 렉시컬 환경의 구성 요소를 프로퍼티가 아니라 컴포넌트라고 표현하는가?

  • 컴코넌트 : 일반적으로 시스템의 독립적인 부분을 의미
  • 렉시컬 환경: 환경 레코드와 외부 환경에 대한 참조라는 두 가지 주요 부분으로 구성되어 있다
  • 따라서 컴포넌트라는 표현이 사용된 것 같다

블록스코프와 함수 스코프는 외부 렉시컬 환경에 대한 참조가 달라지겠지?

- 실행 컨텍스트는 이걸 어떻게 구분해서 참조를 저장할까?

  • JS엔진은 코드의 타입(전역, 함수, eval)과 해당 코드의 문맥을 분석하여 적절한 스코프 체인은 생성하게 된다.

- VariableEnvironment와 관련있지 않을까?

  • VariableEnvironment : 초기희 렉시컬 환경을 저장
  • LexicalEnvironment : 실행 중에 변경될 수 있는 현재의 렉시컬 환경
  • 블록 스코프의 경우 LexicalEnvironment 가 업데이트 되지만, VariableEnvironment는 그대로 유지된다.

24장

- 화살표 함수와 일반 함수의 'this' 바인딩 차이점과 이러한 차이가 클래스 메서드와 콜백 함수에서 어떤 영향을 미치는지

  • 일반 함수: 호출 방식에 따라 this가 동적으로 바인딩
  • 화살표 함수: 자신을 감싸는 외부 스코프의 this를 그대로 사용 (렉시컬 this)
  • 클래스 메서드 : 일반 함수를 사용하면 this가 인스턴스를 가리키지만, 화살표 함수를 사용하면 예상치 못한 결과가 나올 수 있다.
  • 콜백 함수: 화살표 함수를 사용하면 외부 컨텍스트의 this를 유지할 수 있어 유용하다.

- 클로저를 사용하여 프라이빗 변수와 메서드를 구현하는 방법?

클로저는 사용하여 함수 내부에 변수를 선언, 이 변수에 접근하는 메서드만을 반환함으로써 프라이빗 변수와 메서드 구현 가능

   function createCounter() {
     let count = 0;  // 프라이빗 변수
     return {
       increment() { count++; },
       getCount() { return count; }
     };
   }
   
   const counter = createCounter();
   counter.increment();
   console.log(counter.getCount());  // 1
   console.log(counter.count);  // undefined

- 실 서비스 개발의 경우에서 클로저를 사용하는 경우?

- 데이터 캡슐화와 정보 은닉
- 모듈 패턴 구현
- 부분 적용 함수나 커링 구현
- 이벤트 핸들러와 콜백에서 상태 유지

- React에서 클로저 개념을 많이 쓴다고 했는데 언제 어떤 식으로 활용되는지

- useState : 상태와 그 상태를 변경하는 함수를 반환하는데 클로저 이용
- useEffect : 클린업 함수에서 이전 렌더링의 값에 접근할 때 클로저 사용
- useMemo, useCallback : 메모이제이션된 값이나 함수를 생성할 때 클로저 활용
- 예시 코드
function Counter() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prevCount => prevCount + 1);  // 클로저를 통해 최신 상태에 접근
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div>{count}</div>;
}

setCount 함수 내부의 콜백은 클로저를 통해 항상 최신의 count 값에 접근할 수 있다.

@joarthvr joarthvr self-assigned this Sep 4, 2024
@shlee9999
Copy link
Collaborator

  • 프로토타입 기반의 상속이 클래스 기반 상속보다 복잡해서, 클래스를 많이 사용하게 된다고 결론을 지었는데
    리액트에선 클래스를 사용하지 않는다고 알고 있습니다.
    그렇다면 리액트에서 사용하는 상속 방식은 프로토타입 기반일까요? (김민정)

    리액트에서 사용하는 상속 방식은 프로토타입 기반도, 클래스 기반도 아닙니다. 리액트는 상속보다는 컴포지션(Composition) 방식을 선호합니다. 컴포지션은 여러 컴포넌트를 조합하여 더 큰 컴포넌트를 만드는 방식으로, 재사용성과 유지보수성을 높이는 데 중점을 둡니다.

    리액트에서 클래스 컴포넌트는 과거에 주로 사용되었지만, 현재는 함수형 컴포넌트와 훅(Hooks)을 사용하는 것이 일반적입니다. 함수형 컴포넌트는 순수한 함수로 상태와 라이프사이클을 관리하며, 객체 지향의 상속 개념이 아닌 함수형 프로그래밍의 합성(composition)을 중점으로 합니다.

  • 왜 렉시컬 환경의 구성 요소를 프로퍼티가 아니라 컴포넌트라고 표현하는가? (이성훈)

    렉시컬 환경(Lexical Environment)에서 "컴포넌트"라는 용어를 사용하는 이유는, 이 개념이 단순히 객체의 프로퍼티처럼 값을 저장하는 것이 아니라, 변수함수의 유효 범위(scope)를 구성하는 중요한 요소들이기 때문입니다.

    렉시컬 환경은 주로 두 가지 주요 컴포넌트로 구성됩니다:

    1. 환경 레코드(Environment Record): 여기에는 현재 실행 중인 코드 블록의 변수, 함수 선언 등이 저장됩니다. 변수와 함수에 대한 정보가 저장되며, 이를 통해 변수의 값에 접근하거나 함수 호출이 가능합니다.
    2. 외부 렉시컬 환경(Outer Lexical Environment): 현재 환경이 참조하는 상위 스코프를 가리킵니다. 이로 인해 자바스크립트가 중첩된 스코프에서 변수나 함수에 접근할 수 있게 됩니다.

    이러한 이유로 렉시컬 환경의 구성 요소를 "프로퍼티" 대신 "컴포넌트"라고 표현하는 것입니다. "프로퍼티"라는 용어는 객체의 속성을 설명할 때 사용되며, 그 의미가 제한적입니다. 반면 "컴포넌트"는 렉시컬 환경이 어떻게 구성되어 있는지를 더 잘 설명하는 포괄적인 용어입니다.

  • 블록스코프와 함수 스코프는 외부 렉시컬 환경에 대한 참조가 달라지겠지? (이성훈)

    • 실행 컨텍스트는 이걸 어떻게 구분해서 참조를 저장할까?

    • VariableEnvironment와 관련있지 않을까?

    • https://seholee.com/blog/varaible-environment-vs-lexical-environment/

    • 위 블로그에서 가져온 내용입니다.

      function a() {
        let var2 = 10000;
        let var1 = 10000;
        if (true) {
          var var1 = 100;
          let var2 = 10;
          if (true) {
            let var2 = 11;
          }
        }
        if (true) {
          let var2 = 12;
        }
      }

      위의 코드를 보면 블록 스코프는 여러개이고 함수 스코프는 단 한개만 있다. 우리가 이미 알다시피 콜 스택에 쌓이는 Execution Context는 함수 마다 한 개씩 존재하고 Execution Context안에는 Lexical Environment 한 개와 Variable Environment 한 개가 존재한다. 여기서 문제는 블록 스코프가 여러 개 생겼을 때 블록 스코프마다 Execution Context를 달아주어야하는가이다. JS는 그렇게 설계되어있지 않다고 한다. 함수 스코프 내부의 블록 스코프에는 Execution Context 없이 새로운 Lexical Environment가 생성되고, Outer Lexical Environment는 외부 블록 스코프를 호출한다고 한다. let과 const는 블록 스코프 단위이기 때문에 블록 스코프 마다 한 개씩 생성되는 Lexical Environment의 Record에서 주로 관리하고, var은 함수 스코프 단위이기 때문에 함수 스코프 마다 한 개씩 생성되는 Variable Environment의 Record에서 주로 관리한다고 한다. (Lexical Environment에서 var 초기화도 된다는 내용들도 있어서 "주로"라고 표현했다. 내부에 복합적으로 돌아가는 로직들이 있는듯하다.)

  • 화살표 함수와 일반 함수의 'this' 바인딩 차이점과 이러한 차이가 클래스 메서드와 콜백 함수에서 어떤 영향을 미치는지 (김민석)

    발표 내용으로 대체하겠습니다.

24장

  • 클로저를 사용하여 프라이빗 변수와 메서드를 구현하는 방법? (김민석)

    발표 내용으로 대체하겠습니다.

  • 실 서비스 개발의 경우에서 클로저를 사용하는 경우? (조천산)

    클로저를 사용하게 되면 자유 변수를 계속해서 재사용 가능하기 때문에 메모리 및 성능 최적화에 적합하다고 생각됩니다. 그리고 React의 훅도 클로저를 활용해 만들어진 것으로 알고 있습니다.

  • React에서 클로저 개념을 많이 쓴다고 했는데(전혀 인지 못하고 있었습니다..) 언제 어떤 식으로 활용되는지 같이 알아보면 좋을 것 같습니다. (김주영)

    useState가 대표적인 예시입니다! 다음은 간략하게 useState를 클로저로 구현한 예시입니다.

    const React = (function () {
      let state;
    
      return {
        useState(initialValue) {
          if (state === undefined) state = initialValue;
    
          const setState = (newValue) => {
            state = newValue;
          };
    
          return [state, setState];
        },
      };
    })();
    
    const Counter = () => {
      const [count, setCount] = React.useState(0);
    
      console.log(count); // 0
      setCount(1);
      console.log(count); // 1
    };

@minjeongss minjeongss assigned shlee9999 and unassigned joarthvr Sep 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants