Learning React 2장

hyena_lee·2023년 3월 23일
0

React

목록 보기
10/10
post-thumbnail

2.1 변수 선언하기

2.1.1 const 키워드

  • 상수는 값을 변경할 수 없는 변수이다.
  • 상수에는 값을 재설정하는 것은 불가능하다.
  • 상수 값을 변경하려면 에러 발생
var pizza = true;
pizza = false;
console.log(pizza);  //false

2.1.2let 키워드

  • 구문적인 변수 영역 규칙을 지원한다.
  • 자바스크립트에서는 중괄호{} 를 사용해 코드 블록을 만든다
  • 코드 블록이 별도의 변수 영역을 이룬다
  • if/ else 문 같은 경우는 다르다
  • if/ else 블록 안에서 변수를 새로 만들면, 그 변수의 영억이 그 블록안으로만 한정되지 않는다
var topic = '자바스크립트';
if(topic) {
  var topic = '리액트';
  console.log('블록', topic);  // 블록 리액트
}

console.log('글로벌', topic);  // 글로벌 리액트
  • 이 코드에서 if 블록 안의 topic 변수를 변경하려면 if 블록 밖의 topic 변수 값도 변경된다.(실제로는 두 변수가 같은 변수다)
  • let 키워드를 사용하면 변수의 영역을 코드 블록 안으로 한정 시킬 수 있다.
  • let을 사용하면 블록 안에서 글로벌 변수를 보호할 수 있다.
var topic = '자바스크립트';
if(topic) {
  let topic = '리액트';
  console.log('블록', topic);  // 블록 리액트
}
console.log('글로벌', topic);  // 글로벌 자바스크립트
  • if 블록 안의 topic 을 변경해도 if 블록 바깥의 topic 에는 아무런 영향이 없다.
  • 중괄호가 새로운 영역을 만들어내지 못하는 다른 부분으로는 for loop 가 있다.

박스와 관계없이 i 값은 5

var div,
    container = document.getElementById('container');

for (var= i=0; i < 5; i++) {
  div= document.createElement('div');
  div.onclick = function() {
  	alert('이것은 박스 #' + i +'입니다.');
  }
  container.appendChild(div);
}
  • 이 루프에서 컨테이너 안에 5개 div 만든다
  • 각 div 에는 그 div의 인덱스를 경고창에 표시해주는 onclick 핸들러가 할당된다.
  • for 루프 안에서 i를 선언해도 글로벌 영역에 i가 생긴다.
  • i 가 5가 될때까지 for loop 돈다
  • 5개의 div 박스 중 어느것을 클릭하건, i으 값은 글로벌 변수 i에 있는 5이기 때문에 표시되는 인덱스는 모두 같다.

let으로 i의 영역을 제한

  • var 대신 let을 사용해 루프 카운터 변수 1를 선언하면 i의 영역이 블록으로 제한된다.
  • 각 박스를 클릭하면 헤당 박스를 루프를 생성할 때 사용한 i 값이 정상적으로 표시된다.
const container = document.getElementById('container');
let div;
for(let i =0; i '< 5; i++) {
    div = document.getElementById('div');
    div.onclick = function() {
  		alert('이것은 박스 #: 'i +i + '입니다.');
	};
   container.appendChild(div);
}
  

2.1.3템플릿 문자열

  • 템플릿 문자열을 문자열 연결 대신 사용한다.
  • 템플릿 문자열을 사용하면 문자열 중간에 변수를 삽입 할 수도 있다.
  • 전통적인 문자열 연결은 더하기 기호 (+) 로 문자열과 변수를 서로 이어붙이는 방식을 사용한다.
console.log(lastName + ", " + firstName + "" + middleName);
  • 템플릿에서는 변수를 ${}를 사용해 문자열 안에 집어 넣을 수 있기 때문에, 문자열을 단 하나만 사용해도 된다.
console.log(`${lastName}, ${firstName} ${middleName}`);

템플릿 문자열은 공백을 유지해줌

const email = `
	${firstName} 님께

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

주문 상세 정보:
	${lastName} ${firstName} ${middleName}
	${qty} * $${price} = $${qty * price} 공연: ${event}

공연 시작 30분 전까지 배부처에서 티켓을 수령하시 바랍니다.
감사합니다.
${ticketAgent} 드림
`
  • 문자열 안의 공백 문자가 제대로 처리되기 때문에 코드에 이해하기 쉽게 잘 정렬한 HTML 넣을 수 있다.
document.body.innerHTML = `
	<section>
		<header>
			<h1>The HTML5 Blog</h1>
		</header>
		<article>
			<h2>${article.title}</h2>
			${article.body}
		</article>
		<footer>
			<p>copyright ${new Date().getYear() | The HTML% Blog}</p>
		</footer>
	</section>
`;

2.2함수 만들기

