ES6 💖

SOO·2022년 11월 12일

basic

목록 보기
10/16

var, const, let

let과 const전에 우리가 사용했던 건 var임.

var은 변수 중복 선언 가능.
변수 선언문 이전에 변수를 참조하면 언제나 undefined를 반환함.
선언과 초기화를 동시에 진행.

variable이 변하는 걸 막기 위해 어떤 메커니즘이 있어야함 -> const

const가 값을 다시 정의할 수 없게끔 해줌. 변수 중복 선언 불가.

let은 값 변경 가능(재할당 가능). 변수 중복 선언 불가.

선언과 초기화가 분리되어 진행

Dead Zone

hoisting은 JS가 프로그램을 실행하기 전에 이것들을 어딘가로 이동시킨다는거임
(무조건 위에서 아래로 실행된다는게 아님)

함수는 아래쪽에 선언했지만 그 위에 호출을 해도 함수가 실행된다. 이는 JS는 필요한 모든 변수를 유효 범위의 최상단으로 끌어와서 선언을 하게 되기 때문이다.
이것이 호이스팅이다.

console.log(myName); 
var myName = 'soo'

var은 에러 없이 나옴

안에서 일어나는 일

var myName;
console.log(myName);
myName="soo";

hoisted의 뜻은 프로그램이 시작되면 그들이 제일 위로 가는걸 말함.
이건 별로 좋지 않음. 실제로 error를 내야되기 때문에.

console.log(myName)
let myName = "soo";

myName is not defined error.
error가 나는 이유는 JS가 여기서 hoisting이란 걸 해주기 때문.

JS는 hoist하지 않게 되고, 그 말은 top으로 끌어올리지 않는다는 말이고, 정의하지 않았는데 let에 접근하려고 하면 error가 나게 되는거임. 이건 좋은것!
js가 우리가 바보같은 짓 하는걸 허락하지 않는거지

let은 var과 다르게 선언과 초기화가 분리되어 진행되기 때문.

Block Scope

(let과 const의 장점 중 하나)

scope는 기본적으로 버블({}). 이 버블이 variable들이 접근 가능한지 아닌지를 감지해줌.

block scope는 그 블록안에서만 존재한다는 것. 이 블록안에서 선언하면 외부로 나가진 않음.

if (true) {
  let hello = "hi";
}
let hello = "bye";
console.log(hello);

bye가 나옴

let hello = "hi";
if (true) {
  console.log(hello);
  const a = "a";
}
console.log(a);

hi
a is not defined.
외부에서 안으로는 불가!

var은 block scope를 가지지 않고, function scope를 가지고 있음. function scope의 뜻은 var가 function 안에서 접근할 수 있다는 뜻임.
funciton을 만들고 그 안에 var을 넣으면 그 외부에선 접근 ㄴ.

function name () { var soo= "a";};
undefined
console.log(soo);

결과: Uncaught ReferenceError: soo is not defined
at :1:13

Functions

Arrow Functions

arrow function은 js에서 함수의 모습을 개선한거임

const hearts = names.map(function(item) {return item+ "💛";});

이런식으로

const hearts = names.map((item)=>{return item+ "💛";}); 

또 이런식으로

consnt hearts = names.map(item=>item+"💛");

this is Arrow Functions

const button ~
button.addEventListenr ~

이벤트 리스너를 붙이고 이벤트 리스너에 function이 있으면 JS는 우리가 클릭한 버튼을 this keyword에 넣음

arrow function은 this를 이벤트로부터 가지고 있지 않음.
arrow function은 this를 window object로 가지고 있어!

만약에 this를 사용하고 싶다면 function을 사용해야함!

const soo = {name:"Soo", age:23, addYear:()=> {this.age++;}};
console.log(soo);
soo.addYear();
soo.addYear();
console.log(soo);

이러면 결과가 name:"Soo", age:23 나옴. 두 번다!

근데 여기 addYear(){this.age++;}만 바꿔준다면 !!

const soo = {name:"Soo", age:23, addYear(){this.age++;}};
console.log(soo);
soo.addYear();
soo.addYear();
console.log(soo);

23, 25으로 나옴!

Arrow Functions in the Real World

const emails = ["nco@no.com","naver@nadk.com","lydnd@gmail.com"]

Array.prototype.find는 제공되는 테스트 조건을 만족하는 첫번째 엘리먼트 값을 리턴하는 함수!

const foundMail = email.find(item => item.includes("@gmail.com"))
console.log(foundMail);

filter 메소드는 제공된 함수의 조건을 만족한 모든 엘리먼트로 새로운 array를 만들어.

const noGmail = emails.filter(potato => !potato.includes("@gmail"));
console.log(noGmail);

Array.prototype.forEach()

emails.forEach(email => {console.log(email.split("@")[0]);});

nco, naver, lydnd가 나옴!

{} 이거는 implicit return을 못쓰게 만들어, 근데 ()을 같이쓰면 object도 가능해짐

object를 return 하고 싶을 때

const cleaned = emails.map((email, index) => ({username:email.split("@")[0], index}));

console.log(cleaned);

화살표 함수와 일반 함수의 차이

Default Values

const sayHi = (aName = "anion") => "hello" + aName;
console.log(sayHi());

Strings

Template Literals

const wrapper =document.querySelector(".wrapper");
const friends = ["me","lynn","dal","mark"];
const list = `<h1>People i love</h1>
<ul>${friends.map(friend=>`<li>${friend}❤</li>`).join("")}</ul>`;
wrapper.innerHTML = list;

Cloning Styled Components

const styled = aElement => {const el = document.createElement(aElement);
return args=>{
	const styles = args[0];
    el.style = styles;
    return el;
    };
  };
  
const title = styled("hi")`background-color:red; color:blue;`

