[React] Front-End

[Javascript] 앨리의 드림코딩 총정리

ddgoori 2021. 4. 10. 19:35

 

github.com/dream-ellie

 

dream-ellie - Overview

Don't forget to code your dream. dream-ellie has 9 repositories available. Follow their code on GitHub.

github.com

Function

// Function
// - fundamental building block in the program
// - subprogram can be used multiple times
// - performs a task or calculates a value

// 1. Function declaration
// function name(param1, param2) { body... return; }
// one function === one thing
//// 하나의 function은 하나의 일만 해야한다. 

// naming: doSomething, command, verb
// e.g. createCardAndPoint -> createCard, createPoint
// function is object in JS
//// 펑션도 오브젝트다! 펑션을 변수에 할당할 수 있고, 파라미터도 전달할 수 있다.

function printHello() {
  console.log('Hello');
}
printHello();

function log(message) {
  console.log(message);
}

//// 자바스크립트에는 TYPE이 없음..!
//// Typescript는 파라미터나 리턴타입에 항상 타입을 적어줘야함
//// 타입스크립트를 자바스크립트로 결국 변환해서 사용하는 것임.(TypeScript 사이트에서 확인 가능)


log('Hello@');
log(1234);




// 2. Parameters
// premitive parameters: passed by value
// object parameters: passed by reference
function changeName(obj) {
  obj.name = 'coder';
}

const ellie = { name: 'ellie' };
changeName(ellie);
console.log(ellie);




// 3. Default parameters (added in ES6)
function showMessage(message, from = 'unknown') {
  console.log(`${message} by ${from}`);
}

showMessage('Hi!');




// 4. Rest parameters (added in ES6)
//// ...으로 전달하면 배열로 전달 함 
function printAll(...args) {
  for (let i = 0; i < args.length; i++) {
    console.log(args[i]);
  }

//// 간단한 버전의 for문 arg값이 하나하나 돌면서 됨
  for (const arg of args) {
    console.log(arg);
  }

//// 간단한 버전의 for문
  args.forEach((arg) => console.log(arg));
}
printAll('dream', 'coding', 'ellie');




// 5. Local scope
//// 밖에서는 안이 보이지 않고, 안에서만 밖을 볼 수 잏ㅆ다. 
let globalMessage = 'global'; // global variable'(전역변수)

function printMessage() {
  let message = 'hello';
  console.log(message); // local variable(지역변수)
  console.log(globalMessage);
  function printAnother() {
    console.log(message);
    let childMessage = 'hello';
  }
  // console.log(childMessage); //error
}
printMessage();




// 6. Return a value
function sum(a, b) {
  return a + b;
}
const result = sum(1, 2); // 3
console.log(`sum: ${sum(1, 2)}`);




// 7. Early return, early exit
// bad
function upgradeUser(user) {
  if (user.point > 10) {
    // long upgrade logic...
  }
}

// good
//// 조건이 맞지 않을때 빨리 리턴해버리고, 조건이 맞을때 사용하는게 낫다.
function upgradeUser(user) {
  if (user.point <= 10) {
    return;
  }
  // long upgrade logic...
}




// First-class function
// functions are treated like any other variable
// can be assigned as a value to variable
// can be passed as an argument to other functions.
// can be returned by another function

// 1. Function expression
// a function declaration can be called earlier than it is defiend. (hoisted)
// a function expression is created when the execution reaches it.

const print = function () { //// function에 이름을 안넣음. 만약에 function print() 라는 식으로 이름 넣으면 named fucntion
  // anonymous function
  console.log('print');
};
print();
const printAgain = print; //// 할당된 함수는 계속 할당될 수 있음
printAgain();
const sumAgain = sum;
console.log(sumAgain(1, 3));

/////////////////////////////////////////////////////////////////////////////

호이스팅이란?
자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
유효 범위: 함수 블록 {} 안에서 유효
즉, 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어올리는 것이다.
실제로 코드가 끌어올려지는 건 아니며, 자바스크립트 Parser 내부적으로 끌어올려서 처리하는 것이다.
실제 메모리에서는 변화가 없다.
출처: https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html

/////////////////////////////////////////////////////////////////////////////

// 2. Callback function using function expression
//// ansnwer가 'love you'가 맞으면 printYed 함수를 실행하고, 아니면 printNo 함수를 실행하라
function randomQuiz(answer, printYes, printNo) {
  if (answer === 'love you') {
    printYes();
  } else {
    printNo();
  }
}