2.2.1 함수 선언

  • 함수 선언 또는 함수 정의는 function 키워드로 시작하고, 그 뒤에 함수 이름이 온다.
  • 다음 코드 함수 이름은 logCompliment 이다.
  • 함수에 속한 자바스크립트 문장은 중괄호 ({}) 사이에 들어간다.
function logCompliment() {
  console.log("할수있다!");
}

선언한 함수 호출해 실행하기

function logCompliment() {
  console.log('할수있다');
}
logComliment();
  • 함수가 호출되면 (함수 정의에서 함수 본문에 넣은) 위로의 글이 로그에 표시된다.

함수 표현식

  • 함수를 만드는 다른 방법으로는 함수표현식이 있다.
  • 함수표현식은 (이름 없는) 함수를 만들며, 변수에 값을 대입할 수 있다.
const logName = funciton () {
	console.log('할수있다!');
};
logName();
  • 결과는 앞의 (이름있는) 함수와 똑같다. 콘솔에 "할수있다!" 가 출력된다.
// 선언하기 전에 함수를 호출한다.
hey();

// 함수 선언
function hey() {
  	alert("hey")
}
  
  • 함수가 호이스팅, 즉, 함수가 파일의 맨 앞에 정의된 것처럼 처리되기 때문에 이 코드가 제대로 작동한다. 단 같은식을 함수 표현식에 대해 적용하면 아래와 같이 오류가 발생한다.
// 선언하기 전에 함수를 호출한다.
hey();

// 함수 표현식
const hey = function() {
	alert("hey!")
};
// Error: hey is not a function

인수 넘기기

  • logName 함수는 아무 인수나 파라미터를 받지 않는다.
  • 함수가 사용하는 변수에 대핻 동적으로 값을 제공받고 싶다면, 함수 이름 뒤의 괄호 안에 파라미터 이름을 추가해서 함수를 선언된다.
  • firstName 이라는 변수를 추가해 logName 를 다시 정의
const logName = function(firtsName) {
	console.log(`할수있다, ${firstName}` );
};
logName("Nana");
  • logName 함수를 호출하면 firstName 의 값이 콘솔 메시지에 추가된다.
  • 코드에 message라는 다른 인수를 추가할 수 있다.
  • 파라미터를 통해 값을 동적으로 전달할 수 있다.