More String Improvements!

String.prototype.includes()

const isEmail = email => email.includes("@");
console.log(isEmail("soo@naver.co"));

-> true

String.prototype.repeat()

const CC_NUMBER = "6060";
const displayName =`${"*".repeat(10)}${CC_NUMBER}`;
console.log(displayName);

String.prototype.starts/endsWith()

const name = "Mr.jin";
console.log(name.startsWith("Mr"));

Array

Array.from() and Array.of()

Array.of는 어떤 걸 array를 만들고 싶을 때 사용해

const friends = Array.of("soo","jin","jieun");
console.loge(friends);
[soo, jin, jieun]

array-like object를 만나게 되면 array로 바꾸기!

const buttons = document.getElementsByClassName("btn");

-> buttons는 array-like object임

Array.from(buttons).forEach(button => {button.addEventListenr("click",() =>console.log("I ve been clicked") });

Array.find() Array.findIndex() Array.fill()

Array.find()

const friends = ["soo@gmail.com","soo@naver.com"];

const target = friends.find(friend => friend.includes("@gmail.com"));
console.log(target);

-> soo@gmail.com

const friends = ["soo@gmail.com","soo@naver.com"];

const target = friends.find(friend => true);
console.log(target);

true를 하면 찾은 것 중 첫번째 element를 알려줌

const friends = ["soo@gmail.com","soo@naver.com", "aubepluieh3@naver.com"];

const check = () => friends.findIndex((friend)=>friend.includes("naver.com"));
let target = check();

if(target !== -1){
console.log(target);
const username = friends[target].split("@")[0];
const email = "korea.com";
friends[target] = `${username}@${email}`;
target=check();}
console.log(friends);

->

(3) ['soo@gmail.com', 'soo@korea.com', 'aubepluieh3@naver.com']
const friends = ["soo@gmail.com","soo@naver.com", "aubepluieh3@naver.com"];

const check2 = () => friends.findIndex((friend) => friend.includes("fill"));
target = check2();

if (target !== -1) {
friends.fill("*".repeat(5), target);
}
console.log(friends); -> (3) ['soo@gmail.com', 'soo@naver.com', 'aubepluieh3@naver.com']

friends.fill("*".repeat("5"), 1, 3);
console.log(friends); -> (3) ['soo@gmail.com', '*****', '*****']

console.log(friends.includes("sjdkd@gmail.com"));

Object Destructuring

destructuring은 object나 array, 그 외 요소들 안의 변수를 바깥으로 끄집어 내서 사용할 수 있도록 하는거임!

const settings = {
	notifications:{
    	follow:true,
        alerts:true,
        unfollow:false
    },
    color:{
    	theme:"dark"
    }
};

if(settings.notifications.follow){

}
if(settings.notifications.follow){

}

대신 변수를 하나 만들어서 destructuring을 적용할거임

const {follow} = settings;

이렇게 follow에 도달할 수 없어!

const {notifications} = settings;

먼저 notifications로 접근하고, 그리고 notifications 안에 있는 follow로 접근할 수 있음

const {notifications:{follow}} = settings;

기본적으로 이 부분은 notifications 안으로 접근하고, 그건 settings안에 있는데. follow만을 가져오는거지!

만약 우리가 color 값을 가져오고 싶다면 theme이 아니라 color 값을 통채로 가져오고 싶을 때는

const {notifications:{follow}, color} = settings;

console.log(color);

그러니까 이런 방식은 큰 오브젝트에서 특정 변수나 그 안에 속한 작은 오브젝트에 접근할 수 있도록 해주는거야

다시 돌아가서

const {notifications} = settings;

const 변수를 생성하는거지! {notifications} 이 자체가 const 변수야
그치만 여깄는거랑 같은 이름인거지!

const {notifications :{follow}} = settings;

settings의 notifications의 notifications안에 follow 인거지
여기에서는 notifications를 변수로써 가져오는게 아니야
이건 notifications안에 있는 follow라는 값을 변수로 만드는거임

const {notifications:{follow = false }} = settings;

settings 안에 notifications로 가서 follow가 있는지 찾아본 다음에 follow가 없다면 follow = false라고 선언해주겠다는거지.

만약 notifications가 없을 경우

const {notifications: {follow = false} = {}} = settings;

settings 안을 보고 notifications 안으로 가서 follow 값을 찾는거지
만약 follow가 없으면, follow=false가 되는거임

ex) let setting = { color: 'blue', name: 'soo'};
let color:
({color} = setting)
color='pink'
console.log(color) -> pink

Array Destructuring

*잘 안씀

가져온 정보를 조작하지 않을 때 쓰기 좋아

API로부터 응답받은 데이터가 있다고 가정하구, 그리고 그 데이터를 array 형태로 만들어야 하는 상황이라면 그럴 때 array destructuring을 사용하면 좋을 것 같아.
가져온 데이터를 조작할 필요는 없을 때 말이지.
이걸 조작하고 싶다면 object을 쓰는게 좋구

const days = ["Mon", "Tue", "Wed", "Thu", "Fir", "Sat", "Sun"]

앞에 세개만 가져오고 싶을 때

const [mon, tue, wed]= days;
console.log(mon,tue,wed);

이런식으로 기본값을 설정할 수도 있음

const days = ["Mon", "Tue", "Wed"];
const [mon, tue, wed, thu = "Thu"] = days;
console.log(mon, tue, wed, thu);

함수에도 쓸 수 있음

const days = () => ["Mon", "Tue", "Wed"]

const[mon,tue,wed,thu]=days();

console.log(mon,tue,wed,thu);

Renaming

const settings = {color: chosen_color:"dark"};

const {color:{chosen_color = "light"}} = settings;

console.log(chosen_color);