// anonymous function
const printYes = function () {
  console.log('yes!');
};

// named function
// better debugging in debugger's stack traces
//// 이렇게 함수에 name을 쓰는 이유은 디버깅 리스트에 stack traces에 나오게 하기 위함임
// recursions
//// 혹은 함수내에서 그 함수가 계속 호출되게 하기 위함임
const printNo = function print() {
  console.log('no!');
};
randomQuiz('wrong', printYes, printNo);
randomQuiz('love you', printYes, printNo);

// Arrow function
// always anonymous
// const simplePrint = function () {
//   console.log('simplePrint!');
// };

//// 위 함수를 아래처럼 매우 간단하게 나오게할 수 있음
const simplePrint = () => console.log('simplePrint!');

//// 파라미터 a,b 값을 받고 a+b를 리턴하여라
const add = (a, b) => a + b;

//// 리턴값이 한줄 이상인 경우에는 블럭을 넣어서 처리하시오.
const simpleMultiply = (a, b) => {
  // do something more
  return a * b;
};

// IIFE: Immediately Invoked Function Expression
//// 함수 선언후에 전체를 괄호로 묶고 (); 뒤에 붙여주면 바로 함수가 호출됨(따로 우선적으로 불러줄 필요가 없음)
(function hello() {
  console.log('IIFE');
})();


// Fun quiz time❤️
// function calculate(command, a, b)
// command: add, substract, divide, multiply, remainder

function calculate(command, a, b) {
  switch (command) {
    case 'add':
      return a + b;
    case 'substract':
      return a - b;
    case 'divide':
      return a / b;
    case 'multiply':
      return a * b;
    case 'remainder':
      return a % b;
    default:
      throw Error('unkonwn command');
  }
}
console.log(calculate('add', 2, 3));

 

 

+ Hoisting(호이스팅)

 

 

 

자바스크립트 호이스팅(Hoisting)

(안내) 호이스팅의 원리에 대한 글을 추가로 포스팅했습니다. (19.10.13) 자바스크립트의 변수는 다른 언어들과 조금 다르게 동작합니다. 이는 때때로 개발자로 하여금 의도하지 않은 결과를 발생

yuddomack.tistory.com

 

 

Class

'use strict';
// Object-oriendted programming
// class: template
// object: instance of a class
// JavaScript classes
//  - introduced in ES6
//  - syntactical sugar over prototype-based inheritance

// 1. Class declarations
class Person {
  // constructor
  constructor(name, age) {
    // fields
    this.name = name;
    this.age = age;
  }

  // methods
  speak() {
    console.log(`${this.name}: hello!`);
  }
}

//// 새로운 오브젝트를 만들때는 new라는 키워드를 쓴다.

const ellie = new Person('ellie', 20);
console.log(ellie.name);
console.log(ellie.age);
ellie.speak();




// 2. Getter and setters
class User {
  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }

//// get으로 값을 리턴
//// 이 get을 설정하는 순간 위의 this.age는 메모리에 올라가있는 데이터를 읽어오는 것이 아니라
//// 아래의 getter 인 get age()를 호출한다. setter도 마찬가지..
//// 이름이 같으면 무한정 호출하게됨 그래서 게터 세터 사용할때는 이름을 좀 변경해야함

  get age() {
    return this._age;
  }

//// set으로 값 설정 ->
  set age(value) {
    // if (value < 0) {
    //   throw Error('age can not be negative');
    // }
    this._age = value < 0 ? 0 : value;
  }
}

//// 사용자가 -1로 실수로 나이를 지정을 하면
//// 클래스를 사용하는 사용자가 바보같이 잘못사용해도
//// 방어적인 자세로 만들어주는 것이 getter setter


const user1 = new User('Steve', 'Job', -1);
console.log(user1.age);

// 3. Fields (public, private)
// Too soon!
//// 나온지 얼마안됨.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields
class Experiment {
  publicField = 2;
  #privateField = 0;
}
const experiment = new Experiment();
console.log(experiment.publicField);
console.log(experiment.privateField); // #을 붙이면 private되어서 안보임

// 4. Static properties and methods
// Too soon!
//// static은 클래스 자체에 붙어있음. 그래서 오브젝트가 아니라 클래스 이름을 이룔해서 호출이 가능하다

class Article {
  static publisher = 'Dream Coding';
  constructor(articleNumber) {
    this.articleNumber = articleNumber;
  }