const logName = funtion (firstName, message) {
	console.log(`${firstName}: ${message}
};

logName("Nana", "넌할수있다");

값 반환하기

  • 지금까지는 logName 함수는 값을 콘솔에 남기지만, 실제로는 값을 돌려받기 위해 함수를 호출하는 경우가 더 흔하다.
  • 함수에 return 문 추가하기
  • return 문은 함수가 반환할 값을 지정해준다.
  • 함수이름 createName로 바꾸기
const createName = function(firstName, message) {
	return `${firstName}: ${message}`;
};
createName("Nana", "넌할수있다");
  • 함수가 원하는 대로 작동하는지 확인하고 싶을경우, 함수 호출을 console.log로 둘러싸면 된다.
console.log(createName("Nana", "넌할수있다"));

2.2.3디폴트 파라미터

  • c++ 이나 파이썬과 같은 언어에선느 함수의 인자로 사용할 수 있는 디폴트 값을 선언할 수 있다.
  • ES6 명세에는 디폴트 파라미터 추가 됨.
  • 함수를 호출하면서 인자 값을 지정하지 않으면 디폴트 값이 쓰인다.
function logActivity(name: "nana", activity="basketball") {
	console.log(`${name}${activity}를 좋아한다.`);
}
  • logActivity 함수를 호출하면서 아무인자도 지정하지 않아도 디폴트 값을 사용해 함수가 정상적으로 실행된다. 문자열뿐만 아니라 어떤 타입의 값이라도 디폴트 값으로 사용할 수 있다.
const defaultPerson = {
	name: {
    	first: "nana",
      	last: "lee"
    },
  favActivity: "basketball"
};

function logActivity(p=defaultPerson) {
	console.log(`${p.name.first}${p.favActivity}를 좋아한다.`);
}

2.2.4화살표 함수

  • 화살표 함수는 ES6 새로 추가된 유용한 기능이다.
  • 화살표 함수는 사용하면 function 키워드 없이도 함수르 만들 수 있다.
  • 화살표 함수에서는 return 을 사용하지 않아도 식을 계산한 값이 자동으로 반환된다.,
  • 어떤 사람의 이름 (firstName) 을 인수로 받아서 지역영주로 부르는 문자열로 반환하는 함수
const lordify = function (firstName) {
	return `컨터베리의 ${firstName}`;
}

console.log(lordify("nana"));   // 컨터베리의 nana
console.log(lordify("nana));  	// 컨터베리의 nana 
  • 화살표 함수를 사용하면
const lordify = firstName => `컨터베리의 ${firstName}`;
  • 화살표 (=>) 를 사용하면 한 줄로 모든 함수 정의를 끝낼 수 있다.
  • function 키워드를 없애고, 화살표가 어떤 값을 반환하는지 지정해주기 때문에 return도 없앤다.
  • 장점하나는 함수가 파라미터를 단 하나만 받는 경우 파라미터 주변의 괄호를 생략해도 된다는 것!!

파라미터가 2개 이상이라면 괄호가 필요

// 전형저적인 방식
var lordify = function (firstName, land) {
	return `${land}${firstName}`;
};

// 화살표 함수
var lordify = (firtsName, land) => `${land}${firstName}`;

console.log(lordify("nana", "seoul"));   // 서울의 nana
console.log(lordify("nana", "Switzerland"))  // 스위스의 nana
  • 하지만 결과를 계산하기 위해 여러 줄을 사용해야 한다면 중괄호 함수 본문 자체를 둘러싸야한다.
const lordify = (firstName, land) => {
	if(!firstName) {
    	throw new Error ('lordify에게 이름을 넘겨야 한다.');
    }
  	if(!land) {
      throw new Error('나에게는 내 자신이 있다');
    }
  	return `${land}${firstName}`;
}

console.log(lordify("sena", "New Zealand"));  //  뉴질랜드의 세나
console.log(lordify("Hazel"));    // ! 자바스크립트 오류

=> if/else 문을 중괄호로 둘러싸야만 했지만, 여전히 화살표 함수가 더 짧다

객체 반환하기

Q. 객체를 반환하고 싶으면 어떻게 해야할까?

  • 파라미터로 받은 firstName 과 lastName에 따라 객체를 만들어주는 person 이라는 함수를 생각해 보자.
const person = (firstName, lastName) => {
	first: firstName,
    last: lastName
};

console.log(person("nana", "lee"));
// Error: Uncaught SyntaxError: Unexpected token:" 
  • 이 오류를 고치려면 반환하려는 객체를 괄호를 둘러싸면 된다.
const person = (firstName, lastName) => ({
	first: firstName,
    last: lastName
});

console.log(person("nana", "lee"));
  • 자바스크립트나 리액트 앱에서 괄호를 빼먹어서 오류가 생기는 경우가 아주 많다.
  • 잘 기억해두기!!

화살표 함수의 영역

  • 일반 함수는 this를 새로 바인딩 한다
  • this 는 gangwon 객체가 아니라 그 어떤 것이다.
const gangwon = {
	resorts: ["용평", "평창", "강촌", "강릉", "홍천"],
  	print: fuction(delay=1000) {
	 setTimeout(function(){
     	console.log(this.resorts.join(","));
     }, delay);
	}
};

gangwon.print();   // Cannot read property 'join' of undefined 라는 오류 발생
  • 이 오류는 this.resorts의 join 메서드를 호출하려고 시도했기 때문에 발생했다.

  • this 를 콘솔에 찍으면 this가 window 객체임을 알 수 있다

  • 전역객체(global object)
    -어떤 실행 컨텍스트(Execution Context)에도 속하지 않은 최상위 객체를 말합니다. 브라우저에서는 전역 객체를 window라고 부르고, Node.js 환경에서는 전역 객체를 global이라고 부릅니다.
    - 전역 객체에는 자바스크립트의 기본 내장 객체와 함수, 그리고 사용자 정의 전역 변수 등이 포함됩니다. 예를 들어, Object, Array, setTimeout, console 등의 객체나 함수들은 전역 객체의 프로퍼티로 포함되어 있습니다. 따라서 어떤 스코프에서든 이러한 객체나 함수들을 호출할 수 있습니다.
    - 하지만 전역 변수와 함수는 코드의 가독성과 유지보수성을 떨어뜨리므로, 전역 객체를 가능한 한 사용하지 않는 것이 좋습니다.

console.log(this);   // Window()
  • 이 문제를 해결하기 위해 화살표함수를 사용하면 this 영역이 제대로 유지된다.
var gangwon = {
	resorts: ["용평", "평창", "강촌", "강릉", "홍천"],
  	print: function(delay=1000) {
	 setTimeout(() => {
     	console.log(this.resorts.join(","));
     }, delay);
	}
};

gangwon.print();   // 용평, 평창, 강촌 강릉, 홍천
  • 이 코드는 정상 작동하며 .join을 사용해 리조트 이름을 콤마(,)로 연결할 수 있다.
  • 화살표 함수는 새로운 this 영역을 만들어내지 않는다.
var gangwon = {
	resorts: ["용평", "평창", "강촌", "강릉", "홍천"],
  	print: (delay=1000) => {
	 setTimeout(() => {
     	console.log(this.resorts.join(","));
     }, delay);
	}
};

gangwon.print();   // Cannot read property 'join' of undefined 라는 오류 발생
  • print 프로퍼티를 화살표 함수로 바꾸면 this가 window 객체가 된다는 것을 의미함.

2.3 자바스크립트 컴파일 하기

  • 브라우저에서 코들르 실행하기 전에 더 호환성이 높은 코드로 변환하는 것을 컴파일링 gksek.
  • 가장 유명한 자바스크립트 컴파일링 도구로는 바벨이 있다
    -예를 들어 디폴트 파라미터가 지정된 화살표 함수가 있다면
const add = (x=5, y=10) => console.log(x+y);

이 코드를 바벨로 변환하면

'use stric'

var add = function add() {
var x = arguments.length <= 0 || arguments[0] === undefined ? 5 : arguments[0];
var y = arguments.length <= 1 || arguments[1] === undefined ? 10 : arguments[1];
  return console.log(x+y)
};
  • 바벨은 'use strict' 선언을 맨 위에 추가해서 코드가 엄격한 모드에서 실행되도록 만든다.
  • arguments 배열을 통해 x와 y 파라미터의 디폴트 값을 처리한다.

2.4객체와 배열

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

2.4.1구조 분해를 사용한 대입

  • 구조 분해를 사용하면 객체 안에 있는 필드 값을 원하는 변수에 대입할 수 있다.
  • sandwich 객체에 4개의 필드가 있고, bread, meat 필드의 값이 필요
const sandwich = {
	bread: "더치 크런치",
  	meat: "참치",
  	cheese: "스위스",
  	toppings: ["상추", "토마토", "머스타드"]
};

const {bread, meat} = sandwich;
console.log(bread, meat);   // 더치 크런치 참치
  • sandwich를 분해해서 bread와 meat 필드를 같은 이름의 변수에 넣는다.
  • 두 변수의 값은 sandwich 있는 같은 이름의 필드 값으로 초기화되지만, 두 변수를 변경해도 원래의 필드 값이 바뀌지 않는다.
const sandwich = {
	bread: "더치 크런치",
  	meat: "참치",
  	cheese: "스위스",
  	toppings: ["상추", "토마토", "머스타드"]
};

const {bread, meat} = sandwich;
bread = "마늘";
meat = "칠면조";

console.log(bread);   // 마늘
console.log(meat);	// 칠면조 

console.log(sandwich.bread, sandwich.meat); // 더치 크런치 참치
  • 객체를 분해해서 함수의 인자로 넘길수 있다.
const lordify = reqularPerson => {
	console.log(`컨터베리의  ${reqularPerson.firstname}`);
};

var reqularPerson = {
	firstname: "nana",
  	lattname: "lee"
};

lordify(reqularPerson);  // 컨터베리의 nana
  • 객체의 필드에 접근하기 위헤 점(.) 과 필드 이름을 사용하는 대신 reqularPerson 에서 필요한 값과 구조 분해로 가져올 수 있다.
const lordify = ({firstname}) => {
	console.log(`컨터베리의 ${firstname}`)
};

const reqularPerson = {
	firstname: "naan",
  	lastname: "lee"
};

lordify(reqularPerson); // 컨터베리의 nana
  • 데이터 변경하고 이에 맞춰 한 수준 더 깊이 들어가면 reqularPerson 객체 안에 spouse를 키로 하는 새로운 객체 포함시키기
const reqularPerson = {
	firstname: "naan",
  	lastname: "lee",
  	spouse: {
    	firstname: "sena",
      	lastname: "lee",
    }
};

예명도 컨터베리의 영주로 만들고 함수에 있는 구조 분해 인수를 조정하기

const lordify = ({spouse: {firstname}}) => {
	console.log(`컨터베리의 ${firstname}`);
};
lordify(reqularPerson);  // 컨터베리의 sena 
  • 콜론과 내포된 중괄호를 사용해 firstname을 spouse 객체로부터 구조 분해 할 수 있다.

2.4.2배열 구조 분해하기

  • 배열을 구조 분해해서 값을 뽑아낼수 있다.
  • 배열의 첫번째 원소를 변수에 대입하고 싶은 경우
const [firstAnimal] = ["토끼", "거북이" "코끼리"];
console.log(firstAnimal);  // 토끼
  • 불필요한 값을 콤마(,)를 사용해 생략하는 리스트 매칭을 사용할 수 있다.
  • 변수에 대입하지 않고 무시하고 싶은 원소의 위치에 콤마를 넣으면 리스트 매칭을 사용하는 것이다.
const [,,thirdAnimal] = ["토끼", "거북이" "코끼리"];
console.log(thirdAnimal);  // 토끼

2.4.3객체 리터럴 개선

  • 객체 리터럴 개선은 구조 분해의 반대라 할 수있다.
  • 객체 리터럴 개선은 구조를 다시 만들어내느 과정 또는 내용을 한데 묶는 과정이라고 할 수 있다.
  • 객체 리터럴 개선을 사용하면 현재 영역에 있는 변수를 객체의 필드로 묶을 수 있다.
const name  = "탈락";   // 캘리포니아에 있는 산
const elevation = "9788";  // 고도(단위: 피트)

const funHike = {name, elevation};

console.log(funHike); // {name: "탈락", elevation: 9788}
  • funHike객체에는 name과 elevation이라는 필드가 있다/
  • 객체 리터럴 개선 또는 객체 재구축을 통해 객체 매서드륾 만드는 것도 가능하다.
const name  = "탈락";   // 캘리포니아에 있는 산
const elevation = "9788";
const print = function() {
	console.log(${this.name}산의 높이는 ${this.elevation}피트입니다.)
};

const funHike = {name, elevation, print}

funHike.prinf();  //탈락 산의 높이는 9788 입니다.
  • 객체의 키에 접근하기 위해 this 사용했다
  • 객체 메서드를 정희할 때 더이상 function 키워드르 사용하지 않아도 된다.
// 옛날 방식
var skier = {
	name: name,
  	sound: sound,
  	powderYell: function() {
    	var yell = this.sound.toUpperCase();
      console.log(`${yell} ${yell} ${yell}!!!`)
    },
  speed: function(mph){
  	this.speed = mph;
    console.log('속력(mph):', mph)
  }
}


// 새로운 방식
const skier = {
	name,
  	sound,
  	powderYell() {
  	let yell = this.sound.toUpperCase();
      console.log(`${hell}${hell`${hell}!!!`)
  },
   speed(mph){
  	this.speed = mph;
    console.log('속력(mph):', mph)
  }
}
  • 객체 리터럴 개선을 통해 현재 영역에서 볼 수있는 변수들을 객체의 필드에 대입할 수 있으면 function 키워드를 입력하지않아도 되기 때문에 타이핑 해야 할 양이 줄어든다.