settings 데이터를 api로부터 받았다고 해보자

api한테서 이런 데이터가 들어왔는데 api가 파이썬이든 뭐든 암튼 js는 아닌데 이상한 이름으로 된 데이터를 받게 된거임

그럼 이름을 바꿔주고 싶고, 그럴 때 해주는 것이 rename이야.

그렇지만 이름 바꾸자고 destructuring을 포기하긴 싫잖아

그냥 chosen_color 같은 형태의 변수명을 쓰고 싶지 않은 것 뿐!

const chosenColor = settings.color.chosen_color || "light";

이렇게 할 수 있겠지만 별루임

const {color:{chosen_color:chosenColor = "light"}} = settings;

console.log(chosenColor);

이렇게 하면 됨! 변수명을 chosenColor로 바꿔주고 default 값을 light로 설정해준거임!

새 변수 생성대신 업데이트하는 방법

const settings = {color: chosen_color:"dark"};
let chosenColor = "blue";
({color:{chosen_color:chosenColor="light"}}=settings);
console.log(chosenColor);

Function Destructuring

유저 세팅을 저장하는 함수라 하고 saveSettings라고 할거임

function saveSettings(followAlert, unfollowAlert, mrkAlert, themeColor){
}

일케하면 너무 길다

function saveSettings(settings){
console.log(settings);
}

saveSettings({
	follow:true,
    alert:true,
    mkt:true,
	color:"green"
})

일케하면 함수를 호출할 때는 좋은데 함수를 작성할 때는 안좋다.

변수들의 가독성을 확보하면서, 각 변수의 기본값을 설정하고 싶다.
그렇게 하기 위해서 object destructuring을 사용할거임.

function saveSettings({notifications, color : {theme}}){
console.log(theme);};

saveSettings({
	notifications : {
		follow : true,
		alert : true,
		mkt : false
		},
	color : {
		theme: "blue"
	}
});

Value Shorthands

변수 이름을 똑같이 하고 싶다면 shorthand property(단축속성명)을 사용할 수 있음

shorthand property는 여기 쓸데없이 반복되는 부분을 안써도 되게 해주는거임

const follow = checkFollow();
const alert = checkAlert();

const settings = {
notifications: {
follow,
alert:alert,
},
};

두번재 alert는 위에 있는 alert 변수에 해당,
첫번째 alert는 object의 key 값에 해당

key이름이랑 변수명이랑 같다는 뜻

alert만 쓰면 ㅇㅋ

Swapping and Skipping

variable Swapping

let mon = "Sat";
let sat = "Mon";

우리가 원하는건 swap

잘못된 변수들을 이용하여 새로운 array 만들기
[sat, mon] = [mon, sat]

즉 [sat, mon] = ["Sat", "Mon"];이 되는거임

Skipping

const days = ["mon", "tue", "wed", "thu", "fri"];

뒤에 두부분만 가지고 오고 싶으면

const [, , , thu, fri] = days;
console.log(thu, fri); -> thu, fri

console.log(mon) -> error!

REST AND SPREAD

Introduction to Spread

spread는 기본적으로 변수를 가져와서 풀어 해치고 전개하는거임

const friends = [1,2,3,4];
console.log(...friends);

spread를 사용하기 위해서는 friends array안의 1, 2, 3, 4 값을 풀어 헤칠거임

console.log(friends); -> [1,2,3,4]
console.log(...friends); -> 1 2 3 4

이 차이를 알아야함!

const friends = [1,2,3,4]
const family = ["a","b","c"];

console.log([...friends, ...family]);

이 array들 안에 있는 요소들을 원하는거임!
새로고침하면 모든 요소를 담고있는 하나의 array를 얻을 수 있음
-> [1,2,3,4,"a","b","c"]

만약에 console.log([friends,family]);
이렇게 하면 [Array(4), Array(3)]이 나옴!

const person = {name:"soo", age:23};
const hello = {person:true, hello:"hello"};

console.log({...person, ...hello});

-> {name: 'soo', age: 23, person: true, hello: 'hello'}

각각의 object가 포함하고 있는 데이터가, 하나의 object안에 들어가는거지

spread는 변수를 가져가서 풀어해친다!

Spread Applications

기존 데이터를 복사해서 새로운 데이터를 만들고 싶을 때 사용할 수 있는 방법

const friends = ["soo", "hyun"];
const newFriends = ["Park", ...friends];
console.log(newFriends);

-> ['Park', 'soo', 'hyun']

const soo = {username:"soo"};
console.log({...soo, password:"123"});

-> {username: 'soo', password: '123'}

const first = ["mon", "tue", "wed"];
const weekend = ["sat", "sun"];
const fullweek = [...first, "thu", "fri", ...weekend];
console.log(fullweek);

->  ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

const lastName = prompt("Last name : ");
const user = {
username: "soo",
age: 23,
// lastName: lastName !== "" ? lastName : undefined,
...(lastName !== "" && { lastName }),
};

console.log(user);

Park 입력시
{username: 'soo', age: 23, lastName: 'Park'}

아무것도 입력 안할 시
{username: 'soo', age: 23}

Intro to Rest Parameters

parameter라는 건 우리가 함수에게 전달하는 인자들을 이야기 하는거임
그러면 rest parameter?
rest는 모든 값을 하나의 변수로 축소시켜주는거임

const bestFriendMaker = (firstOne, ...rest) => {console.log(`my best friend is ${firstOne}`);
console.log(rest);
};

bestFriendMaker("soo","hyun","dall","guy");

-> 결과

my best friend is soo
['hyun', 'dall', 'guy']

rest는 array를 만들어!

const bestFriendMaker = (first,Second, ...potato) => {console.log(`my best friend is ${first}`);
console.log(potato);
};

bestFriendMaker("soo","hyun","dall","guy");

