해보자고

[UDEMY] Node.js - Section(02) 본문

웹 프로그래밍

[UDEMY] Node.js - Section(02)

초코맛동산 2023. 7. 22. 16:20

Javascript 요약


*약타입 프로그래밍 언어이며 객체 지향 프로그래밍 언어.

약타입 프로그래밍 언어라는 점에서 엄격한 타입 설정은 필요 없으나 오류로 이어질 수 있다. 

객체 지향 프로그래밍 언어라는 점에서 *원시 타입(Primitive type), *참조 타입(Reference Type)의 차이를 알아야 한다. 

Node.js를 통해 브라우저 밖의 서버 등의 다양한 환경에서 실행이 가능하다. 

 

 

*약타입 언어: 명확한 타입 할당이 없다. 

+) string, boolean 등의 타입이 있지만 변수 또는 함수에서 어떤 형태를 사용하는지 정의하라고 강요하지 않고, 타입을 동적으로 변경이 가능하다. ex) 숫자 변수 -> 문자 변수

*원시 타입: string, number, boolean 등과 같이 실제 데이터 값을 저장하는 타입 

*참조 타입: 원시 타입을 제외한 나머지 타입이며, 객체의 번지를 참소하는 타입 즉 메모리 상의 주소를 통해 객체를 참조하는 타입을 의미.

 

Javascript 복습


변수

var name = 'Max'; //문자
var age = 29; //숫자
var hashobbies = true; //Boolean

// line 1 ~ line 3은 전역 변수

function summerizeUser(userName, userAge, userHasHobby) { // function 키워드로 함수 정의, 로컬 변수로 함수 안에서만 사용 가능.
    return ( // return 통해 값 반환
    'Name is ' + 
    userName + 
    ', age is ' + 
    userAge + 
    ', and the user has hobbies: ' + 
    userHasHobby
    );
}

console.log(summerizeUser(name, age, hasHobbies)); // 함수 호출

// line 7 ~ line 18 은 외부에 의존하지 않는 순수 함수로 데이터 모두 인수 형태로 받고 있음.

 

=> 결과 값

 

 

 

 

let 과 const


변수를 생성하는 키워드들이지만 차이점이 존재.

 

차이점

- let은 값의 업데이트가 가능하지만 const는 값의 업데이트가 불가능.

- 즉, 변수 값의 변경 계획 여부에 따라 const와 let을 사용. 

 

const name = 'Max';
let age = 29;
const hasHobbies = true;

name = 'Mazimilian'; // 에러 유발 <- const로 선언했는데 값을 바꿔서
age =30;

function summerizeUser(userName, userAge, userHasHobby) {
    return (
    'Name is ' + 
    userName + 
    ', age is ' + 
    userAge + 
    ', and the user has hobbies: ' + 
    userHasHobby
    );
}

console.log(summerizeUser(name, age, hasHobbies));

 

화살표 함수 


익명 함수

 

- 함수를 정의하는 또 다른 방법

- 익명 함수는 function 다음에 이름을 설정하는 것이 아니라 (ex. function a1 = {};) 익명 함수를 명명된 const에 저장하여 기명 함수로 만들어 줌.

 

const summerizeUser = function (userName, userAge, userHasHobby) { // 변경 코드. function 부터 끝까지 익명 함수
    return (
    'Name is ' + 
    userName + 
    ', age is ' + 
    userAge + 
    ', and the user has hobbies: ' + 
    userHasHobby
    );
}

화살표 함수

- function 키워드가 없기에 좀 더 짧고 이전 방식과 마찬가지로 함수 작동

 

const summerizeUser = (userName, userAge, userHasHobby) => { //  function 키워드를 제거하고 인수 목록과 중괄호 사이에 화살표를 추가
    return (
    'Name is ' + 
    userName + 
    ', age is ' + 
    userAge + 
    ', and the user has hobbies: ' + 
    userHasHobby
    );
};

- 화살표 함수 실습 1

 

const add = (a,b) => {
    return a+b;
};

console.log(add(1,2));
// 결과 값: 3

----------
const add = (a,b) => a+b;

console.log(add(1,2));
// 결과 값: 3

- 화살표 함수 실습 2

- return문이 하나만 있는 화살표 함수라면 중괄호와 return 생략 가능.