2.4.4스프레드 연산자

  • 스프레드 연산자는 3개의 점(...)으로 이뤄진 연산자로 몇 가지 다른 역할을 담담한다.
  • 첫째로, 연산자를 사용해 배열의 내용을 조합할 수 있다.
  • 예) 두 배열이 있다면 두 배열의 모든 원소가 들어간 세번째 배열을 만들 수 있다.
const peaks = ["대청봉", "중청봉", "소청봉"];
const canyons = ["천불동계곡","가아동계곡"];
const seoraksan = ["...peaks, ...canyons"]

console.log(seoraksan.join(', '));  // 대청봉, 중청봉, 소청봉, 천불동계곡, 가야동 계곡
  • peaks와 canyons에 포함된 모든 원소가 seoraksan 이라는 새별에 들어간다.
  • peaks배열에 마지막 원솔르 변수에 담고자 한다면
  • Array.reverse 메서드를 사용해 배열을 뒤집고 구조 분해를 사용해 첫 번째 원소를 변수에 넣으면 될것 같다.
const peaks = ["대청봉", "중청봉", "소청봉"];
const [last] = peaks.reverse();

console.log(last);  //소청봉
console.log(seoraksan.join(', ')); //소청봉, 중청봉, 대청봉

Q. 문제점을 알 수 있는가?

  • 실제 revers 메서드는 원래의 배열을 변경한다.
  • 스프레드연산을 사용하면 원본 배열을 뒤집지 않고 복사본을 만들어서 뒤집을 수 있다.