-> 결과 my best friend is soo
['dall', 'guy']

Rest + Spread + Destructure Magic

const user = {name:"soo", age:"23", password:12345};
const killPassword = ({password, ...rest}) => rest;
const cleanUser = killPassword(user);
console.log(cleanUser);

-> {name: 'soo', age: '23'}

destructuring은 object를 열어서{} 우리가 원하는 것만 골라서 가져오는거임
여기에서는 destructuring을 rest operator하고 함께 사용한거지

const setCountry = ({ country = "KR", ...rest }) => ({ country, ...rest });
console.log(setCountry(user));

-> {country: 'KR', name: 'soo', age: '23', password: 12345}

country 값을 가져오고 없다면 default 값으로 "KR"을 가져오고 그리고 나서 RESET 구문을 이용해서 입력 인자의 나머지 값들을 하나로 축소했고, 그리고 나서 country와 함께 나머지 값을 담고 있는 rest 변수를 전개하여 return 해준거!

const rename = ({ name: newname, ...rest }) => ({ newname, ...rest });
console.log(rename(user));

-> {newname: 'soo', age: '23', password: 12345}

For of Loof

forEach는 배열에 있는 각각의 엘리먼트에 대해 특정한 액션을 실행함
그러니까 나는 특정한 액션을 선언하고, 각각의 엘리먼트들에게 실행할 수 있는거임

forEach는 addHear를 호출하는데, current item과 함께 호출할거임!
current item가 함수의 첫 번째 인자가 될거임!

const friends = ["soo", "hyun", "ha", "hu"];
const addHeart = c => console.log(c);
friends.forEach(addHeart);

soo
hyun
ha
hu

그리고 forEach는 current item말고 index를 붙여서 함수를 호출할 수 있음

const friends = ["soo", "hyun", "ha", "hu"];
const addHeart = (c, i, a) => console.log(c, i, a);
friends.forEach(addHeart);

current item, index, current array

결과

soo 0 (4) ['soo', 'hyun', 'ha', 'hu']
hyun 1 (4) ['soo', 'hyun', 'ha', 'hu']
ha 2 (4) ['soo', 'hyun', 'ha', 'hu']
hu 3 (4) ['soo', 'hyun', 'ha', 'hu']

const friends = ["soo", "hyun", "ha", "hu"];
for (const friend of friends){console.log(friend);}

먼저 for문에서 const로 선언할 지, let로 선언할 지 선택할 수 있다.

for of는 array에서만 동작하는 것이 아니라, iterable한 모든 것에서 동작해.

iterable 하다는 것은 루프가 가능하다는 뜻

for each는 array에서만 동작 가능

for of는 루프를 멈출 수 있음

for(const friend of friends) {
	if(friend === "ha"){
    break;
    }else{
    console.log(friend)}
}

-> soo hyun

Promises

Introduction to Async

JS는 나의 프로그램을 볼 수 있다
JS 프로그램은 기본적으로 데이터를 API에서 가지고 오고, 그 작업이 끝나면 계속될거임!

웹사이트에서 데이터를 어떻게 가져올까? 나는 fetch를 이용할거임

const hello = fetch("http://google.com");
  
console.log("something");
console.log(hello);
  

우리가 한다면, google.come을 fetch하고, error를 얻고
아무것도 console.log하지 말아야함 근데 ??
여기서 일어난 일은 something이 먼저 출력되고, 그리고 나서 에러가 출력됐어.
이게 JS의 비동기성(async)
JS는 단지 fetch를 한다고 프로그램의 실행을 멈추지 않아.
JS는 google fetch를 실행하고, 계속해서 something을 console.log 함!
그리고 나서 google fetch가 끝나면, 에러가 발생!
이게 바로 비동기적!

Creating Promises

Promise는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다.
그래서 Promise를 만들 때는 실행할 수 있는 function을 넣어야함!

이 Promise를 resolve 하거나 reject하는거임 (resolve 함수임
resolve는 야, 이게 네 값이야. JS로 돌아가!
reject는 야, 미안한데 에러가 있어.
이전 비디오에서 google을 fetch 했는데, Promise가 reject 됐어.

const amIGood = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, "Yes you are");
});

console.log(amIGood);

setInterval(console.log, 1000, amIGood);

결과

Promise {}
Promise {}
Promise {: 'Yes you are'}
.
.
.

Promise의 핵심은 내가 아직 모르는 value와 함께 작업할 수 있게 해준다는거임!

Using Promises

promise를 통해 값 얻기
JS에 promise가 끝난 이후의 명령어를 전달하려면 언제 끝나는 건 중요하지 않고 끝나는 이후에 값을 돌려달라구 하는거야 then 이용

amIGood.then(vaue => console.log(value));

Catch는 error을 잡기 위해 쓰는 것

amIGood.then(vaue => console.log(value)).catch(value => console.log(value));  
amIGood.then(result => console.log(result))
  		.catch(error => console.log(error));

then, catch는 각기 다른 상황에서 실행 되는거야

Chaining Promises

then은 넣고 싶은 만큼 넣어주면 됨. 왜냐면 모든 이 모든 then은 서로의 순서가 끝나기만을 기다리는 거거든!

const amIGood = new Promise((resolve, reject) => {
  resolve(2);
});

amIGood
  .then((number) => {
    console.log(number * 2);
  })
  .then((otherNumber) => {
    console.log(otherNumber * 2);
  });

4
NAN

이게 작동이 안되는 이뉴는 promise들을 엮고 싶을 때는 기존의 then에서 return 값이 있어야 하는거야!

const amIGood = new Promise((resolve, reject) => {
resolve(2);
});