  static printPublisher() {
    console.log(Article.publisher);
  }
}

const article1 = new Article(1);
const article2 = new Article(2);
console.log(Article.publisher);
Article.printPublisher();





//// 상속

// 5. Inheritance
// a way for one class to extend another class.
class Shape {
  constructor(width, height, color) {
    this.width = width;
    this.height = height;
    this.color = color;
  }

  draw() {
    console.log(`drawing ${this.color} color!`);
  }

  getArea() {
    return this.width * this.height;
  }
}

//// shape에 선언된 필드들이 자동으로 rectangle에 포함된다.
//// 상속을 이용하면 extends를 이용해서 재사용할수가있다.
//// 필요한 함수만 overridin가능



class Rectangle extends Shape {}
class Triangle extends Shape {
  draw() {
    super.draw();
    console.log('🔺');
  }
  getArea() { // over riding함
    return (this.width * this.height) / 2;
  }

//// 아래는 object의 함수 toString을 오버라이딩한 것

  toString() {
    return `Triangle: color: ${this.color}`;
  }
}

const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw();
console.log(rectangle.getArea());
const triangle = new Triangle(20, 20, 'red');
triangle.draw();
console.log(triangle.getArea());




왼쪽이 어떤 클래스의 인스턴스인지 확인하는 것임
// 6. Class checking: instanceOf
console.log(rectangle instanceof Rectangle);
console.log(triangle instanceof Rectangle); //F
console.log(triangle instanceof Triangle);
console.log(triangle instanceof Shape);
console.log(triangle instanceof Object);
console.log(triangle.toString());

let obj = { value: 5 };
function change(value) {
  value.value = 7;
}
change(obj);
console.log(obj);

 

 

 

 

 

Object

// Class
//// class = fields + methods(가끔 fields만 있기도함)
//// class: template
//// object: Instance of a class
//// 연관있는 것들끼리 묶어놓은 것
//// 클래스는 청사진이라고도 불리고, 템플릿이라고도 불림
//// 데이터는 없고, 한번만 선언됨
//// 이러한 클래스를 통해 만드는 것이 오브젝트
//// 오브젝트는 메모리에 올라감. 데이터가 있으니깐!

'use strict';
// Objects

// one of the JavaScript's data types.
// a collection of related data and/or functionality.
// Nearly all objects in JavaScript are instances of Object
// object = { key : value };
// 오브젝트는 프로퍼티와 값의 집합이다. key는 네임 value는 엘리
// 변수 하나당 하나만 담을 수 있다.
 
 //1. Literlas and Properties
const obj1 = {}; // 'object literal' syntax
const obj2 = new Object(); // 'object constructor' syntax

//근데 신기한게 자바스크립트는 파라미터에 타입이 명시가 안돼있넴 ㅇ.ㅇ?;
function print(person) {
  console.log(person.name);
  console.log(person.age);
}

// 이것도 object를 만드는 방법이다!
// 자바스크립트에서는 클래스가 없어도 아래와 같이 바로 Object를 만들 수 있음! 싱기방기~
const ellie = { name: 'ellie', age: 4 };
print(ellie);

// with JavaScript magic (dynamically typed language)
// 자바스크립트는 동적으로 타입이 런타임때 결정되는 언어다!
// 그래서 뒤늦게 클래스의 property를 아래와 같이 추가할 수 있다. 미친언어 ㅇ.ㅇ.....
// can add properties later
ellie.hasJob = true;
console.log(ellie.hasJob);

// can delete properties later
delete ellie.hasJob;
console.log(ellie.hasJob);





// 2. Computed properties
// 계산된 프로퍼티 
// key should be always string
console.log(ellie.name);
console.log(ellie['name']);  // computed property 보통 닷. 을 쓰는게 나음
// 스트링 형태로 접근 가능
// 즉 key는 항상 string타입으로 지정해서 받아와야함 'name'cjfja

ellie['hasJob'] = true;
console.log(ellie.hasJob);


//동적으로 key에 관련된 value를 받아올 때 유용하다.
function printValue(obj, key) {
  console.log(obj[key]);
}
printValue(ellie, 'name');
printValue(ellie, 'age');




 
// 3. Property value shorthand
const person1 = { name: 'bob', age: 2 };
const person2 = { name: 'steve', age: 3 };
const person3 = { name: 'dave', age: 4 };
const person4 = new Person('elile', 30);
console.log(person4);