const peaks = ["대청봉", "중청봉", "소청봉"];
const [last] = [...peaks].reverse();

console.log(last);		// 소청봉
console.log(peaks.join('. '));  // 대청봉, 중청봉, 소청봉
  • 스프레드 연산자를 사용해 배열의 원소들을 복사했기 때문에 원본인 peaks 변경되지 않고 그대로 남게 된다.
  • 나중에 필요할때 다시 사용할 수있다.
  • 스프레드 연사자를 사용햇 배열의 나머지 원소들을 얻을 수있다.
const lakes = ["경포호", "화진포", "송지호", "청조호"]
const [first, ...rest] = lakes;
console.log(first) ; // 경포호
console.log(res.joim(', '));  // 화진포,송지호, 청초호

  • 세점(...) 구문을 사용해 함수의 인자를 배열로 모을 수있다.
  • 스프레드 연산자가 쓰일 때는 레스트 파라미터 라고 부른다
  • n개으 인자를 스프레드 연산자를 사용해 배열로 모은 다음에, 그 배열을 사용해 여러 가지 내용을 콘솔 메시지를 찍는 함수 보여준다.
function directions(...args) {
	let [start, ...remaining] = args;
  	let [finish, ...stops] = reamining.rerverse();
  
  console.log(`${args.length}도시를 운행합니다.`)
  console.log(`${start}에서 출발합니다.`)
  console.log(`목적지는${finish}입니다.`)
  console.log(`중간에 ${stops.length}군데를 들립니다.`);
  
}

directions(
	"서울",
  	"수원",
  	"천안",
  	"대전",
  	"대구",
  	"부산"
);
  • direction 함수는 스프레드 연사자를 사용해 인자를 받는다.
  • 첫번째 인자는 start 변수에 대입된다.
  • 마지막 인자는 finish 변수에 Array.reverse 통해 대입된다.
  • args 배열하는 도시의 수 args배열에서 2(출발지와 도착지)를 뺀 것이다.
  • directions 함수에 임의의 개수의 경유 도시를 넘길 수 있기 때문에 이런 기능이 매우 유용하다.
