리액트 정리(#1 최신 자바스크립트)

so ez·2020년 7월 20일
1

React - Learning React

목록 보기
1/1
post-thumbnail

자바스크립트는 웹 페이지 상호작용을 손쉽게 추가하기 위해 만든 언어이며, DHTML과 AJAX를 거치며 더 활발히 사용 되었다.
또한 노드가 등장함에 따라 풀스택 어플리케이션을 개발하는데 쓰이는 언어가 되었다.

자바스크립트의 변화를 주도하는 기관이 ECMA(에크마)다.
커뮤니티의 누구든 ECMA에 제안서를 제출할 수 있으며, ECMA 위원회는 제안서를 잘 정의된 여러 단계에 거쳐 채택한다.

자바스크립트 명세는 2015년 6월에 크게 개정되며 ECMAscript 6, ES6, ES2015, ES6Harmony 등 다양한 이름으로 불렸다.

그 후 ECMA는 연도를 부여해 버전 이름을 붙이고 매년 자바스크립트 명세를 개정하기로 합의했다고 한다!

ES6에서 변수 선언하기

ES6 이전에는 var키워드가 변수를 선언하는 유일한 방법이었으나, 지금은 몇 가지 방법이 추가되었다!

1. const

상수(const)는 변경할 수 없는 변수다.
상수가 없던 시절에는 모든 값을 변수에 넣어 사용했다.
하지만 변수는 값을 변경할 수 있다.

var study = true;
study = false;
console.log(study) // false

이전에 상수로 사용했으나 값이 바뀌는 상황.

const study = true;
study = false;
//	Uncaught TypeError가 발생함

const로 선언하고 값을 변경하려고 시도하면 오류가 발생한다.

2. let

기존 var는 if/else 블록 안에서 변수를 새로 만들면 그 변수의 영역이 블록 안으로만 한정되지 않았다.

var study = "자바스트립트";

if(study){
	var study = "리액트";
	console.log('공부하자', study); // 공부하자 리액트
}

console.log('재밌다', study); // 재밌다 리액트

위와 같이 if문 안의 study값을 변경하면 if밖의 study도 변경됐다.
그러나 let을 사용하면 변수 영역을 코드 블록 안으로 한정시킬 수 있다.
그러므로 글로벌 변수의 값을 보호할 수 있다!
(아래 코드와 비교)

var study = "자바스트립트";

if(study){
	let study = "리액트";
	console.log('공부하자', study); // 공부하자 리액트
}

console.log('재밌다', study); // 재밌다 자바스크립트

for문도 마찬가지다.

3. 템플릿 문자열

템플릿 문자열을 문자열 연결 대신 사용할 수 있다.
그러면 중간에 변수를 삽입할 수도 있다.
전통적인 문자열 연결은 더하기 기호(+)로 문자열과 변수를 서로 이어붙이는 방식을 사용한다.

console.log(lastname + ", " + firstname + " " + middlename);

템플릿에서는 ${ }를 사용해 문자열 안에 변수를 집어넣을 수 있기 때문에 문자열을 단 하나만 사용해도 된다.

console.log(`${lastname}, ${firstname} ${middlename}`);

더하기 기호를 사용한 기존의 방식과 결과는 동일하다.

템플릿 문자열은 공백(빈 칸뿐 아니라 탭이나 개행문자 등도 포함)을 유지한다.
따라서 전자우편 템플릿이나 코드예제 등 공백이 들어가야 하는 문자열을 사용할 때는 템플릿 문자열을 사용한다.

예제를 보자!

`
${firstname} 님께,

${event} 티켓 ${qty}건을 구매해주셔서 감사합니다.

주문 상세 정보 :
	${lastname} ${firstname} ${middlename}
    ${qty} x $${price} = $${qty*price}	공연 : ${event}
    
공연 30분 전까지 배부처에서 티켓을 수령하시기 바랍니다.
감사합니다 :)

${ticketAgent} 드림
`

예전에는 자바스크립트에서 HTML 문자열을 직접 사용하려면 모든 문자열을 +로 연결하여 한줄로 처리해야했기 때문에 쉽지 않았다.
이제는 문자열 안의 공백 문자가 제대로 처리되기 때문에 이해하기 쉽게 정렬된 HTML을 코드로 넣을 수 있다.

4. 디폴트 파라미터

C++나 파이썬같은 언어에서는 함수의 인자로 디폴트 값을 선언할 수 있다.
ES6 명세에도 디폴트 파라미터가 추가되었다.
따라서 함수를 호출하면서 값을 지정하지 않으면 디폴트 값이 사용된다.

예를 들어 디폴트 문자열을 다음과 같이 설정할 수 있다.

function logActivity(name="EZ", activity="서핑"){
	console.log(`${name}은(는) ${activity}을(를) 좋아합니다.`);
}

logActivity 함수를 호출하면서 인자를 지정하지 않아도 디폴트 값을 사용해서 함수가 정상적으로 실행된다.
문자열뿐 아니라 어떤 타입의 값도 디폴트 값으로 사용할 수 있다.

var dafaultPerson = {
	name: {
    	first : "Z",
        last : "E",    
    },
    favActivity: "서핑"
}

function logActivity(p = dafaultPerson){
	console.log(`${p.name.first}은(는) ${favActivity}을(를) 좋아합니다.`);
}

화살표 함수

화살표 함수(arrow function)는 ES6에 새로 추가된 유용한 기능이다.
이를 사용하면 function 키워드 없이도 함수를 만들 수 있으며, return을 사용하지 않아도 식을 계산한 값이 자동으로 반환된다.

기존 방식과 화살표 함수를 비교해보자 :)