// 오브젝트를 필요할때마다 일일이 만들면 동일한 키를 계속 반복해서 작성해야한다.
// 함수를 이용해서 아래와 같이 만듬
// 클래스와 같은 것
// 보통 순수하게 오브젝트를 생성하는 함수는 대문자로 시작하도록 하고,
// return 하지는 않고, this 이용함!
// 호출할때도 클래스에서 오브젝트 만드는 것처럼 new 로 만들 수 있음
// 4. Constructor Function
function Person(name, age) {
  // this = {};
  this.name = name;
  this.age = age;
  // return this;
}




// 5. in operator: property existence check (key in obj)
// 키가 있는지 없는지 확인하는 것
console.log('name' in ellie);
console.log('age' in ellie);
console.log('random' in ellie); false
console.log(ellie.random); undefined // <-정의하지 않은 것 출력하면 나옴





// 6. for..in vs for..of
// for (key in obj)
console.clear();

//앨리가 가지고 있는 키들이 그 안의 지역변수의 키에 할당된다.

for (let key in ellie) {
  console.log(key);
}

// for (value of iterable)
// 이 데이터의 모든 값을 찍기 위해 과거 for문과 다른 방법
// array에 있는 모든 값들이 할당되면서 출력됨(아래 방법)
const array = [1, 2, 4, 5];

for (let value of array) {
  console.log(value);
}






// 7. Fun cloning
// Object.assign(dest, [obj1, obj2, obj3...])
const user = { name: 'ellie', age: '20' };
const user2 = user;
user2.name = 'coder'; // 요것을 실행하면
console.log(user); // ref를 가리키고 있는 것이기 때문에 user의 이름도 coder로 같이 바뀐다.

세상에....

// old way -> 복사하는 방법 과거 방법으로!
const user3 = {};
for (let key in user) {
  user3[key] = user[key];
}
console.clear();
console.log(user3);

// 복사 가능! ! ! object복사
// 전달하는 오브젝트는 텅텅빈 것
const user4 = Object.assign({}, user);
console.log(user4);

// another example
const fruit1 = { color: 'red' };
const fruit2 = { color: 'blue', size: 'big' };
const mixed = Object.assign({}, fruit1, fruit2);
console.log(mixed.color); //blue  -> red는 덮어씌워짐
console.log(mixed.size); // big

 

 

 

 

Array

'use strict';

// Array🎉

// 1. Declaration
const arr1 = new Array();
const arr2 = [1, 2];

// 2. Index position
const fruits = ['🍎', '🍌'];
console.log(fruits);
console.log(fruits.length);
console.log(fruits[0]);
console.log(fruits[1]);
console.log(fruits[2]);
console.log(fruits[fruits.length - 1]);
console.clear();



// 3. Looping over an array
// print all fruits
// a. for
for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

// b. for of
for (let fruit of fruits) {
  console.log(fruit);
}

// c. forEach
fruits.forEach((fruit) => console.log(fruit));




// 4. Addtion, deletion, copy
// push: add an item to the end
fruits.push('🍓', '🍑');
console.log(fruits);

// pop: remove an item from the end
const poped = fruits.pop();
fruits.pop();
console.log(fruits);

// unshift: add an item to the benigging
fruits.unshift('🍓', '🍋');
console.log(fruits);

// shift: remove an item from the benigging
fruits.shift();
fruits.shift();
console.log(fruits);

// note!! shift, unshift are slower than pop, push
// splice: remove an item by index position
// splice에서 어디까지 지울지 지정안하면 그 뒤로 다지워짐 ! !
fruits.push('🍓', '🍑', '🍋');
console.log(fruits);
fruits.splice(1, 1);
console.log(fruits);

// splice한 이후로 그 지운자리부터 데이터를 넣을 수 있음
fruits.splice(1, 1, '🍏', '🍉');
console.log(fruits);

// combine two arrays
const fruits2 = ['🍐', '🥥'];
const newFruits = fruits.concat(fruits2);
console.log(newFruits);

두개의 배열이 합쳐서서 1열의 배열이 합쳐져서 만들어짐


// 5. Searching 검색
// indexOf: find the index

console.clear();
console.log(fruits);
console.log(fruits.indexOf('🍎'));
console.log(fruits.indexOf('🍉'));
console.log(fruits.indexOf('🥥'));
//데이터값이 몇번째 인덱스에 있는지 확인 가능