const morning = {
	breakfast: "미역국",
  	lunch: "삼치구이와 보리밥"
};

const dinner = "스테이크 정식";
const backpackingMeals ={
	...moring,
	dinner  	
};

console.log(backpackingMeals);
// {breakfast: "미역국", lunch:"삼치구이와 보리밥", dinner:"스테이크 정식"}

2.5 비동기 자바스크립트

  • 모두 예제는 동기적임
  • 자바스크립트 코드를 작성할때는 일련의 명령이 순서대로 실행된다.
const header = documnet.getElementById("heading");
header.innerHTML = "Hey!"
  • 해석하자면, id가 heading 인 엘리먼트를 찾아와! 그리고 그 엘리머먼트를 찾으면 내부 HTML에 Hey!라는 문자열을 넣으면 어때?

2.5.1단순한 프라미스와 fetch

  • REST API로부터 간단한 데이터 앱이 받아오려면 20줄 이 넘는 코드 작성해야만 한다.
  • randomuser.me API로부터 데이터를 가져오자.
  • 전자우편, 주소, 전화번호, 집주소 등 정보가 들어 있으며, 그런 데이터를 더미로 활용하기 좋다.
  • fetch는 유일한 데이터를 받아로 URL 을 받는다.
console.log(fetch("https://api.randomuser.me/?nat=US&results=1"));
  • 콘솔로그를 보면 대기중(pending)인 프라미스(promise) 를 볼 수 있다.
  • 프라미스는 자바스크립트에서 비동기적으로 동작을 잘 처리해준다.
  • 대기중인 프라미스는 데이터가 도착하기 전의 상태를 표현한다.
  • .then() 이라는 함수를 대기중인 프라미스에 연쇄 호출해야한다.
  • 이 함수는 콜백 함수를 인수로 받으며, 바로 앞에 있는 연산 (프라미스) 이 성공하면 콜백이 호출된다.
  • fetch()는 데이터를 받아오고, .then() 은 데이터가 도착하면 그 데이터를 가지고 다른 일을 한다.

JSOM으로 바꾸기

fetch("https://api.randomuser.me/?nat=US&result=1").then(res => console.log(res.json))
);
  • then은 프라미스가 정상적으로 완료되면 콜백 함수를 한 번만 호출한다. 이 콜백 함수가 반환하는 값은 그 다음에 오는 then 함수의 콜백에 전달되는 인자가 된다. 따라서 성공적으로 처리된 프라미스를 처리하기 위해 then 함수를 연쇄적으로 호출할 수 있다.
fetch("https://api.randomuser.me/?nat=US&result=1")
.then(res=> res.json())
.then(json => json.results)
.then(console.log)
.catch(console.error);
  • fetch를 호출해 randomuser.me 에 대한 GET 요청을 보낸다. 요청이 성공하면 응답 본문을 JSON 으로 변환한다.
  • JSON 데이터 중에서 resulet 를 얻는다.
  • 콘솔에 results 값을 출력한다.
  • catch함순느 fetch 가 성공하지 못한 경우 콜백을 호출한다.
  • console.error 를 사용해 그냥 오류를 콘솔에 출력

2.5.2 async / await

  • 비동기 프라미스를 처리하는 다른방법으로 ascync 함수를 만드는 방법
  • async 함수는 프라미스 다음에 있ㄴ는 코드를 실행하기 전에 프라미스가 끝날 때까지 기다리라고 명령 할 수 있다.
const getFakePerson = async () => {
	let res = await fetch('https://api.reandomuser.me/?nat=US&results=1');
  	let { results } = res.json();
  	console.log(results);
};

getFakePerson();
  • getFakePerson 함수 앞에 async 라는 키워드가 있다는 점에 유의하자.
  • getFakePerson 함수를 비동기 함수로 만들어준다.
  • 프라미스가 완료 될 때까지 기다릴 수 있다.
  • 프라미스 호출 앞에 await 키워드를 붙이면, 프라미스가 완료될때까지 기다렸다가 함수가 진행이 된다.
  • then 함수를 사용하는 코드와 완전히 똑같은 일을 한다.

const getFakePerson = async () => {
	try {
    	let res= await fetch('https://api.randomuser.me/?nat=US&results=1');
      	let { results } = res.json();
      	console.log(results);
    } catch (error) {
    	console.error(error);
    }
};
getFakePerson();
  • 앞에서 본 then 을 사용한 코드와 완전히 같은 일을 한다.
  • fetch 호출이 성공하면 결과를 콘솔 로그에 남긴다.
  • 실패하면 console.error 를 사용해 오류를 콘솔에 남긴다.
  • async와 await을 사용할 때는 프라미스 호출 주변을 try...catch 블록으로 둘러싸서 정상적으로 완료되지 않은 프라미스에서 발생한 오류를 처리할 필요가 있다.