- 즉 위 함수와 아래 함수는 동일한 구문

 

 

const addOne = (a) => a + 1;

console.log(addOne(1));
// 결과 값: 2
---------
const addOne = a => a + 1;

console.log(addOne(1));
// 결과 값: 2

- 화살표 함수 실습 3

- 인수가 하나라면, 인수 이름을 입력하고 괄호가 없어도 있을 때와 동일하게 작동함. 

- 둘 모두 가능하지만 일반적으로는 괄호 없는 구문을 사용함. 

 

const addRandom = () => 1 + 2;

console.log(addRandom());
// 결과 값: 3

- 인수가 없는 화살표 함수가 있으면 비어있는 괄호 한 쌍을 명시해야 함. 즉 공백으로 두면 안 됨.

 

객체와 속성 및 메소드


객체 생성

- 일반적으로 중괄호를 통해 객체 생성

- 중괄호 안에는 키-값 쌍이 들어감. (프로퍼티 또는 필드라고도 불림)

- 객체를 통해 데이터 묶기가 가능.

 

const person = { // person이 객체
    name: 'Max', // :이 꼭 필요하다.
    age: 29
};

console.log(person);
// 결과 값: { name: 'Max', age: 29 }

 

const person = {
    name: 'Max',
    age: 29,
    greet: () => {
        console.log('Hi, I am ' + this.name); //this는 주위 객체를 참조하며, 마침표를 사용함. '.'으로 속성 또는 매서드, 즉 객체 내의 변수나 함수를 액세스.
    }
};

person.greet();
// 결과 값: Hi, I am undefined

- 객체에 변수 뿐 아닌 함수도 넣는 것이 가능

- 결과 값이 Hi, I am undefined인 이유 => 화살표 함수의 특성 때문. this는 이제 person 객체가 아닌 전역 범위, 전역 노드 런타임 범위를 참조. 이를 참조하도록 하려면 기존 function 키워드를 사용해야 함. (아래 코드 참조)

const person = {
    name: 'Max',
    age: 29,
    greet: function() { // 변경 코드
        console.log('Hi, I am ' + this.name);
    }
};

person.greet();
// 결과 값: Hi, I am Max

- 또는 화살표 함수 사용 X, 키와 괄호 사이의 콜론을 생략하고 바로 함수 본문 입력 => 메서드가 됨. (아래 코드 참조)

const person = {
    name: 'Max',
    age: 29,
    greet() { // 변경 코드
        console.log('Hi, I am ' + this.name); 
    }
};

person.greet();
// 결과 값: Hi, I am Max
 

배열과 배열 메서드


배열

- 대괄호로 정의

- 참조타입

- 어떤 데이터든 배열에 담길 수 있음. 

- 배열에 하나의 데이터 타입만을 사용할 필요 없음. 

const hobbies = ['sports', 'Cooking', 1, true]; // 가능

 

 

for 루프와 배열

 

const hobbies = ['sports', 'Cooking'];
for (let hobby of hobbies) { // 매 반복마다 각 원소를 hobby 변수로 저장 
    console.log(hobby);
}

- hobbies에 두 개의 원소가 있기에 console.log는 2번 실행됨. 

- 매 반복마다 값이 바뀌며, 왼쪽에서 오른쪽으로 진행. 

 

결과 화면

 

- 배열에는 다양한 내장 메서드가 존재.

- 확인 방법| 배열명.

map  

- 배열 또는 값들을 변환해주며 새로운 배열을 반환함. -> 기존의 것을 편집하는 대시 새로운 배열을 반환. 

- 함수의 형태이며, 어떻게 배열 혹은 배열의 원소를 편집할지 정의해야 함. 

- 배열의 모든 원소에 하나씩 적용되며 업데이트된 원소가 새로운 배열에 반환.

 

const hobbies = ['sports', 'Cooking'];

console.log(hobbies.map(hobby => 'Hobby: ' + hobby)); // 새로운 배열
console.log(hobbies); // 기존 배열

 

 

play.js 결과

- 결과를 보면 기존 배열이 편집된 것X.

- map을 통해 편집된 새로운 배열을 결과로 확인 가능.

push

- 기존 배열에 새로운 원소를 추가할 수 있음. 

 