const timesTwo = (numbertwo) => numbertwo * 2;  
const timesTwo = (number) => number * 2;
amIGood
  .then(timesTwo)
  .then(timesTwo)
  .then(timesTwo)
  .then(timesTwo)
  .then(timesTwo)
  .then(() => {
    throw Error("Something is wrong");
  })
  .then((lastNumber) => console.log(lastNumber))
  .catch((error) => console.log(error));
  

Promise.all

주어진 모든 Promise를 실행한 후(reslove 되고 나면) 진행되는 하나의 Promise를 반환함

const p1 = new Promise((resolve) => {
  setTimeout(resolve, 3000, "First");
});

const p2 = new Promise((resolve) => {
  setTimeout(reject, 2000, "second");
});

const p3 = new Promise((resolve) => {
  setTimeout(resolve, 1000, "third");
});

const motherPromise = Promise.all([p1, p2, p3]);
motherPromise.then((value) => console.log(values));

즉 Promise.all이 다른 promise들이 전부 진행될 때까지 기다렸다가 진행되었다는거임. 여기 나오는 값을이 Array라는거지. Value의 array들인거야

["First", "Second", "Third"]

p1, p2, p3가 언제 끝나는지 상관 없고 이 값들을 순서에 맞춰서 얻게 되는거임!

Promise.all은 순서에 맞춰서 (내가 요청한대로) 시간이 얼마나 걸리던 전부 끝났을 때 값을 순서대로 제공하는거임.

만약 이게 10초가 걸린다면 우리가 10초를 기다려야 하지만 여전히 순서에 맞춰서 값이 제공될거임

const p1 = new Promise((resolve) => {
setTimeout(resolve, 3000, "First");
});

const p2 = new Promise((resolve, reject) => {
setTimeout(reject, 2000, "second");
});

const p3 = new Promise((resolve) => {
setTimeout(resolve, 1000, "third");
});

const motherPromise = Promise.all([p1, p2, p3]);

motherPromise
.then((value) => console.log(value))
.catch((err) => console.log(err));

제공한 promise가 하나라도 Reject 되면, motherPromise도(다른 promise들도) reject 되는거임

모든 프로세스가 돌아가는지확인할 때 굿!

Promise.race

Promise.all이랑 사용법 똑같음

이 세 개 중에 하나라도 resolve 되거나 reject 되면 된다는거임
Promise Race가 resolve 되어서 then으로 넘어가거나 reject 되어서 catch로 넘어가려면 p1, p2, p3 중 하나만 resolve 되거나 reject 되면 돼!

const p1 = new Promise((resolve) => {
setTimeout(resolve, 3000, "First");
});

const p2 = new Promise((resolve, reject) => {
setTimeout(reject, 2000, "second");
});

const p3 = new Promise((resolve) => {
setTimeout(resolve, 1000, "third");
});

Promise.race([p1, p2, p3])
.then((value) => console.log(value))
.catch((err) => console.log(err));

어느 것이 먼저 되는 지 상관 없을 때 Race를 사용하면 됨!
정말 어떤 것이 먼저 되든지 상관 없을 때 말이야!

Third가 나옴.
5초 후에 reject가 실행되기로 되어 있어. 하지만 Promise Race를 reject에 대해 아무 것도 하지 않음! 또 First가 10초 후에 resolve 되기로 했었는데, 신경 쓰지 않았어. 단지 빠르게 실행되는 것만 신경쓰면 됨. 기본적으로 가장 먼저 끝난 Promise가 부모 Promise를 resolve할 거야. 알겠지?
Promise Race를 많이 사용하지 않음. 왜냐면 보통 세가지 전부 잘 되는지를 신경쓰니까!
Race는 이 중 어떤 것이든지 성공하거나 reject가 발생하지 않으면 resolve 됨!
또한 이렇게 하지 않고 이렇게 바로 사용해도 됨,,!

Finally

만약 에러가 발생하면, Spinner를 멈추고 유저에게 에러를 해결하라고 보여주고 싶고, 업로드에 성공하면, Spinner를 멈추고 싶어.

결과에 대해 신경쓰지 않아도 됨. finalize 하는데 성공하든지 실패하든지는 상관 없어.

Finally를 보통 API 호출할 때 씀! 로딩할 때, 하나를 얻고 두 개를 얻고 세 개를 얻고 마지막으로 데이터를 보여주거나 로딩을 멈추거나 뭔가를 하거나 할 때.

const p1 = new Promise((resolve, reject) => {
setTimeout(reject, 1000, "First");
})
.then((value) => console.log(value))
.catch((e) => console.log(`${e}error`))
.finally(() => console.log("Im done"));

Real world Promise

//fetch("https://google.com")
// .then((response) => console.log(response))
// .catch((e) => console.log(`✔${e}`));

fetch("http://127.0.0.1:5500/index.html")
.then((response) => response.text())
// .then((potato) => console.log(potato))
.catch((e) => console.log(`✔${e}`));

fetch("https://yts.mx/api/v2/list_movies.json")
.then((response) => {
//console.log(response);
return response.json();
})
.then((potato) => console.log(potato))
.catch((e) => console.log(`✔${e}`));

fetch가 하는 일은 뭔가를 가지고 오는거임.

ASYNC/AWAIT

Async Await

ASYNC/AWAIT을 만든 이유는, 보기 좋은 코드를 만들기 위해서야.
asyncs/await은 기본적으로 Promise를 사용하는 코드를 더 좋게 보이게 하는 문법임. then, catch는 조금 old 해
기본적으로 asyncs/await은 Promise 밖에서 값을 가져올 수 있는 방법
많은 then이나 catch를 사용하지 않고 말이야

먼저 await은 혼자서는 사용할 수 없음
await은 항상 async function 안에서만 사용할 수 있음
async function은 어케 만들까?