###2.5.3 프라미스 만들기

  • 비동기 요청을 하면 발생할 수 있는 경우 2가지다.
  • 모든일 원하는 대로 잘 풀리거단, 오류가 생길 수 있다.
  • 요청 성공이나 실패에 다양한 유형이 있다.
  • 예를 들어 성공할 때까지 여러번 다른 방법으로 데이터를 가져오려고 시도할 수있다.
  • 여러 유형의 오류를 받을 수도 있다.
  • 프라미스를 사용하면 간단하게 비동기 작업의 성공이나 실패를 돌려줄 수 있다.

  • getPeopel 함수는 새로운 프라미스를 반환한다.
  • 프라미스는 API요청을 보낸다.
  • 프라미스가 성공하면 데이터를 읽어온다.
  • 프라미스가 성공하지 않으면 오류를 발생시킨다.
const getPeople = count =>
	new Promise((resolves, rejects) => {
    	const api = `htpps://api.randomuser.me/?nat=US&results=${count}`;
      	const request = new XMLGttpReques();
      	request.open("GET", api);
      	reqeust.onload = () => 
        	request.status === 200
      		? resolves(JSON.parse(request.response),.results)			: reject(Error(request.statusText));
      request.onerror = err => rejects(err);
      request.send();
    });
  • 아직 프라미스가 작동하지 않는다.
  • getpeople 함수를 호출하면서 원하는 회원수를 전달하면 프라미스를 만들 수 있다.
  • then 함수를 연쇄시켜서 프라미스가 완료되면 원하는 일을 할 수 있다.
  • 프라미스 실패하면 자세한 정보가 catch 함수에 전달한 콜백에게 전달한다.
  • asycn/await 구문을 사용하면 catch 블록으로 오류정보가 전달된다.
getPeople(5)
	.then(members => console.log(members))
	.then(error => console.log(`getPeople failed: ${error.message}`));
  • 프라마스를 사용하면 비동기 요청을 쉽게 처리할 수있다.
  • 자바스크립트에서는 비동기 처리를 할 일이 많고 비동기 동작에 대해 잘 이해해야만 한다.

2.6 클래스

  • ES2015 이전에는 공식적으로 자바스크립트 명세에 클래스 문법이 없었다.
  • 자바스크립트는 프로토타입을 사용한 상속이라고 불리는 방법이다.
  • 객체지향처럼 느껴지는 구조를 만들어내기 위한 기법이다.
  • 예를 들어 new를 사용해 호출해야하는 Vacation 생성자를 다음과 같이 정의할 수 있다.
function Vacation(destination, length) {
	this.destination = destination;
  	this.lengh = length;
}
Vacation.prototype.print = function() {
	console.log(this.destination + "은(는) " + this.length + " 일 걸립니다.");
};

const maui = new Vacation("마우이", 7);

maui.print();  // 마우이은(는) 7일 걸립니다.
  • 이 코드는 객체지향 언어의 커스텀 타입과 비슷한 느낌의 물건을 만들어낸다.
  • Vacaiton에는 프로퍼티(destionation, length)들과 메서드(print) 가 있다.
  • maui 인스턴스는 프로토타입을 통해 print 메서드를 상속받는다.
  • ES2015에는 클래스 선언이 추가됐다.
  • 함수는 객체이면 상속은 프로토타입을 통해 처리된다.
  • class는 단지 이 기가 막힌 프로토타입 구문에 대한 구문적 편의를 제공할 뿐이다.