// includes
console.log(fruits.includes('🍉'));
console.log(fruits.includes('🥥'));
// 데이터값이 있는지 없는지 확인 가능. 배열 안에 해당되는 값이 없으면 -1 출력

// lastIndexOf
console.clear();
fruits.push('🍎');
console.log(fruits);
console.log(fruits.indexOf('🍎')); // 첫번재로 해당하는 값을 만나면 그 인덱스 리턴
console.log(fruits.lastIndexOf('🥥')); // 마지막으로 해당하는 값을 만나면 그 인덱스 리턴

pop이 리턴이 되는건지 그냥 없애는건지 그런것도 중요. 리턴이 되면 팝되는 걸 받아올 수가 있음

 

 

 

Array - API

// Q1. make a string out of an array
{
  const fruits = ['apple', 'banana', 'orange'];
  const result = fruits.join(',');
  console.log(result);
}

// Q2. make an array out of a string
{
  const fruits = '🍎, 🥝, 🍌, 🍒';
  const result = fruits.split(','); //스트링을 구분자를 통해 배열로 만들어줌
  console.log(result);
}

// Q3. make this array look like this: [5, 4, 3, 2, 1]
{
  const array = [1, 2, 3, 4, 5];
  const result = array.reverse();
  console.log(result);
  console.log(array);
}

// Q4. make new array without the first two elements
{
  const array = [1, 2, 3, 4, 5];
  const result = array.slice(2, 5);
  console.log(result);
  console.log(array);
}

class Student {
  constructor(name, age, enrolled, score) {
    this.name = name;
    this.age = age;
    this.enrolled = enrolled;
    this.score = score;
  }
}
const students = [
  new Student('A', 29, true, 45),
  new Student('B', 28, false, 80),
  new Student('C', 30, true, 90),
  new Student('D', 40, false, 66),
  new Student('E', 18, true, 88),
];

// Q5. find a student with the score 90
{
  const result = students.find((student) => student.score === 90);
  console.log(result);
}

// Q6. make an array of enrolled students
{
  const result = students.filter((student) => student.enrolled);
  console.log(result);
}

// Q7. make an array containing only the students' scores
// result should be: [45, 80, 90, 66, 88]
{
  const result = students.map((student) => student.score);
  console.log(result);
}

// Q8. check if there is a student with the score lower than 50
{
  console.clear();
  const result = students.some((student) => student.score < 50); //배열중에 조건 하나라도 만족하면 return true
  console.log(result);

  const result2 = !students.every((student) => student.score >= 50); //모든 배열의 조건에 만족하면 return true
  console.log(result2); 
  
}
console.clear();
// Q9. compute students' average score
{
//콜백함수는 배열의 모든 요소들이 다 됨
//어떤값이 누적된 값이 전달됨
//reduce 배열의 모든값을 누적하는, 모아놓을 때 하는 것 -> current은 배열의 아이템을 순차적으로 전달받음
//reduceRight은 배열의 제일 뒤에서부터 시작하는 것
  const result = students.reduce((prev, curr) => prev.score + curr.score);
  console.log(result / students.length);
}

// Q10. make a string containing all the scores
// result should be: '45, 80, 90, 66, 88'
{
  const result = students 
    .map((student) => student.score)  //score만 있는 배열 리턴
    .filter((score) => score >= 50)		//filter함수는 Array에서 조건에 맞는 값을 결과값으로 추출해줌
    .join();					
  console.log(result);
}

// Bonus! do Q10 sorted in ascending order
// result should be: '45, 66, 80, 88, 90'
{
//map을 이용하면 새로운 배열이 만들어짐 join을 하면 스트링으로 리턴
  const result = students
    .map((student) => student.score)
    .sort((a, b) => b - a) //a이전값, b현재값 -> 점수가 높은게 앞에 나옴!  !
    .join();  //join은 소팅된 배열을 스트링으로 바꿔줌
  console.log(result);
}

 

 

JSON

 

'use strict';

// JSON
// JavaScript Object Notation

// 1. Object to JSON (오브젝트를 제이슨으로!)
// stringify(obj)
// object를 스트링으로 serialize하고 string을 다시 object로 deserialize해야함


let json = JSON.stringify(true);  //JSON이라는 오브젝트로 변환 가능
console.log(json); // boolean 타입도 json의 stringify가능

// JSON이라는 API에는 parse stringify 두 개가 있음
// parse: JSON에 스트링타입을 넣으면 => 어떤 타입으로 변환이 된다.
// stringify: 스트링으로 변환해준다. 콜백함수로 전달하면 조금더 통제하면서 가능