const getMoviesPromise = () => {
  fetch("https://yts.mx/api/v2/list_movies.json")
    .then(response => {
      console.log(response);
      return response.json();
    })
    .then((potato) => console.log(potato))
    .catch((e) => console.log(`✔${e}`));
};
const getMoviesAsync = async () => {
  const response = await fetch("https://yts.mx/api/v2/list_movies.json");
  console.log(response);
  const json = await response.json();
  console.log(json);
};

getMoviesAsync();
  

둘 중에 뭐가 더 나음??
await는 기본적으로 Promise가 끝나길 기다려. wait으로 이해해버려!
그리고 response를 여기서 했던 것처럼 이 변수에 넣어줌
그러니까 기본적으로 resolve 된 값을 여기에 넣어줘

await은 기본적으로 뒤에서 .then(response => {
console.log(response);
return response.json();
})

이걸 해주고 있음!

그리고 await response.json()을 통해 JSON도 얻을 수 있어.
await은 성공을 기다리는게 아니라 Promise가 끝나길 기다려주는거야
resolve 되든 reject 되든 상관 없음. await은 단지 끝나길 기다려주는거야.

try catch finally

const getMoviesAsync = async () => {
  try {
    const response = await fetch("https://yts.mx/api/v2/list_movies.json");
    const json = await response.json();
    console.log(json);
  } catch (e) {
    console.log(e);
  } finally {
    console.log("we are done");
  }
};

getMoviesAsync();

Catch Block이 await안에 있는 error만 잡는게 아니라 밖에 있는 error까지 잡아
어떤 error가 try blobck에 있든지 무조건 잡아! await안에서 발생한 것만 잡는게 아니야. 밖에도 있을 수 있고, 여전히 잡을 수 있음!

왜 이걸 쓰면 더 좋은지
Why async await
예제 있는 사이트

Parallel Async Await

const getMoviesAsync = async () => {
  try {
    const [moviesResponse, upcomingResponse] = await Promise.all([
      fetch("https://yts.mx/api/v2/list_movies.json"),
      fetch("https://yts.mx/api/v2/movie_suggestions.json?movie_id=100"),
    ]);

    const [movies, upcoming] = await Promise.all([
      moviesResponse.json(),
      upcomingResponse.json(),
    ]);

    console.log(movies, upcoming);
  } catch (e) {
    console.log(e);
  } finally {
    console.log("we are done");
  }
};

getMoviesAsync();

+)

Babel

Clases

Introduction to Classes

엄청 많은 코드를 가지고있고 이것을 구조화하길 원할 때, Class를 이용한다면
매우 유용할 수 있음! 왜냐 class는 재사용 가능!

Class는 기본적으로 blueprint! 단순히 화려한 object!

User라는 Class를 만들어 볼겡

Class는 constructor를 안에 갖고 있음!
Constructor는 Class를 말그대로 construct한다는 consturctor!
네가 class를 구성할 때 쓰는 Class 안에는 뭔가 좀 이상한 this로 불리는게 있어!

instance는 살아있는 class를 말해!

class User {
  constuctor() {
  	this.username = "Soo";
  }
  sayHello() {
  	console.log("Hello, I'm Soo");
  	}
  }

const cuteUser = new User();

console.log(cuteUsesr.username);
setTimeout(sexyUser.sexyHello, 4000);  
  

이제 얼마나 많은 instance들을 class가 가질 수 있을까 ? 원하는 만큼!

const baseObject={
  username: "Soo",
  sayHello:function(){
  	console.log("I'm Soo");
  	}
  };  
const cuteUser = baseObject;
const uglyUser = baseObject;

cuteUser.sayHello();
uglyUser.sayHello();  
class User {
  constructor(name){
  	this.username=name;
  }
  sayHello(){
  	console.log(`Hello, my name is ${this.username}`);
  }
}  

const cuteUser = new User("Soo");
  
cuteUser.sayHello();

많은 Classes를 가지면 코드가 엄청 구조적으로 변할거야!

Extending Classes

this는 기본적으로 클래스 안에서 볼 수 있고, 클래스 그 자체를 가리켜
언제든 추가하고 싶거나 클래스로부터 어떤 것을 불러오고 싶을 때 this를 사용할거임!

class User {
constructor(name, lastname, email, password) {
this.username = name;
this.lastname = lastname;
this.email = email;
this.password = password;
}
sayHello() {
console.log(`Hello, my name is ${this.username}`);
}
getProfile() {
console.log(`${this.username} ${this.email} ${this.password}`);
}
updatepassword(newpassword, currentpassword) {
if (currentpassword === this.password) {
this.password = newpassword;
} else {
console.log("can't change password");
}
}
}
class Admin extends User {
// constructor(superadmin) {
// this.superadmin = superadmin;
// } -> consturctor를 다시 정의해서 기존의 constructor을 잃어버려서 오류가 생김!
deleteWebsite() {
console.log("Boom!");
}
}

const sexyUser = new User("Soo", "hyun", "soo@com", "1234");

console.log(sexyUser.password);
sexyUser.updatepassword("new password", "123a4");
console.log(sexyUser.password);
  
const sexyAdmin = new Admin("Soo", "hyun", "soo@com", "1234");
sexyAdmin.deleteWebsite();
console.log(sexyAdmin.email);  

super

class Counter {
constructor({ initialNumber = 0, counterId, plusId, minusId }) {
  this.count = initialNumber;
  this.counter = document.getElementById(counterId);
  this.plusBtn = document.getElementById(plusId);
  this.minusBtn = document.getElementById(minusId);
  this.addEventListeners();
}
addEventListeners() {
  this.plusBtn.addEventListener("click", this.increase);
  this.minusBtn.addEventListener("click", this.decrease);
}
increase() {
  this.count = this.count + 1;
  this.repaintCount();
}
decrease() {
  this.count = this.count - 1;
  this.repaintCount();
}
repaintCount() {
  this.counter.innerText = this.count;
}
}