class Vacation {
  	constructor(destination, length) {
    	this.destination = destination;
  		this.lengh = length;
    }
  print () {
  	console.log(`${this.destination}() ${this.length}일 걸립니다.");
  }
}
  • 클래스를 만들 때는 보통 클래스 이름의 첫 글자를 대문자로 표시한다.
  • 클래스를 만들고 나면 new 키워드를 사용해 해당 클래스의 새로운 인스턴스를 만들수 있다.
  • 인스턴스의 메서드를 호출 할 수 있다.
  • 클래스 객체를 만들고 나면 새로운 객체를 생성하기 위해 원하는 만큼 new를 호출 할 수 있다.
  • 클래를 확장도 할 수 있다.
  • 기존의 클래스 (부모 또는 상위 클래스)를 확장한 새로운 클래스 (자식 또는 하위 클래스)는 상위 클래스의 모든 프로퍼티와메서드를 상속한다.
  • 상속한 메서드나 프로퍼티를 하위 클래스 선언 안에서 변경할 수도 있다.
  • 디폴트로 모든 메서드와 프로퍼티가 상속될 것이다.

  • Vacation을 여러가지 휴가 타입을 정의하기 위한 추상 클래스로 사용할 수있다.
  • 예를 들어 Expedition은 Vaction 클래스를 확장하되 장비를 표현하는 프로퍼티(gear)를 포함한다.
class Expedition extends Vaction {
	construcor (destination, length, gear) {
    	super(destination, length);
      	this.gear = gear;
    }
  print() {
  	super.print();
   	console.log(`당신의 ${this.gear.join("와(과) 당신의 ")}를(을) 가져오십시오`)
    
  }
}
  • 간단한 상속관계를 볼 수 있다.
  • 하위 클래스는 상위 클래스의 프로퍼티를 상속한다.
  • print() 에서는 상위 클래스에 있는 print()를 호출한 다음에 Expedition에 있는 추가 정보를 출력했다.
  • 상속을 사용해 만든 하위 클래스의 인스턴스를 만들 때도 상위클래스의 인스턴스를 생성할 때와 마찬가지로 new 키워드로 사용한다.
const trip2 = new Expedition("한라산", 3, ["선글라스, "오색깃발", "카메라"]);
                                        trip2.print();

// 한라산은(는) 3일 걸립니다.
// 당신의 선글라스와 (과) 당신의 오색 깃발과 당신의 카메라를 가져오십시오.

2.7 ES6 모듈

  • 자바스크립트 모듈은 다른 자바스크립트 파일에서 이름 충돌이 없이 쉽게 불러서 활용할 수 있는 재사용 가능한 코드 조각을 말한다.
  • 자바스크립트 모듈은 한 모듈당 하나씩 별도의 파일로 저장한다.
  • 모듈을 만들고 외부에 익스포트하는 방법에는 한 모듈에서 여러 자바스크립트 객체를 외부에 노출시키는 방식과 한 모듈에 하나의 자바스크립트 객체를 노출시키는 방식이 있다.

text-helper.js 파일에 있는 다음 모듈은 두 함수를 외부에 노출시킨다.

export const print(message) => log(message, new Date());
export const log(message, timestamp) => 
	console.log(`${timestamp.toString()}: ${message}`)
  • export를 사용해 다른 모듈에서 활용할도록 이름(함수, 객체 변수, 상수 등이 될 수 있다)을 외부에 익스포트할 수 있다.
  • print함수와 log함수를 외부에 익스포트하는 중이다.
  • text-helper.js 정의된 다른 선언들은 이 모듈 내부에만 한정된다.
  • 경우에 따라 모듈에서 단 하나의 이름만을 외부에 익스포트하고 싶을 때가 있다.
  • 그런 경우 export default 를 사용할 수 있다.
  • mt-freel.js 파일은 구체적인 탐험 계획을 외부에 노출시킨다.
const freel = new Expedition("프릴 산", 2, ["식수", "간식"]);
export default freel;
  • export default는 오직 하나의 이름만을 노출하는 모듈에서 export대신 사용할 수 있다.
  • export나 export default 에서의 기본 타입, 객체, 배열, 함수 등 모든 타입의 자바스크립트 이름을 외부테 노출시킬 수 있다.
  • import 명령을 사용해 다른 자바스크립트 파일에 있는 모듈을 불러와 사용할 수 있다.
  • 외부에 여러 이름을 노출한 모듈을 임포트할 때는 객체 구조 분해를 활용 할 수 있다.
  • export default를 사용해 한 이름만 노출한 경우에는 노출된 대상을 한 이름으로 부를 수 있다.
import {print, log} from './text-helpers';
import freel from './mt-freel';

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

freel.print();

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

import { print as p, log as }  from './text-helpers';
        
        p('메시지를 print');
        l('메시지를 log');
  • import * 를 사용하면 다른 모듈에서 가져온 모든 이름을 사용자가 정한 로컬 이름 공간 안에 가둘 수있다.
import * as fns from './text-helpers';
  • 모든 브라우저나 노드가 import나 export구문을 완전히 지원하지는 못한다.
  • 최신 자바스크립트 문법과 마찬가지로 바벨은 import와 export를 지원한다.
  • 소스 코드에서 이런 문장을 사용하면 바벨이 어떤 파일에서 모듈을 찾아서 포함시켜야 할지 모를수 있다.

2.7.1 커먼JS

  • 커먼는 모든 버전의 노드에서 지원하는 일반적인 모듈 패턴이다.
  • 이런 방식의 모듈을 바벨이나 웹팩이나 사용할 수 있다.
  • 커먼 JS를 사용하면 module.exports를 사용해 자바스크립트 객체를 익스포트 할 수 있다.
  • 예를 들어 커먼JS에서 print와 log 함수를 객체로 반환 할 수 있다.

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

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

module.exports = {print, log};
  • 커먼 JS 는 import문 지원하지 않는다.
  • 그 대신 require 함수를 통해 모듈을 임포트 할 수 있다/
const { log, print } = require('./text-heplers')
  • 최신 자바스크립트 문법에 포함된 기능 대부분은 함수형 프로그래밍 기법을 지원하기 윈한 것이다.
  • 함수형 자바스크립트에서는 여러 함수를 모아둔 것으로 코드를 생각하과, 그런 함수를 서로 합성해서 애플리케이션을 구축한다.

[Reference]
1. Learning React(Alex Banks/Eve Porcello/오현석/한빛미디어_2021)

profile
실수를 두려워 말고 계속 도전 하는 개발자의 여정!

0개의 댓글