[코드 정리] 6주차 (Component, import, export 등의 개념)

Soozynn·2021년 8월 29일
0

<6주차 과제의 목적>

  • 컴포넌트의 목적에 대해서 잘 생각해보기
  • 컴포넌트를 어떤 상황에 쓰게 될건지, 그러한 상황들은 어떤 상황들일지..
    예를 들어 시계가 아닌 컴포넌트를 만든다면 어떨지...



이번주차 과제에서 헷갈렸던 개념과 문법.. object 개념에 대해서 객체리터럴


먼저, 메서드란?

자바스크립트의 객체는 키(key)값(value)으로 구성된 프로퍼티(Property)들의 집합이다. 프로퍼티의 값으로 자바스크립트에서 사용할 수 있는 "모든 값" 을 사용할 수 있고, 프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 메서드라 부른다.

👉 아래와 같이 객체 프로퍼티에 할당된 함수를 메서드(method) 라고 한다.

var obj = {
  name: "sujin",
  age: function foo() { // -> 메서드
  // blah blah.. code..
  }
}


메서드 단축 구문

객체 리터럴 안에 메서드를 선언할 때 단축 문법을 사용할 수 있다.

// 아래 두 객체는 동일하게 동작합니다.

user = {
  sayHi: function() {
    alert("Hello");
  }
};

// 단축 구문을 사용하니 더 깔끔해 보이네요.
user = {
  sayHi() { // "sayHi: function()"과 동일합니다.
    alert("Hello");
  }
};

위처럼 function을 생략해도 메서드를 정의할 수 있다.

다만, 일반적인 방법과 단축 구문을 사용한 방법이 완전히 동일하진 않다.



과제를 진행하면서 내가 헷갈렸던 부분과 이해가 되지 않았던 부분

정말 간단한 개념이면서 예제이지만 나는 이조차 제대로 이해를 하지 못하였었다.

아래 코드에서 예를 들면,

const CanolaUI = {
  /*
   * 👉🏻 create 메소드입니다.
   * CanolaError에 대해서 살펴보신 후, componentFactory로 이동하세요.
   */
  create(options) {
    validateOptions(options);
    
    return componentFactory(options.template, options.events); 
  },
};

export default CanolaUI;

여기서 사용된 create() 메소드가 Object.create() 와 같은 것인 줄로만 알았다.

⛔ 하지만 둘은 연관성이 없으며, 위에서 사용된 create() 메소드는 객체 안에서의 자체 메소드이다.

Object.create()에서 말하는 Object는 객체를 뜻하는 네임을 쓰는 것이라고 생각했는데 그렇지 않고 저 문법 그대로 사용하여야 해당 메소드를 사용할 수 있는 것이다. 때문에 이 개념과 많은 혼동이 일어나 코드를 제대로 이해하지 못하였다.

위에 구문에서 create()메서드 단축 구문을 이용한 객체안에서의 함수 값이다.
위에서도 말했듯 이를 메서드라고 부른다.


const CanolaUI = {
  greeting: "hello",
  create(options) {
    return componentFactory(options.template);
  }
}
console.log(CanolaUI.greeting); // "hello"
const Clock = CanolaUI.create({ ... });

create()는 객체 안에서 정의된 함수 값이므로 CanolaUI 객체의 키 값으로 정의된 greeting을 불러오면 그 것의 값인 "hello"가 찍히는 것과 같이, CanolaUI.create({ ... });는 말그대로 CanolaUI 객체의 값이 create를 변수 Clock에 담은 것이다.

또, CanolaUI에서 create()는 인자로 options을 받고 있기 때문에 이 options의 값이 바로 CanolaUI.create({ ... });에서 {...} 값이 인자로 전달되는 것이다.

이 다음으로 중요한 것이 그렇다면, CanolaUI.create()리턴하는 값이 무엇이냐 이다.
로직을 따라가보면 리턴하는 값은 componentFactory(options.template);임을 알 수 있고, 이 값이 무엇을 또 리턴하는지 알면 된다.

export default function componentFactory(generateTemplate) {
  function Component(options) { ... }

  Component.prototype.render = function () { ... };

  Component.prototype.destroy = function () { ... };

  return Component;
}

-> 피드백 내용)
내부 로직을 축소해서 보면 위와같은 형태로 함수가 만들어져있습니다. 리턴값을 한번 확인해보세요.
바로 Component 함수 즉, Pascal Case로 네이밍이 되어있기 때문에 Component라는 생성자 함수를 리턴하는 것을 알 수 있습니다.

이쯤되면 이런 의문이 드실 수 있습니다. 왜 이렇게 복잡하게 생성자 함수를 리턴하는거야?

그 답은 배우셨던 prototypeclosure 그리고 같은 함수 Context로 묶기 위함에 있습니다.
componentFactory가 인자값으로 받는 generateTemplate가 이 내부에서 어떻게 쓰이고 있는지 확인해보세요.
이해하게 되신다면 이 구조를 파악하게 되실 수 있을 것 같습니다.



Component란?

먼저 component는 요소, 부품이라는 뜻을 가지고 있다.

  • 목적에 대해 짚고 넘어가야할 필요가 있다.



import

import componentFactory from "./Component";
import CanolaError from "./CanolaError";

이번주차 과제에서 이렇게 코드가 짜여져있어 처음에는 해당하는 파일 내에서 저 값들만 가져올수 있는거구나 했는데 아니었다.