new Counter({ counterId: "count", plusId: "add", minusId: "minus" });

SYMBOL, SET AND MAP

Symbols

for library를 만들고 있는 사람들을 위한 것

symbol은 고유한 데이터 타입

Symbols는 생성자에 한 가지를 가지는데 Description이야.

const hello = Symbol();
const bye = Symbol();

따라서 여기에 Description을 넣을 수 있어, 하지만 Description은
Value가 아니야 이것들은 단지 Description일 뿐이야 알겠쥥

이 Value을 Symbol 밖으로 빼낼 방법은 없어!

const superBig = {
 [Symbol("nico")]:{
  	age:12
  }, 
 [Symbol("nico")]:{
  	age:12
  }, 
 hello:"bye" 
  };
  

Sets

object의 property가 있는 줄 확인할 수 있어!

const aeSet = new Set([1, 2, 3, 4, 5, 6, 7, 8, 8, 9]);  

aeSet
Set(9) {1, 2, 3, 4, 5, …}

aeSet.has(10)
false

이 Set을 위한 매우 강력한 API를 갖고 있어

WeakSet

뭐가 사용되지 않던간에 그들이 메모리 내에 요소들을 차지하고 있고, 컴퓨터는 메모리가 필요해. 너가 사용하지 않는 것을 청소하려고 할거임 okay?

그게 바로 garbage collection

너의 object를 가르키는 무언가가 없다면, 너의 object는 garbage collector가 가져갈거임!

const weakSet = new WeakSet();
weakSet.add({hello:true})
weakSet {{...}}

garbage

weakSet
WeakSet {}

Map and Weakmap

const map = new Map();
map.set("age", 18)
map.has("age")

true

GENERATORS AND MAPS

Generators

const friends = ["Dal", "Flynn", "Mark"]
  
function friendTeller(){
	for(const friend of friends){
  		yield friend;
  }  
}  
  
const friendLopper = friendTeller();

Proxies

proxy는 filter로 생각할 수 있어!
proxy는 두 개의 input을 취하는데 하나는 target, 이거는 우리가 filter를 하고 싶은 object, 이 경우에는 userObj
다른 하나는 handler,, object임,,

const userObj = {username: "nico", age:12, password:1234 };  
const userFilter = {
	get:()=>{
  		
  		return "NOTHING";
  	},
  	set:()=>{
  		console.log("Somebody wrote something");
  	}
  };
const filteredUser = new Proxy(userObj, userFilter);  

Should you learn proxies or generators? No thanku

New ?? Operator

or(||)은 변수에 기본값을 줄 때 사용함

name =0;
0
console.log("hello", name || "anonymous")
hello anonymous  

변수값은 0이 될 수도 있는데 이렇게 되면 변수값이 있어도 False로 판단해
or은 빈문자열이나 0을 False로 처리해
or 연산자에게는 0도 어떤 값이 아닌 False일 뿐이야

??연산자는 변수값이 null이거나 undefined일 때만 작동해

name =0;
0
console.log("hello", name ?? "anonymous")
hello 0  

Optional Chaining

예상한 것을 (API 등이) 가지고 있는지 아닌지 확신할 수 없을 때 사용

const lynn={nmae:"lynn"}  
console.log(lynn.profile && lynn.profile.email)

undefined
undefiend

console.log(lynn?.profile?.email?.provider?.name)

undefined
undefiend

즉 email은 profile이 없다면 호출되지 않을거야
그리고 profile은 lynn이 없다면 호출되지 않을거야

padStart and padEnd

minutes = String(minutes).padStart(2, "0")

"03"

원하는 길이 가능, 빈자리 메꾸기 가능

padStart랑 padEnd는 절대 값을 변화시키지않아!

"1".padStart(2,"0").padEnd(3,"s")

"01s"

trim, trimStart, trimEnd

비어있는 공간을 없애준다. (단어 사이의 공백 제외)

Object entries, Object values,Object fromEntries

built-in objects에서 object는 JS DATA TYPE
object는 create, assign, freeze 같은 메소드를 가지고 있지

const person = {name:"soo", age:12}
Object.entries(person)
(2) [Array(2), Array(2)]
0: (2) ["name", "soo"]
1: (2) ["age", 12]

Entries는 좀 독특한게 배열의 배열을 return 해
key값의 이름과 값이 배열의 형태로 들어있음!

Object.Entries는 key를 알고 싶을 때 사용하면 됨!