기존 함수 방식

var lordify = function(name) {
	return `열심히 공부하는 ${name}`;
}

console.log(lodify("EZ")); // 열심히 공부하는 EZ

화살표 함수 방식

var lodify = name => `열심히 공부하는 ${name}`;

이렇게 화살표를 사용하면 모든 함수 정의를 한 줄로 끝낼 수 있다.
function 키워드를 없앴고 어떤 값을 반환하는지 화살표가 지정해주기 때문에 return도 없앴다.
또 다른 장점은 함수가 파라미터를 단 하나만 받는 경우 파라미터 주변의 괄호를 생략해도 된다는 것이다.
파라미터가 2개 이상이라면 괄호가 필요하다

var lodify = (name, study) => `${study}를 공부하는 ${name}`;

console.log(lodify("EZ","react")); // react를 공부하는 EZ

p.36 this와 화살표 함수 이해하고 작성하기

ES6 트랜스파일링

모든 웹브라우저가 ES6를 지원하지는 않고, 지원하더라도 모든 기능을 지원하지 않는 경우가 많다.
그러니 브라우저에서 ES6코드를 실행하기 전에 ES5로 컴파일하면 ES6가 제대로 작동하도록 보장할 수 있다.
이런 변환을 트랜스파일링(transpiling)이라고 한다.
가장 유명한 트랜스파일링 도구로는 바벨(Babel)이 있다.

트랜스파일링으로 브라우저가 최신 자바스크립트 기능을 지원할 때 까지 기다리지 않아도 바로 사용할 수 있게 됐다!
트랜스파일링은 한 버전의 자바스크립트 코드를 더 많은 브라우저가 이해할 수 있는 다른 버전의 자바스크립트 구문으로 변환하는 것이다.
게다가 이제는 자바스크립트에서 소스코드가 생겨났다.
이 말은 브라우저에서 직접 실행할 수 있는 파일이 프로젝트에 들어있는 경우도 있다는 뜻이다.

const add = (x=5, y=10) => console.log(x+y);

이 코드를 트랜스파일러로 변환하면 다음과 같은 출력이 생긴다.

"use strict";

var add = function add(){
	var x = arguments.length <= 0 || arguments[0] === undifined ? 5 : arguments[0];
    var y = arguments.length <= 1 || arguments[1] === undifined ? 10 : arguments[1];
	return console.log(x+y);
};

트랜스파일러는 use strict 선언을 맨 위에 추가해서 코드가 엄격한 모드에서 실행되도록 만든다.
x와 y 파라미터의 디폴트 값은 arguments 배열로 처리된다.
이렇게 만들어진 자바스크립트는 다양한 브라우저에서 사용 가능하다.