export를 이용하여 내보낸 값을 기준으로 다른 모듈에서 import를 사용하여 내보낸 값을 복사해서 쓸 수 있는 것이다.
따라서 저 name명은 그냥 해당하는 모듈에서 export로 내보낸 값을 쓰기 위한 네임명이라는 것이다.
export로 어떤 값을 내보냈는지에 따라 네임명을 설정해주면 더 좋기때문에 저렇게 적은 것 같다.


MDN 인용 글)

import 문은 다른 모듈에서 내보낸 바인딩을 가져올 때 사용합니다.

가져오는 모듈은 "use strict"의 존재 유무와 상관없이 무조건 엄격 모드입니다. HTML 안에 작성한 스크립트에서는 import를 사용할 수 없습니다.

함수형 구문을 가진 동적 import()도 있으며, type="module"을 필요로 하지 않습니다.

<script> 태그의 nomodule 속성을 사용해 하위호환성을 유지할 수 있습니다.

name 파라미터는 "export 되는 멤버를 받을 오브젝트의 이름"입니다. member 파라미터는 각각의 멤버를 지정하지만, name 파라미터는 모두를 가져옵니다. 모듈에서 name 은 멤버 대신 하나의 default 파라미터를 통해 export 하는 경우에도 동작할 수 있습니다. 다음의 명확한 예제 문법을 살펴봅시다.

아래 예시에서,
모듈 전체를 가져옵니다. export 한 모든 것들을 현재 범위(스크립트 파일 하나로 구분되는 모듈 범위) 내에 myModule 로 바인딩되어 들어갑니다.

import * as myModule from "my-module.js";

export

export 문은 JavaScript 모듈에서 함수, 객체, 원시 값을 내보낼 때 사용합니다. 내보낸 값은 다른 프로그램에서 import 문으로 가져가 사용할 수 있습니다.

내보내는 모듈은 "use strict"의 존재 유무와 상관없이 무조건 엄격 모드입니다. export 문은 HTML 안에 작성한 스크립트에서는 사용할 수 없습니다.



6주차 과제 요구사항 정리

const html = generateTemplate.call(this).trim();

strict mode에서 일반적인 호출방법으로 함수를 실행하면 this의 값은 undefined입니다.
generateTemplate함수는 this를 참조하고 있는 string값이 return 되고 있고,
this, 즉 undefined는 어떠한 property도 가지고 있지 않으므로 오류에서 "Cannot read property 'backgroundColor' of undefined" 라고 안내해주고 있습니다.
혹시 위의 내용이 이해가 정확하게 안간다면 this에 대해서 조금 더 꼼꼼하게 검색해보시길 추천드립니다.
그리고 callapply, bind와 함께 항상 세트처럼 설명되는 개념입니다.
3가지를 함께 비교해보고 어떤 차이점들이 있는지 알아보시길 추천합니다.
this, prototype 을 공부할 때 개인적으로 가장 도움이 되었던 자료입니다. 참고해주세요~


setIntervalclearInterval로 사용중지를 하지 않으면 메모리 누수로 연결된다는 점을 유의해주셔야합니다.


과제의 흐름에 대해 간단하게 설명
일단 프로젝트의 가장 상위인 app.js 에서 출발해볼게요.

// in app.js
const Clock = CanolaUI.create({ ... });

Clock 변수에는 CanolaUI.create가 실행되면서 리턴된 값이 할당되어있습니다.

// in /Canola/index.js
const CanolaUI = {
  create(options) {
    ...
    return componentFactory(options.template);
  },
};

이를 확인하기 위해 CanolaUI를 확인해보면,
CanolaUIcreate methodcomponentFactory의 리턴값을 다시 리턴합니다.

// in /Canola/Component.js
export default function componentFactory(generateTemplate) {
  function Component(options) { ... }

  Component.prototype.render = function () { ... } // 생성자함수의 prototype 객체에 render라는 method가 추가되었습니다.

  Component.prototype.destroy = function () { ... } // 생성자함수의 prototype 객체에 destroy라는 method가 추가되었습니다.

  return Component;
}

이를 확인하기 위해 componentFactory를 확인해보면,
생성자함수 Component를 리턴하고 있습니다. (생성자 함수는 보통 대문자로 시작합니다.)
돌고 돌았지만 간단히 정리해보면, Clock 변수에는 생성자함수 Component가 담겨있다는 것을 알 수 있습니다.\

  • Clock변수 -> CanolaUI.create 리턴값 -> componentFactory 리턴값 -> 생성자함수 Component
const myClock = new Clock({ ... });

myClock.render();

⭐ 이제 myClock 변수을 살펴보면,
myClock 변수에는 Clock이라는 생성자함수를 new와 함께 호출한 instance가 할당됩니다.
myClock이라는 instance 안에는 render라는 method가 없지만,
myClock.render를 실행할 수 있는 이유는
프로토타입 체인이 동작하여 생성자함수 Componentprototype 객체에 추가되어있는 render method를 사용할 수 있기 때문입니다.

render method에서는 this.$el처럼 this가 등장합니다.
여기서 thisrender가 실행되는 순간 결정되는데,
myClock.render(), 즉 "dot notation" 방식으로 시행되었으므로, dot(.) 앞의 myClockthis 입니다.
과제와 관련되어 가장 기본적인 흐름이라고 생각되는 부분만 말씀드렸습니다.

0개의 댓글