const hobbies = ['sports', 'Cooking'];

hobbies.push('Programming');
console.log(hobbies);
// 오류 발생XX

 

결과 값

- 배열은 참조타입이므로, const로 배열을 선언해도 그 값을 바꾸는 것이 가능.

why?

- 배열이 저장된 메모리 위치를 가리키는 주소만 저장하기에 새 원소를 추가해도 주소를 나타내는 포인터가 바뀌지는 않았기 때문에.

- 즉 const 값이 바뀐 것 X

Spread 및 Rest 연산자 


불변성

기존 배열을 편집하지 않고, 기존 값과 새로운 값이 모두 포함된 새로운 배열을 만드려는 패턴. 즉 사본에 변경된 값을 더한 배열로 기존 객체를 편집하지 않고서, 편집 가능. 이는 곧 오류를 적게 일으킬 수 있음.

 

Slice 연산자

- slice()

- 배열을 복사함. 

- 인수를 입력하여 복사하길 원하는 원소의 범위를 제한할 수 있음. (인수가 없다면 배열 전체를 복사함.)

 

중첩 배열 

- 대괄호로 새로운 배열을 만들고 hobbies를 추가

const copiedArray = [hobbies];
console.log(copiedArray);

 

위 결과 값.

- 실제로는 배열 안에 또 다른 배열이 있는 것임. 즉 외부 배열에 하나의 원소만이 있고 그 원소가 바로 내부 배열.

- 따라서 사본이 아니라 첫 원소가 기존의 배열인 새로운 배열인 것. 

- 이는 사본이 아니라 완전히 동일한 객체를 의미함. 

 

Spread 연산자

- 배열 또는 객체 앞에 점 세 개 추가하기. 

- 연산자 뒤에 오는 배열, 객체 등을 받아서 원소 또는 속성을 끄집어 냄. 

 

const person = {
    name: 'Max',
    age: 29,
    greet() {
        console.log('Hi, I am ' + this.name);
    }
};

const copiedPerson = {...person}; // 기존 객체의 원소를 모두 추출해서 새로운 객체에 추가.
console.log(copiedPerson);

const hobbies = ['sports', 'Cooking'];

const copiedArray = [...hobbies]; // 스프레드 연산자에 대괄호가 씌워져 있음 -> 기존 배열에서 끄집어낸 모든 원소를 새로운 배열에 추가해 준다는 의미.
console.log(copiedArray);

 

 

- ['sports', 'Cooking'] 은 기존 배열의 사본임. 

- { name: 'Max', age: 29, greet: [Function: greet] }은 기존 객체의 사본임. 

 

Rest 연산자

- 배열 또는 객체 앞에 점 세 개 추가하기. 

- 구문으로 보면 스프레드 연산자와 동일하지만 사용하는 위치에 따라 정의가 달라짐.

- 스프레드 연산자와 레스트 연산자의 구분: 

스프레드 연산자 배열이나 객체에서 원소나 속성을 추출하는 데 사용
레스트 연산자 인수 목록이나 함수에서 여러 인수를 하나의 배열로 묶는데 사용

 

- Rest 연산자 예시: 

const toArray = (arg1, arg2, arg3) => {
    return [arg1, arg2, arg3];
}
console.log(toArray(1,2,3,4));

// 결과 값: [ 1, 2, 3 ]

- 유연한 코드는 X => 인수로 3개의 값을 전달할 때는 괜찮은데, 지정한 인수 값을 넘어서면 추가된 인수는 추가되지 않음. 

 

const toArray = (...args) => { // 인수 개수에 관계없이 모든 인수를 가지고 와서 하나의 배열로 나타낼 수 O
    return args; 
}
console.log(toArray(1,2,3,4));

// 결과 값: [ 1, 2, 3, 4 ]

Destructuring


들어오는 객체에서 무엇을 필요로 하는지, 어떤 값을 로컬 변수에 저장해서 이 함수에 사용할지 확실히 명시함으로써 이해하기 쉬운 코드를 작성하는데 도움이 되는 구문.

객체나 배열 내의 원소를 액세스하거나, 이름 또는 위치에 따라 무시하게 해줌. -> 이는 삭제와는 달라서 삭제되는 것이 아니며 우리가 작성하는 함수 또는 대상에 사용되지 않는 다는 뜻

 