인라인 바벨 트랜스파이럴를 사용하면 브라우저에서 자바스크립트를 직접 트랜스파일 할 수도 있다.
browser.js 파일을 포함시키고(HTML의 script태그 사용), 변환하고 싶은 코드의 script 태그에 type="text/babel"을 지정하면 된다.

<div id="output"></div>
<!--바벨 로딩-->
<script src = "https://unpkg.com/babel-stendalone@6/babel.min.js"></script>
<!--변환할 코드를 script태그 안에 넣기 -->
<script type="text/babel">
const getMessage = () => "Hello World";
document.getElementById('output').innerHTML = getMessage();
</script>
<!--파일에 있는 소스 코드를 트랜스파일링 하기-->
<script src="script.js" type="text/babel">

ES6 객체와 배열

ES6는 객체와 배열을 다루는 방법과, 객체와 배열 안에서 변수영역을 제한하는 방법을 다양하게 제공한다.
그러한 기능으로 구조분해, 객체 리터럴 개선, 스프레드 연산자 등이 있다.

1. 구조 분해를 사용한 대입

구조분해(destructuring)를 사용하면 객체 안에 있는 필드 값을 원하는 변수에 대입할 수 있다.

바로 예제를 보자!

var sandwich = {
  bread : "플랫 화이트",
  meat : "베이컨",
  topping : ["치즈","상추","칠리소스"]
}

var {bread, meat} = sandwich;
console.log(bread, meat); // 플랫 화이트 베이컨

위 코드는 sandwich를 분해해서 bread와 meat필드를 같은 이름의 변수에 넣어준다.
두 변수의 값은 sandwich에 있는 같은 이름의 필드 값으로 초기화 되지만, 두 변수를 변경해도 원래의 필드 값은 바뀌지 않는다.

변수 변경해도 필드값 안바뀌는 예제 ㄱㄱ

var {bread, meat} = sandwich;

bread = "식빵"
meat = "삼겹살"

console.log(bread, meat); // 식빵 삼겹살
console.log(sandwich.bread, sandwich.meat); // 플랫 화이트 베이컨

객체를 분해해서 함수의 인자로 넘길 수도 있다.

var study = person => {
  console.log(`오늘도 공부하는 ${person.firstname}`);
}

var person = {
  firstname : "zeze",
  lastname : "E"
}

study(person); // 오늘도 공부하는 zeze

객체의 필드에 접근하기 위해 점(.)과 필드이름을 사용하는 대신 person에 필요한 값을 구조분해로 가져올 수도 있다.

var study = ({firstname}) => {
  console.log(`오늘도 공부하는 ${firstname}`);
}

study(person); // 오늘도 공부하는 zeze

구조 분해는 더욱 선언적이라 코드를 작성한 사람의 의도를 잘 설명해준다.
구조 분해로 firstname을 가져옴으로써 객체의 필드 중에서 firstname만 사용한다는 사실을 선언한다.

배열을 구조분해해서 원소의 값을 변수에 대입할 수도 있다.
배열의 첫번째 원소를 변수에 대입하고싶다고 가정하자.

var [firstResort] = ["용평","평창","강촌"];

console.log(firstResort); // 용평

불필요한 콤마(,)를 사용해 생략하는 리스트 매칭을 사용할 수도 있다.
무시하고 싶은 원소 위치에 콤마를 넣으면 리스트 매칭이 된다.
위 배열에서 첫 두 원소를 콤마로 대치하면 다음과 같다.

var [,,thirdResort] = ["용평","평창","강촌"];

console.log(thirdResort); // 강촌

헐 신기하다

2. 객체 리터럴 개선

객체 리터럴 개선(object literal enhancement)은 구조분해의 반대라 할 수 있다.
객체 리터럴 개선은 구조를 다시 만들어내는 과정 또는 내용을 한데 묶는 과정이라 할 수 있는데 이 구조를 사용하면 현재 영역에 있는 변수를 객체의 필드로 묶을 수 있다.

var name = "백두산";
var elevation = 2744; // 높이(단위: 미터)

var funHike = {name, elevation};

console.log(funHike) // {name: "백두산", elavation: 2744}

