https://github.com/stepanowon/react-2021-spring-beginner
GitHub - stepanowon/react-2021-spring-beginner
Contribute to stepanowon/react-2021-spring-beginner development by creating an account on GitHub.
github.com
2022.8.1.월
ES6 를 위한 환경설정 방법
1. node.js 설치
2. visual studio code 설치
3. extension pack 설치
- Korean language
- Babel ES6/ES7
- Reactjs code sinppets
- view-in-browser
vscode를 새로 열고, 프로젝트 폴더 생성한다음 연다.
보기 > 터미널 열어서 > 파워쉘을 cmd로 바꿔준다. ( 강사와의 싱크를 위해서)
터미널에서 npm init 수행 (node package 를 하나 만드는 것이다.)
엔터키 쭉 눌러서 프로젝트 생성함
package.json 파일이 만들어지는 것 확인
아래 명령어를 입력해서 디펜던시 추가
npm install --save-dev babel-cli babel-core babel-preset-env babel-preset-stage-2
--global 옵션은 전역, --save-dev 옵션은 개발 의존성으로 설치하는 것
package.json에 devDependencies 추가된 것 확인
cli : command line interface ( 터미널에서 명령으로 실행하기 위한 인터페이스) ,
ex)babel 명령어를 터미널에서 입력 가능
babel은 .\node_modules\.bin\babel 에 설치되어있다.
core : 별도 언급 안함
preset-env : 표준문법
preset-env-stage-2 : 확장문법 (표준은 아닌데, 곧 표준이 되거나 많이 쓰는 문법)
npx : node pacakge executer (설치된 패키지의 경로들이 정리되어있고, 설치되어있지 않은 녀석은 다운로드까지 설치해줌)
.\node_modules\.bin\babel 으로 실행할 필요 없이 npx babel 로 실행하면된다.
.babelrc 파일 생성 후 아래 내용 작성
{
"presets" : {"env", "stage-2"}
}
src 폴더 만들고, sample.js 파일 하나 생성
let name = "World";
console.log(`hello ${name}!!`);
(여기서 삽질 포인트, 강의만 보고 따라 치다가 작은 따옴표로 감쌌는데 아무리 해도 중괄호가 일반 텍스트로 인식이 되지 않았다.
다음날까지 vs code es6 syntax error 등의 내용으로 삽질을 하다가 결국 알게된 사실... 작은 따옴표가 아니라 역따옴표다. backtick 이라고 불리는... 하아 정말 ㅋㅋㅋ 이내용 결국 뒷강의에 나온다.)
2022.8.2.화
--save : 전역 설치 (컴퓨터상의 어느 경로에서도 해당 패키지 이용가능, 대신 모든 프로젝트에 영향을 주기 때문에 권장 안함. 꼭 필요한것만)
--save-dev : 개발 의존성, 즉 개발할때만 필요하다.
es6로 작성된 코드를 es5로 트랜스파일해서 실행하기 때문에, babel은 개발할때만 필요하다.
--save : 메인 의존성, 개발할때도 필요하고, 실행할때도 필요한 패키지
남이작성한 코드에 devdependanceis가 추가되어있는데, 이걸 실행하려면 npm install 하면된다.
(때문에 작성한 코드를 전달할때는 node_modules 는 빼고 전달하면된다.)
작성은 es6로, 실행은 es5로 한다. 그럼 디버깅은?
디버깅도 es6로 하기 위해서는 source map이란 것을 활요한다.
npm install babel-plugin-source-map-support --save-dev
npx babel src/test1.js -o build/test1.js --source-maps (파일 단위)
npx babel src -d build --source-maps (디렉토리 단위)
자바스크립트 vs ES6 문법 비교
let 사용 가능, 기존의 var는 개발자를 힘들게 하는 문제가 하나 있다. 바로 Hoisting 작업
Hoisting : 변수를 미리 생성하는 것. 동일한 변수명으로 로컬 사용시 디버깅이 어려울 수 있다.
console.log(A1);
var A1 = "hello"
위와같은 문법도 에러가 나지 않는다. hoisting 때문에
자바스크립트는 Interpreter를 사용하여 Line 단위로 한줄씩 번역하고 실행을 한다.
이 경우, 변수를 할당하는 과정이 실행도중에 일어나서 느려지는 현상이 발생한다.
때문에, 메모리 할당작업을 스크립트 코드 블락을 웹브라우저가 문자열 그대로 로딩해서, 파싱하여 그 안에서 var 가 붙어있는걸 몽땅 찾아 메모리 할당 작업을 미리 한다.
console.log.(A1);
var A1 = "Hello";
console.log.(A1);
var A1 = 100;
console.log.(A1);
var A1 = {a:1};
console.log.(A1);
동일한 변수를 여러개 선언해도 에러가 나지 않는다.
위의 결과는 undefined, Hello, 100,a:1 이 출력된다.
Hoisting 과정중에 변수가 이미 생성되어 있다면, 변수 생성을 시도한다. 이미 존재하면 생성하는 작업을 하지 않는다.
즉, 아래와 같이 동작하게 되는 것이다.
var A1;
console.log.(A1);
A1 = "Hello";
console.log.(A1);
A1 = 100;
console.log.(A1);
A1 = {a:1};
console.log.(A1);
때문에 개발자는 변수이름의 중복을 회피해야한다.
var는 block level의 scope을 지원하지 않는다.
예를들어 아래 코드의 결과는 어떻게 될 것인가?
var A1 = 200;
function test() {
console.log(A1);
if (false) {
var A1 = 100;
}
console.log(A1);
}
test()
if 문에 false 가 걸려있기 때문에, 전역변수를 참조해서 200이 나온 뒤, 200이 한번 더 나올것을 기대할 것이다.
하지만 함수 내부도 Hoisting 되어 함수 내에 A1변수는 생성이 되지만, 실제 값이 할당되지 않아 undefined만 2개 찍히는 충격적인 결과가 나온다.
여기서 제대로 현타가 왔다. ㅋㅋ
let을 무조건 써야 하는 이유가 여기에 있다. 아니면 변수명 중복에 정말 주의해야할듯
(대부분 var를 let으로 대체 가능하다고한다. 대부분이면 안되는 경우도 있긴 있는듯..)
그러면서 추천해준 책은 : 인사이드 자바스크립트 (Inside JavaScript), 순수 문법을 공부하기 좋은책
es6 / es5 변환 확인은 아래 사이트에서 확인 가능
Babel · The compiler for next generation JavaScript
The compiler for next generation JavaScript
babeljs.io
es6 에서는 디폴트 파라미터를 전달 할 수 있다.
가변 파라미터(rest operator) 사용 가능
- 파라미터 마지막에 ..변수명으로 붙이면 가변인자가 되면 배열로 전달 받는다.
기존에는 argument 방식을 이용했었음.(내장 인자인 argument로 받아왔었음)
구조분해 할당이 가능하다.
let arr = [10,20,30,40];
let [a,b,c] = arr;
console.log(a,b,c);
let p1 = {name : "홍길동", age:20, gener:"M"};
let {name, age} = p1;
let obj= {
a : {a1 : {a11:100. a12 : 200}},
b : {b1 : 300, b2:400}
}
let{a:{a1:{a11}}, b:{b1}} = obj;
let{a:{a1:{a11 : z1}}, b:{b1}} = obj; // a11을 z1 으로 받아낼 수도 있다.(변수명을 바꿀수있다.)
구조분해 할당의 참맛은, 함수 파라미터 전달할 때.
Arrow function 표현식을 사용할 수 있다.
//전통적인방식
let test1 = function(a,b) {
return a+b;
}
// arrow 표현식 (타언어의 람다와 비슷)
let test2 = (a,b) => {
return a+b;
}
// 리턴문만 있을땐 리턴값만 적어도 된다.
let test3 = (a,b)=> a+b;
arrow 표현식을 왜 쓰는가? 자바스크립트의 this 문제 때문에 쓴다.
자바크스립트에서 this는 현재 호출중인 메서드를 보유한 객체를 가리킨다.(default)
자바에서의 this는 객체 자기 자신을 가리킨다.
binding 시점
java / C# : 생성자가 호출되는 시점에 this가 바인딩 된다.
JS : 메서드를 호출할때마다 this가 바인딩 된다.
var obj = {result : 0};
obj.add = function(x,y) {
this.result = x+y;
}
obj.add(3,4); // add를 호출하는 객체가 obj 이니, add내부의 this는 obj 가된다.
console.log(obj);
var obj = {result : 0};
obj.add = function(x,y) {
this.result = x+y;
}
//obj.add(3,4); // add를 호출하는 객체가 obj 이니, add내부의 this는 obj 가된다.
//console.log(obj);
//만약 아래와 같이 실행된다면?
var add2 = obj.add;
console.log(add2 === obj.add);
add2(3,4);
console.log(obj); // result 값이 0으로 나온다.
console.log(window.result); // 실제 global 영역의 result에 저장되어있다.
Lexical binding 이라고 하는 현상때문에 이런 일이 발생한다. (메서드를 어느 객체의 메서드 형태로 호출하느냐에 따라 this가 연결되는 것)
때문에 JS에서는 apply, call 메서드를 이용해서 this를 지정할 수 있다.
var obj = {result : 0};
obj.add = function(x,y) {
this.result = x+y;
}
var obj = {};
// add 함수에 obj를 직접 this로 지정하여 호출한다.
add.apply(obj,[4,5]); //apply는 인자를 배열로 전달
add.call(obj,3,4); // call은 인자를 가변으로 전달
bind 메소드를 사용해서 this지정도 가능하다.
var obj = {result : 0};
obj.add = function(x,y) {
this.result = x+y;
}
var obj = {};
var add2 = add.bind(obj);
add2(4,5)
그럼 함수가 중첩되었을 때는?
var obj = {result : 0};
obj.add = function(x,y) {
console.log(this); // obj 의 this이다.
function inner() {
this.result = x+y;
}
inner();
// 함수 호출을 그냥 호출한다. 객체가 없으면 global이 생략된 것으로 간주된다.
// 때문에 inner내의 result는 전역변수 에 할당되어버린다.
}
obj.add(4,5);
위와 같이 Lexical binding의 문제가 발생하여 개발자를 힘들게 한다;
이를 해결하기 위해 apply,call, bind등을 사용해야한다.
하지만 arrow function을 사용하면 이 모든게 해결된다. (화살표 함수는 Lexical binding 하지 않는다.)
var obj = {result : 0};
obj.add = function(x,y) {
console.log(this); // obj 의 this이다.
let inner = () => {
this.result = x+y;
}
inner();
// 함수 호출을 그냥 호출한다. 객체가 없으면 global이 생략된 것으로 간주된다.
// 때문에 inner내의 result는 전역변수 에 할당되어버린다.
}
obj.add(4,5);
Object literal (중괄호)
속성명과, 변수명이 같으명 생략 가능하다.
var obj = {name : name, age:age, email:email}
var obj = {name,age,email};
기존엔 속성에 function을 할당하면 메서드가 된다.
변경된 방법에서는 속성 표기 없이, 함수명만 써도된다. ( 조금더 자바스럽게 바뀜)
backtick 을 사용할 수 있다.
템플릿 대입문 ${} 로 문자열 끼워넣기 기능 제공
여러줄도 표기 가능.
Class, 상속 기능 지원, 생성자는 cunstroctor라고 선언
(문법이 java와 거의 비슷하여, 자세히 설명하지 않고 스킵)
Callback 지옥을 벗어날 수 있는 방법 : Promise 패턴을 지원 (자바스크립트 비동기 처리를 수행하는 추상적인 패턴)
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
var num = Math.round(Math.random() * 20);
var isValid = num % 2;
if (isValid) { resolve(num); }
else { reject(num); }
}, 1000);
});
p.then(function(num) {
console.log("SUCCESS : " + num);
}).catch(function(num) {
console.log("FAIL : " + num);
});
console.log("Hello!");
Promise Chaining을 통해 연속적인 작업 처리 가능.
Promise.all()
- 모든 작업이 완료되면 resolve promise를 리턴한
- 작업 중 하나라도 reject이 되면 reject promise를 리턴함
Promise.race()
- 주어진 promise 들 중에서 하나라도 완료되면 resolve하는 메서드
Module 시스템
import를 위해서는 export를 먼저해야한다. export된 것들만 import 가능하다.
module 안에서 선언된 모든 것은 local 이다. (java로 따지자면 private 과 같다.)
export 한 것은 public 상태가 된 다.
export 대상 항목은 - let, const, var, function, class 가 있다.
export let a = 1000;
export function f1(a) { }
export { n1, n2 as othername, ...}
import
다른 모듈로부터 값,함수,클래스들을 임포트 할 수 있다.
import * as obj from '모듈 경로'
import {name1, name2 as otername, ...} from '모듈 경로'
import default-name from '모듈 경로'
vc code 에서 import 입력하면 자동완성 뜨는데 statement로 나온 항목 선택하면 코드가 자동완성으로 작성된다.
모듈 경로는 상대 경로다 (현재 소스가 있는 폴더 기준의 상대경로)
default export
default export 를 이용하면 단일 값을 export/ import 할 수 있다. ( 가장 빈번하게 쓰이는 녀석을 default export 로 지정한다.
// src/module1.js
let base = 100;
const add = (x) => base + x;
const multiply = (x) => base * x;
const getBase = () => base;
export{ add, multiply };
export default getBase;
//src/main.js
import getBase, { add, multiply } from './module1";
Spread Operator ( 전개 연선자)
객체나 배열을 복제할 때 자주 사용한다.
- 기존 객채,배열을 그대로 둔 채 새로운 객체, 배열을 생성함. (주소만 참조하는것이 아니라 값 자체를 복사함)
- 불병성(immutability) 확보를 위해 사용한다.
let arr = [10,20,30];
let arr2 = [...arr];
console.log(arr2);
let arr3 = ["hello", ...arr, "world"];
console.log(arr3);
let obj = { a:100, b:200 };
let obj2 = { ...obj };
console.log(obj === obj2); // false
let obj3 = {...obj, c:300, d:400};
console.log(obj3); // {a:100,b:200,c:300,d:400)}