함수 안

- name 속성만이 필요한 코드가 필요하다고 생각. 

- 객체에서는 속성 이름으로 이 값들을 추출.  

// <<Destructuring 이용XX>>
const person = {
    name: 'Max',
    age: 29,
    greet() {
        console.log('Hi, I am ' + this.name);
    }
};

const printName = (personData) => {
    console.log(person.name);
}

printName(person);
// 결과 값: Max

 

// <<Destructuring 이용O>>
const person = {
    name: 'Max',
    age: 29,
    greet() {
        console.log('Hi, I am ' + this.name);
    }
};

const printName = ({name}) => { // . 다른 속성은 무시되며 이 속성은 name이라는 변수로 저장되어 사용할 수 있음.
    console.log(name);
}

printName(person);
// 결과 값: Max

- 인수 목록에 {}(중괄호) 추가하여 관심있는 객체 속성을 명시. 

 

함수 밖

const person = {
    name: 'Max',
    age: 29,
    greet() {
        console.log('Hi, I am ' + this.name);
    }
};

const printName = ({name}) => {
    console.log(name);
}

printName(person);

const { name, age } = person; // name과 age 값이 저장된 새로운 const가 생성. person의 속성명과 입력한 값이 일치해야 함. 
// 윗 줄: 일반적으로는 틀린 문법이지만 구조 분해에서는 올바른 방법
console.log(name, age);
// 결과 값: Max 29

 

배열 구조 분해 

const hobbies = ['sports', 'Cooking'];
const [hobby1, hobby2] = hobbies; // hobby1과 hobby2를 대괄호로 묶은 const를 생성하고 이를 hobbies에 할당.
console.log(hobby1, hobby2); // 배열을 기록하게 하지 않아서 대괄호가 없음.
// 결과 값: sports Cooking

- 객체 구조 분해와 다르게 배열 구조 분해에서는 원하는 이름을 선택할 수 있다.

WHY?

- 배열에서는 원소들에 이름이 없고 위치를 기반으로 추출되기 때문. 따라서 hobby1은 항상 첫 번째 원소, hobby2는 항상 두 번째 원소.

비동기 코드와 프로미스


비동기 코드 

예시 1)

setTimeout(() => { // 내장된 타이머 함수. 1번째 인수는 할 내용, 2번째 인수는 타이머(<- 밀리초로 표현해야 해서 2초 = 2000 밀리초.)
    console.log('Timer is done!');
}, 1); // 비동기 코드

console.log('Hello!'); //동기 코드
console.log('Hi!'); //동기 코드

 

결과 값.

 

- 비동기화 코드는 1밀리초로 아무리 빠른 시간이라도 즉시 끝나지 않기 때문에 비동기화 코드임.

- 두 console.log 스니핏은 하드웨어를 제외하고는 딜레이가 존재하지 않으므로 동기화 코드.

- 결과 값으로 Hello, Hi! 가 Timer is done! 보다 빠르게 나오는데 이는 Node.js와 Javascript가 일반적으로 코드 실행이 종료될 때까지 기다리지 않는다. 즉, setTimeout() 에서 콜백 함수라고 하는 함수를 인식 -> 모든 동기화 코드를 실행 -> 비동기화 코드가 실행.

 

 

예시 2)

const fetchData = (callback) => {
    setTimeout(() => {
        callback('Done!');
    }, 1500);
};

setTimeout(() => {
    console.log('Timer is done!');
    fetchData((text) => {
        console.log(text);
    });
}, 2000); 

console.log('Hello!');
console.log('Hi!');

 

결과 값

- 중첩된 비동기화, 콜백함수를 사용할 때의 몇 가지 문제점. (인데,, 잘 안 쓴다고 하는데 호호 이해가 안되네.) 

 

프로미스

'웹 프로그래밍' 카테고리의 다른 글

PBL4 - 코드 분석  (0) 2023.09.14
[UDEMY] Node.js - Section(03)  (0) 2023.08.24
[UDEMY] Node.js - Section(01)  (0) 2023.07.07
[javascript] 생활 코딩 스터디 1주차 (1) [정리]  (0) 2023.03.12