이제 funHike에는 name과 elevation이라는 필드가 들어있다.
객체 리터럴 개선 또는 객체 재구축으로 객체 메서드를 만드는것도 가능하다!

var name = "백두산";
var elevation = 2744;
var print = function(){
  console.log(`${this.name}의 높이는 ${this.elevation}m 입니다.`);
}
var funHike = {name, elevation, print}

funHike.print() //	백두산의 높이는 2744m 입니다.

이 때 객체 키에 접근하기 위해 this를 사용했다는 것을 유의하자.
객체 메서드를 정의할 때 더이상 function 키워드를 사용하지 않아도 된다!

3. 스프레드 연산자

스프레드 연산자(spread operator)는 세 개의 점(...)으로 이루어진 연산자로, 몇 개의 다른 역할을 담당한다.
먼저 배열의 내용을 조합할 수 있다. 예를 들어 두 배열이 있다면 스프레드 연산자를 적용하여 두 배열의 모든 원소가 들어간 세 번째 배열을 쉽게 만들 수 있다.

var food = ["닭갈비", "닭꼬치", "닭강정"]
var drink = ["소주", "맥주"]
var ezFavorite = [...food, ...drink]

console.log(ezFovorite.join(', '); // 닭갈비, 닭꼬치, 닭강정, 소주, 맥주

food와 drink에 포함된 모든 원소가 ezFavorite이라는 새 배열에 들어간 것을 확인할 수 있다.

이 스프레드 연산자로 해결할 수 있는 문제를 보자!
food 배열의 마지막 원소를 변수에 담고싶다고 가정하고 Array.reverse 메서드를 사용해 배열을 뒤집고 구조 분해를 사용해 첫 번째 원소를 변수에 넣어보자.

var food = ["닭갈비", "닭꼬치", "닭강정"]
var [last] = food.reverse();

console.log(last);	// 닭강정
console.log(food.join(', '));	// 닭강정, 닭꼬치, 닭갈비

마지막 콘솔에 찍어서 나온 결과와 같이 원본 배열도 변경되는 것을 확인할 수 있다.
하지만 스프레드 연산자를 사용하면 원본 배열을 변경하지 않고 복사본을 만들어서 뒤집을 수 있다!(와 나 이거때문에 코딩테스트에서 고생했었는데 ㅠ)

var food = ["닭갈비", "닭꼬치", "닭강정"]
var [last] = [...food].reverse();

console.log(last);	// 닭강정
console.log(food.join(', '));	// 닭갈비, 닭꼬치, 닭강정

스프레드 연산자를 사용해 배열의 원소를 복사했기 때문에 원본인 food는 변경되지 않고 그대로 남아있다.
따라서 나중에 필요할 때 food 연산자를 재사용 할 수 있당!

또한 배열의 나머지 원소를 얻을 수도 있다.
예제를 보시죠,,

var food = ["닭갈비", "닭꼬치", "닭강정"]
var [last] = [...food].reverse();

console.log(last);	// 닭강정
console.log(food(, ));	// 닭갈비, 닭꼬치, 닭강정

그만 쓰고싶은데 예제가 또 있다.
함수의 인자를 배열로 모을 수도 있다고 한다,,
아래는 'n개의 인자를 스프레드 연산자를 사용해 배열로 모은 다음 그 배열을 사용해 여러가지 내용을 콘솔 메시지로 찍는 함수'를 보여주는 예제다.

function directions(...args){
  var [start, ...remaining] = args;
  var [finish, ...stops] = remaining.reverse();
  
  console.log(`${args.length} 도시를 운행합니다.`);
  console.log(`${start}에서 출발합니다.`);
  console.log(`목적지는 ${finish}입니다.`);
  console.log(`중간에 ${stops.length}군데 들립니다.`);
}

  directions("서울", "수원", "천안", "대전", "대구", "부산");

directions 함수는 스프레드 연산자를 사용해 인자를 받는다.
첫번째 인자는 start 변수에 대입된다.
마지막 인자는 finish 변수에 Array.reverse를 사용하여 대입된다.
그 후 args 배열의 length를 사용해 몇개의 도시를 운행하는지 보여주고, 목족지로 가는동안 들러야 하는 도시의 수는 args 배열에서 2(출발지와 도착지)를 뺀 것이다.
directions 함수의 임의 개수는 경유 도시를 넘길 수 있기 때문에 이런 기능은 매우 편리하다!

마지막으로,,(우욱) 연산자를 객체에 사용할 수도 있다.
스프레드 연산자를 객체에 사용하는 방법은 배열에 사용한 것과 비슷하다,,
바로 예제를 보자.

var morning = {
  breakfast : "샌드위치",
  lunch : "닭갈비"
};

var dinner = "간장불고기";

var meals = {
  ...morning,
  dinner
};

console.log(meals);
// {brackfast: "샌드위치", lunch: "닭갈비", dinner: "간장불고기"}

드디어 스프레드 연산자가 끝~~!

프라미스

프라미스(promise)는 비동기적인 동작을 잘 다루기 위한 방법으로, 비동기 요청을 더 쉽게 처리할 수 있게 해준다.
자바스크립트에서는 비동기로 데이터를 처리하는 경우가 많기 때문에 비동기 요청을 쉽게 처리할 수 있으면 좋다. 노드에서도 프라미스를 많이 사용하는 것을 볼 수 있다.
따라서 프라미스를 잘 이해하는 것은 필수적인 덕목!

randomuser.me API로부터 데이터를 가져오는 비동기 프라미스를 하나 만들자.
이 API에는 가짜 멤버에 대한 전자우편 주소, 이름, 전화번호, 집주소 등의 정보가 들어 있으며, 그런 데이터를 더미(dummy)로 활용하기 좋다.

getFakeMembers 함수는 새로운 프라미스를 반환한다.
그 프라미스는 randomuser.me API에 요청을 보내는데,
프라미스가 성공한 경우에는 데이터를 제대로 받아올 것이고, 실패한 경우에는 오류가 발생할 것이다.

const getFakeMembers = count => new Promise((resolves, rejects) => {
  const api = `https://api.randomuser.me/?nat=US&results=${count}`;
  const request = new XMLHttpRequest();
  request.open = () =>
  	(request.status === 200) ?
    resolves(JSON.parse(request.response).results) :
    reject(Error(request.statusText))
  request.onerror = (err) => rejects(err);
  request.send();
})

이 함수로 프라미스를 만들 수 있게 되었지만 아직 사용한 것은 아니다.
가져오고 싶은 멤버 수를 getFakeMembers 함수에 전달해 호출하면 실제 프라미스를 사용할 수 있다.
프라미스가 성공한 경우에 처리할 작업을 기술하기 위해 then 함수를 프라미스 뒤에 연쇄(체이닝, chaining)시킨다.
이 때 오류를 처리하기 위한 콜백도 함께 제공한다.

getFakeMembers(5).then(
  members => console.log(members);,
  err => console.error(new Error("randomuser.me에서 멤버를 가져올 수 없습니다."));
)

클래스

이전 자바스크립트에는 공식적으로 클래스가 없었고 타입은 함수로 정의했다.
ES6에서는 클래스 선언이 추가되었다.하지만 자바스크립트는 여전히 기존 방식으로 작동한다.
함수는 객체며 상속은 프로토타입을 통해 처리된다.

클래스를 정의하면 new 키워드를 사용해 해당 클래스의 새로운 인스턴스를 만들 수 있다.
그 후 인스턴스의 메서드를 호출할 수 있다.
(클래스 이름의 첫글자는 대문자로 시작하는 관습이 있당)

class Vacation{
  constructor(destination, length){
    this.destination = destination;
    this.length = length;
  }
  
  print(){
    console.log(`${this.destination}은(는) ${this.length}일 걸립니다.`);
  }
}

const trip = new Vacation("칠레 산티아고", 7);

console.log(trip.print()); // 칠레 산티아고은(는) 7일 걸립니다.

클래스 객체를 만든 뒤에는 새로운 객체를 생성하기 위해 원하는만큼 new를 호출할 수 있다.
클래스를 확장할 수도 있다. 기존 클래스(부모클래스)를 확장한 새로운 클래스(자식클래스)는 상위 클래스의 모든 프로퍼티와 메서드를 상속한다.
이렇게 상속한 프로퍼티나 메서드를 하위 클래스 선언 안에서 변경할 수도 있다.

위 예제에서 쓴 Vacation을 여러가지 휴가 타입을 정의하기 위한 추상 클래스로 사용할 수도 있다.
예를 들어 아래 예제의 Expedition은 Vacation 클래스를 확장하여 장비를 표현하는 프로퍼티(gear)를 더 가진다.

class Expedition extends Vacation {
  constructor(destination, length, gear){
    super(destination, length);
    this.gear = gear;
  }
  
  print(){
    super.print();
    console.log(`당신의 ${this.gear.join("와(과) 당신의 ")}를(을) 가져오십시오.`);
  }
}

const trip2 = new Expedition("한라산", 3, ["카메라", "생수", "선글라스"]);

trip2.print();
// 한라산은(는) 3일 걸립니다.
// 당신의 카메라와(과) 당신의 생수와(과) 당신의 선글라스를(을) 가져오십시오.

ES6 모듈

자바스크립트 모듈(module)은 다른 자바스크립트 파일에서 쉽게 불러서 활용할 수 있는 재활용 가능한 코드 조각을 말한다.
이전에는 자바스크립트를 모듈화 하는 방법이 import와 export를 처리하는 라이브러리를 활용하는 것 뿐이었지만, ES6부터는 자바스크립트 자체에서 모듈을 지원하기 시작했다.

자바스크립트는 각각의 모듈을 별도의 파일로 저장한다.
모듈을 만들고 외부에 익스포트하는 방법에는
1. 한 모듈에서 여러 자바스크립트 객체를 외부에 노출시키는 방법
2. 모듈당 하나의 자바스크립트 객체를 노출시키는 방법
이 있다.

  1. 한모여자(한 모듈에서 여러 자바스크립트) 예제
export const print(message) => log(message, new Date());

export const log(message, timestamp) => console.log(`${timestamp.toString()}: ${message}`);

다른 모듈에서 사용하도록 이름(함수, 객체, 변수, 상수 등이 될 수도 있음)export할 수 있다.(위 예제에서는 print와 log 함수)
예제에서 정의된 다른 선언은 모듈 내부에 한정된다(즉, 로컬 선언이 된다)..

  1. 한모한자(한 모듈에서 한개의 자바스크립트) 예제
    export default 사용
const study = new Student("EZ", 7, ["react", "javascript"]);

export default study;

오직 하나의 이름만 노출하는 모듈에서 사용한다.

모듈은 import 명령을 사용해 다른 자바스크립틑 파일을 불러와 사용할 수 있다.
외부에 여러 이름을 노출한 모듈을 import할 때는 객체구조분해를 활용할 수 있따.
export default를 사용해 한 이름만 노출한 경우에는 노출된 대상을 구조분해없이 한 이름으로 부를 수 있다.

import {print, log} from './js파일 이름'
import study from './js파일 이름'

print('메시지를 print');
log('메시지를 log');

study.print();

모듈에서 가져온 대상에 다른 이름을 부여할 수도 있다.

import {print as p, log as l} from './js파일 이름'

p('메시지를 print');
l('메시지를 log');

import *를 사용하면 다른 모듈에서 가져온 모든 이름을 사용자가 정한 로컬 이름 공간 안에 가둘 수 있다.

import * as fns from './js파일 이름'

커먼JS

커먼JS는 모든 버전의 노드에서 지원하는 일반적인 모듈 패턴이다.
바벨이나 웹팩에서 사용할 수 있다.
커먼JS를 사용하면 자바 객체를 module.exports를 사용해 아래 예제처럼 export할 수 있다.

const print(message) => log(message, new Date())

const log(message, timestamp) => console.log(`${timestamp.toString()}: ${message}`);

module.exports = {print, log}

커먼 JS는 import문을 지원하지 않는다.
대신 require 함수로 모듈을 import할 수 있다.

const { print, log } = require('./js파일 이름')

여러번 읽으며 내용을 첨삭 할 예정입니다,,

profile
여기 프론트엔드 개발자 죽어가요

0개의 댓글