FE 레벨4 SSR | JS의 평행세계, 서버와 클라이언트 - 토론 #55
Replies: 13 comments 3 replies
This comment has been hidden.
This comment has been hidden.
-
팀 이름: 모모구성원 (해리, 낙타, 빙봉) 문제1var 키워드로 선언한 변수는 전역변수처럼 동작한다. 그리고, var 키워드로 선언한 변수는 덮어씌워질 수 있다. 즉, 값의 재할당이 가능하다. var ts = 10000;
var js = 20000;
var ts = 20000;
var js = 40000; 이렇게 선언된 것과 마찬가지라고 할 수 있고, 뒤에 선언한 변수인 20000, 40000가 출력된다. 문제2프리코스{
"name": "javascript-racingcar",
"version": "1.0.0",
"description": "우아한테크코스 프리코스 자동차 경주 미션",
"type": "module",
"dependencies": {
"@woowacourse/mission-utils": "2.1.1"
}, 본 코스{
"name": "@woowacourse/javascript-racingcar",
"version": "1.0.0",
"description": "우아한테크코스 웹 프론트엔드 레벨1 자동차 경주 미션",
"main": "src/index.js",
"scripts": {
"start": "npm run build-prod && node dist/bundle.js",
"build-dev": "webpack --mode development",
"build-prod": "webpack --mode production",
"test": "jest --watch"
}, "type": "module", 가장 큰 차이는 type의 존재 유무이다. module로 설정하지 않으면 기본적으로 Common JS 모듈 시스템을 사용하게 된다. 프리코스에서는 ESM을 사용할 것이라고 명시 한 것을 확인할 수 있다. 실제로 프리코스의 index.js 파일을 확인해 보면 import App from "./App.js";
const app = new App();
app.play();
반면, 본 코스 미션에서는 import 구문을 사용하지만 파일 확장자는 사용하지 않고 있다. vs code에서 바로 실행하면
이렇게 module을 사용할 것을 에러 메시지로 알려주는 것을 확인할 수 있다. 본 코스 레파지토리의 프로젝트를 실행하기 위해선 npm run start 명령어를 사용해서 웹팩 도구로 빌드해야 하는 것을 확인할 수 있다. 문제3트랜스파일링 결과는 아래와 같다. "use strict";
var _Car = _interopRequireDefault(require("./Car"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var car = new _Car["default"](); import -> require로 변환 |
Beta Was this translation helpful? Give feedback.
-
리뷰미
문제1위에서부터 script를 읽으며 foo.js의 변수 값이 bar.js의 변수 값으로 덮어 씌워진다. 따라서 문제2프리코스에서는 webpack을 사용하지 않고 있고, 레벨 1 미션에서는 webpack을 사용하고 있다. 레벨 1 자동차 경주에서는 webpack 없이도 구현이 가능했으나, 이후 webpack으로 번들링할 미션을 마주하기 이전에 미리 경험해보자는 취지가 아니었을까 추측한다. 문제3Babel은 ES6을 지원하지 않는 구형 브라우저에서도 코드가 동작할 수 있게 트랜스파일 과정을 거치게 도와준다. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
코드잽구성원 (마스터위, 월하, 헤인) 문제1문제2
문제3
|
Beta Was this translation helpful? Give feedback.
-
팀 이름: 행동대장구성원 (토다리, 쿠키, 웨디, 문제1foo.js -> bar.js 순서대로 요청하고 받아옵니다. DOMContentLoaded 이벤트가 실행되었을 때 #ts, #js요소의 innerText는 전역 변수인 ts, js의 값으로 대체되는데요. 스크립트인 foo.js 를 실행해서 ts = 10000, js = 20000이라는 값이 선언과 동시에 초기화 됐습니다. 그 후 바로 bar.js 를 실행 해 ts = 20000, js = 40000이라는 값으로 ts, js의 값이 재할당 됩니다. var는 중복 선언이 허용되며, 중복 선언이 사용되었을 경우 제일 마지막에 선언된 값으로 값이 초기화됩니다. 그래서 결국 최종적으로 ts, js 변수의 값은 20000, 40000가 되어 화면의 #ts, #js 요소의 값은 20000, 4000으로 보여지게 됩니다. 문제2package.json을 보니까 웹팩 설치 유무에 차이가 있었습니다. 레벨 1의 경우는 웹팩을 사용해 번들링했고, 프리코스에는 웹팩이 없습니다. 그리고 프리코스에는 type: "module"이 있고 레벨 1의 경우는 없습니다. 웹팩으로 번들링을 하면 import,export를 할 필요가 없고 하나의 js파일로 뭉쳐지기 때문에 js파일을 모듈로 인식할 필요가 없어집니다. 또한 웹팩은 cjs, esm 둘 다 가능하기 때문에 굳이 cjs만 사용하도록 type: "module"을 선언해줄 필요가 없어집니다. 문제3못했습니다. |
Beta Was this translation helpful? Give feedback.
-
땅콩포메, 마루, 썬데이 문제1
foo.js에서 선언한 변수들을 추후에 bar.js 에서 재선언하면서 변수가 덮어 씌워진다 문제2프리코스 자동차 경주 저장소에서는 js 파일 자체를 실행시켰는데, 본 미션 자동차 경주 저장소에서는 빌드 결과물인 번들을 실행시킨다. 문제3import문이 require로 바뀌고 class 문법이 생성자 함수로 변경되었다 |
Beta Was this translation helpful? Give feedback.
-
방끗헤일리, 리안, 제이드 문제 1
script 불러올 때 순서대로 가져와지기 때문에 처음 그래서 결과값으로
이 된다. 문제 2프리코스:
본 코스:
문제 3 |
Beta Was this translation helpful? Give feedback.
-
코레아
문제1script끼리 동기적으로 실행되어 foo 다음에 bar가 실행된다. 동일한 스코프라서 변수명이 공유되고 var라서 값이 재할당 되었다. 문제2프리코스의 package.json에만 문제3node.js에서는 cjs 모듈 방식을 사용하는데 import 문법은 esm이라서 node.js에서 돌아가게 해주기 위해 Babel을 사용하였다. JS 최신 문법을 타겟 환경에서 안전하게 실행할 수 있도록 도와준다. |
Beta Was this translation helpful? Give feedback.
-
팀 이름: 크루루
문제 1결과
문제 21. ESModule의 사용 여부
2. 트랜스파일링 사용 여부
문제 3바벨은 ES6+의 최신 문법을 구형 자바스크립트 환경에서도 동작할 수 있도록 변환합니다. Car 클래스에 대해서 변환된 내용은 다음과 같습니다. 주요 변경점
"use strict";
function _typeof(obj) {
"@babel/helpers - typeof";
return (
(_typeof =
"function" == typeof Symbol && "symbol" == typeof Symbol.iterator
? function (obj) {
return typeof obj;
}
: function (obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype
? "symbol"
: typeof obj;
}),
_typeof(obj)
);
}
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports["default"] = void 0;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", { writable: false });
return Constructor;
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return _typeof(key) === "symbol" ? key : String(key);
}
function _toPrimitive(input, hint) {
if (_typeof(input) !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (_typeof(res) !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _classPrivateFieldInitSpec(obj, privateMap, value) {
_checkPrivateRedeclaration(obj, privateMap);
privateMap.set(obj, value);
}
function _checkPrivateRedeclaration(obj, privateCollection) {
if (privateCollection.has(obj)) {
throw new TypeError("Cannot initialize the same private elements twice on an object");
}
}
function _classPrivateFieldSet(receiver, privateMap, value) {
var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set");
_classApplyDescriptorSet(receiver, descriptor, value);
return value;
}
function _classApplyDescriptorSet(receiver, descriptor, value) {
if (descriptor.set) {
descriptor.set.call(receiver, value);
} else {
if (!descriptor.writable) {
throw new TypeError("attempted to set read only private field");
}
descriptor.value = value;
}
}
function _classPrivateFieldGet(receiver, privateMap) {
var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get");
return _classApplyDescriptorGet(receiver, descriptor);
}
function _classExtractFieldDescriptor(receiver, privateMap, action) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to " + action + " private field on non-instance");
}
return privateMap.get(receiver);
}
function _classApplyDescriptorGet(receiver, descriptor) {
if (descriptor.get) {
return descriptor.get.call(receiver);
}
return descriptor.value;
}
var _price = /*#__PURE__*/ new WeakMap();
var _distance = /*#__PURE__*/ new WeakMap();
var Car = /*#__PURE__*/ (function () {
function Car() {
_classCallCheck(this, Car);
_classPrivateFieldInitSpec(this, _price, {
writable: true,
value: 10000,
});
_classPrivateFieldInitSpec(this, _distance, {
writable: true,
value: 0,
});
}
_createClass(Car, [
{
key: "move",
value: function move() {
_classPrivateFieldSet(this, _price, _classPrivateFieldGet(this, _price) + 1000);
_classPrivateFieldSet(this, _distance, _classPrivateFieldGet(this, _distance) + 1);
},
},
]);
return Car;
})();
var _default = Car;
exports["default"] = _default; |
Beta Was this translation helpful? Give feedback.
-
투룻지니, 시모, 리버 문제1답 : js - 20000, ts - 40000 js에서 var 키워드로 선언된 변수는 함수 스코프를 가져서 모든 변수들이 window 객체 내 ts, js 변수로 선언됩니다. html 파일을 읽을 때 script를 하나씩 읽게 되는데 이 과정에서 foo.js를 읽을 때 10000,20000이 되고 bar.js를 읽을 땐 20000, 40000이 되어 최종적으로 ts는 20000, js는 40000이 됩니다. 문제2두 프로젝트의 차이점은 프리코스의 경우 반면, 레벨 1 자동차 경우에는 // App.js
import RacingGameController from './controller/RacingGameController.js';
const fs = require('fs');
console.log(fs);
const App = Object.freeze({
async start() {
await RacingGameController.run();
},
});
export default App; 하지만 lv1 자동차 미션에서 esm을 사용하는 것을 볼 수 있는데, 그 이유는 웹팩 내 번들링 과정에서 babel이 트랜스파일링 과정에서 cjs 문법과 esm 문법 모두 지원해주기 때문에 esm과 cjs 문법 모두 지원하는 것을 알 수 있습니다. 문제3"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
var _price = /*#__PURE__*/new WeakMap();
var _distance = /*#__PURE__*/new WeakMap();
var Car = /*#__PURE__*/function () {
function Car() {
_classCallCheck(this, Car);
_classPrivateFieldInitSpec(this, _price, {
writable: true,
value: 10000
});
_classPrivateFieldInitSpec(this, _distance, {
writable: true,
value: 0
});
}
_createClass(Car, [{
key: "move",
value: function move() {
_classPrivateFieldSet(this, _price, _classPrivateFieldGet(this, _price) + 1000);
_classPrivateFieldSet(this, _distance, _classPrivateFieldGet(this, _distance) + 1);
}
}]);
return Car;
}();
var _default = Car;
exports["default"] = _default; class Car {
#price = 10_000;
#distance = 0;
move() {
this.#price += 1_000;
this.#distance += 1;
}
}
export default Car; 두 코드의 차이점은 옛날 문법으로 변환된 여부 차이입니다. 트랜스파일링 한 이전에는 es6로 작성된 문법이지만, 이후는 es5로 변환하기 때문에 오래된 브라우저나 환경에서도 동작 가능합니다. 즉, 최신 js 문법과 기능을 사용하면서도 그 코드가 오래된 환경에서도 동작할 수 있도록 할 수 있습니다. |
Beta Was this translation helpful? Give feedback.
-
모우다멤버: 소파, 수야, 치코1. 아래의 코드 결괏값과 왜 이렇게 도출되는지를 설명하세요./index.html <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./src/foo.js"></script>
<script src="./src/bar.js"></script>
<script>
addEventListener("DOMContentLoaded", () => {
document.querySelector("#ts").innerText = ts;
document.querySelector("#js").innerText = js;
});
</script>
</head>
<body>
<p>Typescript: <span id="ts"></span></p>
<p>Javascript: <span id="js"></span></p>
</body>
</html> /src/foo.js var ts = 10000;
var js = 20000; /src/bar.js var ts = 20000;
var js = 40000; var≤=전역객체의 프로퍼티의 값 근데 전역 객체는 하나다 <script src="./src/foo.js"></script>
<script src="./src/bar.js"></script>
<script>
addEventListener("DOMContentLoaded", () => {
document.querySelector("#ts").innerText = ts;
document.querySelector("#js").innerText = js;
});
</script> 위 스크립트는 결국 이거다. var ts = 10000;
var js = 20000;
var ts = 20000;
var js = 40000;
addEventListener("DOMContentLoaded", () => {
document.querySelector("#ts").innerText = ts;
document.querySelector("#js").innerText = js;
}); 다만 두 script에 async가 붙어 불러오는 순서가 보장되지 않을 경우 값은 다르게 나올 수 있다 2. 크론이 의도한 프리코스 자동차 경주 저장소와 본 미션 자동차 경주 저장소의 차이점과 팀에서 그렇게 생각하게 된 이유를 설명하세요.(힌트: package.json을 참고한다) 레벨1 소파 제출 https://github.com/woowacourse/javascript-racingcar/blob/ss0526100/src/index.js 레벨 1 호프 https://github.com/woowacourse/javascript-racingcar/blob/moonheekim0118/package.json 핵심 키워드:
디폴트값 → CJS 문법으로 모듈화 → require, exports 문법 사용 https://webpack.kr/api/module-methods/ 이론은 도출했는데, 실제가 다른 걸 봤죠.
CJS는 ESM을 import() 할 수 있지만, 좋은 방법은 아니다
지금부터는 CJS에서 import를 사용해 ESM 스크립트를 가져오고 싶다면, 비동기적으로 dynamic import() 를 사용해야 한다.
(async () => {
const {foo} = await import('./foo.mjs');
})();
JavaScript
음.. 어떤 exports도 쓰지 않는다면 괜찮아 보인다. 만약 exports가 필요하다면 Promise를 export해야 하므로 (스크립트의) 사용자에게 엄청난 불편함을 줄 수 있다.
module.exports.foo = (async () => {
const {foo} = await import('./foo.mjs');
return foo;
})();
JavaScript cjs는 동기적/import에 변수 할당 가능 ems는 비동기적/import에 변수 할당 불가능 변수할당된 cjs→esm 변경 어려울듯 변수할당되지 않은 esm→cjs 변경 쉬울듯?(esm에 await 걸면 되니까) 3. 아래의 절차에 따라 Babel을 사용하여 트랜스파일링하고, 원본 코드와 Babel을 이용해 트랜스파일된 코드의 차이점은 무엇인지 설명하세요. 특히, 이러한 변환이 필요한 이유를 포함하여 설명하세요.
|
Beta Was this translation helpful? Give feedback.
-
🍀 코딩해듀오파란, 해시, 파슬리 1️⃣ 문제1foo.js와 bar.js는 순서대로 로드됩니다. 즉, foo.js가 먼저 실행되고 그 다음에 bar.js가 실행됩니다. 이후에 DOM이 완전히 로드되면 DOMContentLoaded 이벤트 핸들러가 실행되며, 변수 ts와 js의 값을 읽어 화면에 출력합니다. 브라우저는 foo.js에서 결론적으로, JavaScript에서 전역 범위에서 선언된 변수들은 같은 이름을 사용할 경우 새로운 값을 덮어씌우는 방식으로 동작합니다. 스크립트가 로드되는 순서에 따라, bar.js의 변수가 foo.js에서 선언된 변수를 덮어씌웠기 때문에 최종적으로 ts는 20000, js는 40000으로 설정됩니다. 2️⃣ 문제2프리코스 자동차 경주 저장소의 package.json에는 package.json에서 본 미션의 경우, Webpack과 함께 babel-loader를 사용해 ESM으로 작성된 파일을 CommonJS로 트랜스파일링합니다. 따라서 3️⃣ 문제3시간 문제로 생각해 보지 못했습니다 😭
// dist/index.js
"use strict";
var _Car = _interopRequireDefault(require("./Car"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var car = new _Car["default"]();
car.move();
car.move();
car.move();
// dist/Car.js
"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
var _price = /*#__PURE__*/new WeakMap();
var _distance = /*#__PURE__*/new WeakMap();
var Car = /*#__PURE__*/function () {
function Car() {
_classCallCheck(this, Car);
_classPrivateFieldInitSpec(this, _price, {
writable: true,
value: 10000
});
_classPrivateFieldInitSpec(this, _distance, {
writable: true,
value: 0
});
}
_createClass(Car, [{
key: "move",
value: function move() {
_classPrivateFieldSet(this, _price, _classPrivateFieldGet(this, _price) + 1000);
_classPrivateFieldSet(this, _distance, _classPrivateFieldGet(this, _distance) + 1);
}
}]);
return Car;
}();
var _default = Car;
exports["default"] = _default; |
Beta Was this translation helpful? Give feedback.
-
수업 시간에 공개됩니다.
1. 아래의 코드 결괏값과 왜 이렇게 도출되는지를 설명하세요.
/index.html
/src/foo.js
/src/bar.js
2. 크론이 의도한 프리코스 자동차 경주 저장소와 본 미션 자동차 경주 저장소의 차이점과 팀에서 그렇게 생각하게 된 이유를 설명하세요.
(힌트: package.json을 참고한다)
3. 아래의 절차에 따라 Babel을 사용하여 트랜스파일링하고, 원본 코드와 Babel을 이용해 트랜스파일된 코드의 차이점은 무엇인지 설명하세요. 특히, 이러한 변환이 필요한 이유를 포함하여 설명하세요.
Beta Was this translation helpful? Give feedback.
All reactions