json = JSON.stringify(['apple', 'banana']);
console.log(json);
// 배열 타입처럼 보이지만 "" double쿼트로 들어가있는 json이 출력됨
// ["apple","banana"]

const rabbit = {
  name: 'tori',
  color: 'white',
  size: null,
  birthDate: new Date(),
  jump: function () {
    console.log(`${this.name} can jump!`);
  },
};

json = JSON.stringify(rabbit); // 위의 rabbit object를 제이슨으로 변환한다!
console.log(json);  // 이때 jump는 함수이므로 json으로 변환되지 않는다.

// 내가 원하는 프로퍼티만 골라서 정의를 하면, 해당하는 프로퍼티만 제이슨으로 변환이 된다. 
json = JSON.stringify(rabbit, ['name', 'color', 'size']);
console.log(json);

// 콜백함수를 이용해서 세밀하게 통제하는 과정 
// 
json = JSON.stringify(rabbit, (key, value) => {
  console.log(`key: ${key}, value: ${value}`);
  return key === 'name' ? 'ellie' : value; //key가 name이면 ellie로 변환하고 그게 아니면 value로 그대로 사용한다는 뜻
});
console.log(json);




// 2. JSON to Object (JSON을 오브젝트로 변환하는 법)
// parse(json)
console.clear();
json = JSON.stringify(rabbit);

// 우리가 변환하고 있는 Json을 parse를 통해 전달해주기만 하면됨
console.log(json);
const obj = JSON.parse(json, (key, value) => {
  console.log(`key: ${key}, value: ${value}`);
  return key === 'birthDate' ? new Date(value) : value;
  // 만약 키가 birthDate이면 new Data(value)로 넣거라. 
});

console.log(obj);
rabbit.jump();
// obj.jump(); // object -> json 이후 json -> object는 jump라는 api가 없다.
// obj를 json으로 변환할때는 데이터만 serialize돼서 jump라는 함수가 포함이 안됨
console.log(rabbit.birthDate.getDate());
// birthDate <-오브젝트인데.. json으로 변환하면 스트링으로 변환돼서 다시 json을 오브젝트로 변환할 때 스트링으로 인식돼서 Date()  객체 내부 함수를 사용할 수가 없음
// 이것때문에 리바이벌을 사용하는 것임
console.log(obj.birthDate.getDate());
// 제이슨으로 만든 birthDate로 만든걸 출력하면 오류가 남. string

 

유용한 사이트:

JSON Diff checker: http://www.jsondiff.com/

JSON Beautifier/editor: https://jsonbeautifier.org/

JSON Parser: https://jsonparser.org/

JSON Validator: https://tools.learningcontainer.com/j...

 

 

 

CallBack

 

'use strict';

// JavaScript is synchronous.
// Execute the code block in order after hoisting.
// hoisting: var, function declaration -> var변수나 함수선언들이 자동으로 위로 올라가는 것
// hoisting: 코드가 나타나는 순서대로 실행된다. 

// 콜백함수: 우리가 전달해준 함수를 나중에 니가 불러줘!
// map, filter 등..에서 콜백함수를 많이 이용함 
// 끝나고 나중에 다시 불러줘! 해서 CallBack 함수

console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');

//싱크로너스! -> 순서대로 호출
//에이싱크로너스! -> 비동기, 언제 호출될지모름



// 즉각호출
// Synchronous callback

function printImmediately(print) {
  print();
}
printImmediately(() => console.log('hello'));



// 나중 호출
// Asynchronous callback

function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);

// Callback Hell example
class UserStorage {
  loginUser(id, password, onSuccess, onError) {
    setTimeout(() => {
      if (
        (id === 'ellie' && password === 'dream') ||
        (id === 'coder' && password === 'academy')
      ) {
        onSuccess(id);
      } else {
        onError(new Error('not found'));
      }
    }, 2000);
  }

  getRoles(user, onSuccess, onError) {
    setTimeout(() => {
      if (user === 'ellie') {
        onSuccess({ name: 'ellie', role: 'admin' });
      } else {
        onError(new Error('no access'));
      }
    }, 1000);
  }
}

const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your passrod');
userStorage.loginUser(
  id,
  password,
  user => {
    userStorage.getRoles(
      user,
      userWithRole => {
        alert(
          `Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
        );
      },
      error => {
        console.log(error);
      }
    );
  },
  error => {
    console.log(error);
  }
);