Object.fromEntries([["name","soo"],["age",12],["f","k"],["hello","true"]])
{name: 'soo', age: 12, f: 'k', hello: 'true  

key가 name일 때 key값을 알려면 Object.Entries를 쓰는거임!
배열의 배열로부터 Object를 만들고 싶으면 쓸 수 있는건?Object.fromEntries

Array flat

const flatTest = [1, [2, 2, [3, 3, [4, 4, [5, 5]]]]];

console.log(flatTest.flat()); -> [1, 2, 2, Array(3)]
console.log(flatTest.flat(2)); -> [1, 2, 2, 3, 3, Array(3)]
console.log(flatTest.flat(3)); -> [1, 2, 2, 3, 3, 4, 4, Array(2)]
console.log(flatTest.flat(4)); -> [1, 2, 2, 3, 3, 4, 4, 5, 5]

Array Sort

const word = ["apple", "banana", "coconut", "dodorian", "emart"];

const sortWordsByLength = (wordA, wordB) => {
console.log(wordA, wordB);
return wordA.length - wordB.length;
};

console.log(word.sort(sortWordsByLength));

const people = [
{
name: "soo",
age: 12,
},
{
name: "joey",
age: 30,
},
];

const orderPeopleByAge = (personA, personB) => {
return personB.age - personA.age;
};

console.log(people.sort(orderPeopleByAge));

sort는 배열 값을 변경시킴!
비교함수는 무조건 무엇이라도 반환해야함
object 배열을 정렬할 수 있음

Promise allSettled

Promise.allSettled은 모두 promise가 성공할 필요는 없어
promise가 성공하면 status는 fulfilled을 가지는거야@
그리고 value로 promise를 가지는거구

만약 promise가 rejected되면 status는 rejected이고 reason은 promise의 Error가 되네!

언제 allSettled을 쓰고, 언제 all을 쓸 것인가?
모든 promise가 잘 작동하는 지 확인할 필요가 없으면 우리는 allSettled을 사용하면 됨

다만 모든 promise가 동시에 동작하는지 확인하는게 중요하면 그 때는 promise.all을 사용해야지.

promise.all은 서로 상관이 있는 promise들을 동작시킬 때 사용해
모두 성공 or 모두 실패

promise.allSettled는 promise들이 서로 독립적이라 상관없을 때 사용할 수 있어.
그리고 어떤게 잘 동작하는 지 동작하지 않는지 확인할 때도 말야!

ex) promise끼리 상관이 있다면 promise.all을 사용해,
promise끼리 상관이 없거나 어떤게 실패하는지 보고 싶을 때 아니면 어떤게 성공하는지 보고 싶으면 promise.allSettled를 사용하도록해.

2022

Logical OR Assignment

변수가 falsy일 때 변수에 value를 넣을 수 있게 하는거야!
이름이 없는지 확인해서 값을 annonymous라고 주는 것 대신에!

let name = prompt("what is your name");
name || = "anonymous";
console.log(`Hello ${name}`);  

name은 아마 null이거나 undefined, 또는 false인거야!
만약 그런 것들이 온 경우, JS한테 annonymous를 넣으라고 말하는거야

변수가 falsy일 때, 즉 undefined, false, 빈 문자열, 0 혹은 null일 때,
이 중 하나가 오면, JS는 이 값을 거기 넣을거야!

Logical AND Assignment

변수가 정의가 되어있고 value가 있다면, 변수를 수정할 거라는 뜻!

여기에 user라는 객체에 username이 soo고 password가 123이라면,,

const user = {
  username:"soo",
  password:123
 };  
  
 if(user.password) {
	user.password = "[secret]";  
} 
  
console.log(user);

이렇게 숨기는 일을 and assignment가 할 수 있다는 거임

const user = {
  username:"soo",
  password:123
 };  
  
user.password && ="[secret]";
  
console.log(user);

우리는 보호된 secret password을 얻을 수 있어!

Logical NULLISH Assignment (??=)

undefined 나 null일 때만 작동!

const user = {
	username:"nico",
  	password: 123,
  	isAdmin: null
  };
  
user.isAdmin ??=true;
console.log(user);
  

Numeric Separators

const num = 1_1_0__00_000;
console.log(num);

11000000

Promise any

Promise.any는 p1, p2, p3 중 어느 하나가 끝나기를 기다려
그런 다음 코드가 진행이 되는거야

Promise.any([p1,p2,p3]).then()  

예를 들어 이 코드에서 p2가 먼저 끝났다면, 그냥 다음으로 가는거임

const p1 = new Promise((resolve) => {
  setTimeout(resolve, 1000, "quick");
  });
  
const p2 = new Promise((resolve) => {
  setTimeout(resolve, 5000, "slow");
  });  
  
Promise.any([p1,p2]).then(consle.log);
  

console -> quick이 나옴!!

replaceAll

새로운 변수를 만들어서 사용해야함

const name = "soo";
const newName = name.replaceAll("o", "🤯");
console.log(name, newName);

at()

at은 array에서 여러분이 찾고 싶은 걸 찾을거야,,

const arr = ["a", "b", "c", "d"];

console.log(arr.at(2));
console.log(arr[2]);

만약 배열에서 0부터 시작하는 인덱스의 항목을 찾고 싶다면, 다른 점은 없어!
하지만 끝에서부터 item을 찾고 싶다면 at 메서드가 짱임!

우리가 d를 받아온 이유는 at은 음수 인덱스를 사용해서 끝에서부터 찾을 수 있거든, 끝에서부터 -1, -2, -3, -4임..

consle.log(arr.at(-3));
-> b

JS에서 일반적인 방법으로는 끝에서부터 찾을 수 없어
앞에서부터 인덱스는 0,1,2,3 이렇게 되구,,

Object hasOwn

Objec.hasOwn은 object가 property를 가지고 있는지 확인해

const user = {
  name:"nico",
  isAdmin:"hi"
  };
  
console.log(user.hasOwn(user,"isAdmin"));  

Error cause

error.cause는 에러에 메세지를 추가할 수 있을 뿐만 아니라, 또 다른 정보를 추가하는 기능도 있어

try{
  2+2;
  throw new Error("DB Connection Failed.", {
  	cause:{
  		error:"Password is incorrect.",
  		value:1234,
  		message:["too short", "only number not ok."]
  		}
  	});
  } catch(e) {
  console.log(e.cause);
  }  

Class Field Declarations

class Counter {
  count = 0;
  plus(){
  	this.count++;
  	}
  }  

Private Methods and Fields

class Counter {
  #count = 0;
  static description = "Count up to five.";
  static isMyChild(instance){
  	return instance instanceof Counter;
  }
  get count() {
  	return this.#count;
  }
  plus(){
  	if(this.#count ===5){
  		this.#reset();
  	}	else{
  		this.#count++;
  	}
  
  } 
}  
  
  
  }  

0개의 댓글