헬창 개발자
자바스크립트 리마인드 본문
학습 목표
- 서버 통신을 위한 자바스크립트 밑바닥을 숙지해보자!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1. 자바스크립트 기본 문법
변수
- 자바스크립트는 동적언어이기 때문에, 변수 타입을 미리 선언할 필요가 없다.
- 타입은 프로그램이 처리되는 과정에서 자동으로 파악한다.
- 프로그램이 파악한 데이터 타입을 확인 하려면 typeof를 통해 확인해야한다.
- ES6 이후로 var대신 const, let을 사용하는것을 추천한다. → 변수 호이스팅, function-level-scope문제
호이스팅
아직 값이 없음에도 오류가 나지 않는 현상을 말한다.
자바스크립트의 데이터 타입에는 숫자, 문자, boolen, undefined, null이 있다.
그러면 변수가 어떻게 생성되며 어떻게 호이스팅이 이루어지는지 살펴보자
선언 단계(Declaration phase)변수를 실행 컨텍스트의 변수 객체(Variable Object)에 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.
초기화 단계(Initialization phase)변수 객체(Variable Object)에 등록된 변수를 위한 공간을 메모리에 확보한다. 이 단계에서 변수는 undefined로 초기화된다.
할당 단계(Assignment phase)undefined로 초기화된 변수에 실제 값을 할당한다.
변수는 위처럼 3단계에 걸쳐 생성된다.
var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
var puppy = "cute";
console.log(puppy);
//undefined
//cute
puppy라는 변수를 아직 선언하지 않은 상태에서 호출했는데 오류가 나지 않고 undefined라는 값을 반환한다.
이는 떡하니 변수값을 가지고 있지 않지만 떡하니 메모리 공간을 차지하고 있다는 것을 의미한다.
내가 아직 할당하지 않은 변수가 제 맘대로 참조할 수 있게 되어 있는 것이다.
→ let과 const를 사용하면 변수를 중복으로 선언 할 수 없어 변수 호이스팅 문제를 해결할 수 있다.
스코프
범위라는 뜻으로 변수에 접근할 수 있는 범위를 말한다.
함수 레벨 스코프(Function-level scope)
함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.
블록 레벨 스코프(Block-level scope)
모든 코드 블록(함수, if 문, for 문, while 문, try/catch 문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다.
- Function-level scope의 사용
function-level-scope란 함수의 블록 범위 내에서 선언한 변수는 함수 내에서만 인정하고 함수 외부에서 선언한 변수는 모두 전역변수가 된다는 뜻이다.var puppy = "cute"; console.log(puppy); // cute { var puppy = "so cute"; } console.log(puppy); // so cute
- Block-level scope의 사용
let과 const는 block-level-scope이다.let puppy = "cute"; { let puppy = "so cute"; } console.log(puppy); // cute
- 방금 전에 블록 내부에서 선언된 변수는 외부애 영항을 끼치지 않는다고 했다. 따라서 1행의 puppy와 5행의 puppy는 이름만 같을 뿐 다른 변수이다.
- const와 let의 특징
const는 값을 재할당할 수 없어 값을 변경할 수 없고 let은 값을 재할당할 수 있어 값을 변경할 수 있다. 이 외 나머지 기능은 비슷하다.const puppy = "cute"; puppy = "so cute!!"; // TypeError: Assignment to constant variable. let dog; console.log(dog); // undefined dog = "so lovely"; console.log(dog); // so lovely
클로저
function outer() {
var a = 'A';
var b = 'B';
function inner() {
var a = 'AA';
console.log(b);
}
return inner;
}
var outerFunc = outer();
outerFunc(); // B
클로저라는 개념은 내부 함수가 외부 함수의 스코프(범위)에 접근할 수 있는 것을 말한다.
자바스크립트에서 스코프는 함수 단위로 생성되는데 위 예제에서 inner()함수의 스코프가 outer()함수의 스코프를 참조하고 있고 outer()의 실행이 끝나고 소멸된 이후에도 inner()함수가 outter()함수의 스코프에 접근할 수 있는것을 클로저라고 한다.
객체와 배열
자바스크립트에서 객체는 key, value의 쌍을 이루어진 property의 정렬되지 않은 집합을 의미한다.
const country = {
name: "Korea",
population: "5178579",
get_name: function () {
return this.name;
}
};
객체가 가진 특징, 정보를 property라고 하고 위처럼 키:값 형태로 나타낸다.
그리고 객체는 property말고 행위를 가질 수 있는데 이는 객체안에 함수를 넣어 만들어 사용하는데 이를 메서드라고 한다.
배열안에는 숫자, 문자열, 객체 등 어떤 것이든 요소로 넣을 수 있고 .push()를 이용하여 원하는 요소를 넣을 수 있다.
const coffee = [];
coffee.push({ name: 'Americano' });
coffee.push({ name: "Latte" });
console.log(coffee); // [ { name: 'Americano' }, { name: 'Latte' } ]
console.log(coffee[0]); // { name: 'Americano' }
console.log(coffee.length); // 2
const animal = ['dog', 'cat'];
let [first, second] = animal;
console.log(first); // dog
console.log(second); // cat
‘구조 분할 할당’이라는 것이 있는데 위 처럼 객체나 배열을 변수로 간편하게 분해해주는 문법이다.
함수
function add(a, b) {
return a + b;
}
console.log(add(1, 4)); // 5
const add = (a, b) => {
return a + b;
}
console.log(add(1, 4)); // 5
function을 통해 선언하고 ()안에 파라미터를 지정하고 {}문 안에 로직을 작성하고 return을 통해 반환 값을 저장할 수 있다.
함수를 function대신 화살표 함수(Arrow Function)인 ⇒를 통해 선언할 수 있다. ( ES6부터 도입된 화살표 함수로 흔히 람다식이리고 한다.)
this의 사용
var people = {
name: 'gildong',
say: function () {
console.log(this);
}
}
people.say();
var sayPeople = people.say;
sayPeople();
//people.say();
{ name: 'gildong', say: [Function: say] }
//sayPeople();
<ref *1> Object [global] {
global: [Circular *1],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
queueMicrotask: [Function: queueMicrotask],
performance: Performance {
nodeTiming: PerformanceNodeTiming {
name: 'node',
entryType: 'node',
startTime: 0,
duration: 44.510300010442734,
nodeStart: 0.8840000033378601,
v8Start: 3.59620001912117,
bootstrapComplete: 29.489600002765656,
environment: 15.374400019645691,
loopStart: -1,
loopExit: -1,
idleTime: 0
},
timeOrigin: 1659796401810.695
},
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
}
}
peple.say()에서 people 객체가 say()를 호출했으므로 this는 people 객체가 되고 sayPeople 변수에 people.say를 넣고 호출한 경우는 전역변수→ 전역이 호출한 주체가 되므로 this는 전역 객체가 된다.
프로토타입과 상속
프로토타입의 뜻은 원형인데 자바스크립트로 객체 지향 프로그래밍을 할 수 있게 도와주는 것이다.
자바스크립트엔느 클래스가 없으므로 프로토타입을 통해 비슷하게 흉내낸다. → 자바스크립트가 프로토타입 기반 언어인 이유
Prototype을 사용하는 이유는
- 생성자 함수로 생성된 객체 모두에 프로퍼티, 메서드를 공유하기 위해서다.
- 상속을 구현할 수 있다.
- __proto__
- 모든 객체가 갖고 있는 프로퍼티
- 부모의 prototype 프로퍼티에 대한 정보를 의미 ( prototype link )
- prototype
- 함수만 갖고 있는 프로퍼티 ( 함수도 객체이므로 __proto__를 갖고 있음 )
- 자신의 prototype 객체이며 자식 객체는 이를 참조함
function func() { };
console.log(func.prototype); //func {}
func.prototype.name = 'gildong';
console.log(func.prototype); // func { name: 'gildong' }
const animal = {
leg: 4,
tail: 1,
say() {
console.log('I have 4 legs 1 tail');
}
}
const dog = {
sound: 'wang'
}
const cat = {
sound: 'yaong'
}
dog.__proto__ = animal;
cat.__proto__ = animal;
console.log(dog.leg); // 4
console.log(cat.leg); // 4
자바스크립트에서 기본 데이터 타입을 제와한 모든 것이 객체인데, 이 객체의 원형인 프로토타입을 이용해서 새로운 객체를 만들어 내고 이렇게 새로운 객체는 또 다른 객체의 원형이 되어 새로운 객체를 만들어 낼 수 있다.
2. 자바스크립트의 비동기 처리
콜백 함수
콜백은 말그대로 나중에 실행되는 코드를 의미한다.
자바스크립트에서 함수는 마지막으로 넘겨 받은 인자 콜백을 실행하는 매커니즘이고 여기서 인자로 들어가는 함수를 콜백 함수라고 한다.
- 콜백 함수의 비동기 처리
setTimeout(() => { // 내장 함수 setTimeout(callback, delayTime) console.log('todo: First work!'); }, 3000); setTimeout(() => { console.log('todo: Second work!'); }, 2000); // 결과 // todo: Second work! // todo: First work!
- 콜백 함수의 동기 처리
setTimeout(() => { setTimeout(() => { console.log('todo: Second work!'); }, 2000); console.log('todo: First work!'); }, 3000); // 결과 // todo: First work! // todo: Second work!
Promise
Promise는 코드의 중첩이 많아지는 콜백 지옥을 벗어날 수 있게 해주는 객체이다.
function workP(sec) {
// promise의 인스턴스를 리턴하고
// then에서 리턴한 것을 받는다.
return new Promise((resolve, reject) => {
// Promise 생성시 넘기는 callback = resolve, reject
// resolve 동작 완료시 호출, 에러 났을 경우 reject
setTimeout(() => {
resolve(new Date().toISOString());
//reject(new Error());
}, sec * 1000);
});
}
workP(1).then((result) => {
console.log('첫번째 작업', result);
return workP(1);
}).then((result) => { //promise chaining
console.log('두번째 작업', result);
});
//첫번째 작업 2022-08-11T07:20:58.421Z
//두번째 작업 2022-08-11T07:20:59.438Z
workP()라는 함수는 new 키워드를 통해 Promise의 인스턴스를 생성하여 반환한다. Promise를 생성할 때 resolve와 reject를 넘기게 되는데 여기서 resolve는 위에서 배운 콜백 함수와 비슷한것이고 workP()의 요청이 성공 하게 되는 경우 resolve함수를 호출하고 실패할 경우 reject 함수를 호출하게 된다.
async/await
Promise의 단점을 보완해주는 패턴이다.
asyncFunc() : async를 사용한 함수
function workP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Date().toISOString());
}, sec * 1000);
});
}
function justFunc() {
return 'just Function';
}
async function asyncFunc() {
return 'async Fucntion';
}
console.log(justFunc());
console.log(asyncFunc());
console.log(workP());
//just Function
//Promise { 'async Fucntion' }
//Promise { <pending> }
일반 함수인 justFunc()은 반환으로 준 문자열 just Function을 그대로 반환되지만 workP(), asyncFunc()는 둘다 Promise 객체를 반환하는 것을 확인 할 수 있다.
Promise를 사용하기 때문에 Promise 패턴에서처럼 함수를 호출 할 때 then()을 사용할 수 있다.
function workP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('workP function');
}, sec * 1000);
});
}
async function asyncFunc() {
const result_workP = await workP(3);
console.log(result_workP);
return 'async function';
}
asyncFunc().then((result) => {
console.log(result)
});
//workP function
//async function
await 사용법은 async 키워드를 붙인 함수 안에 lock을 걸어 놓고 싶은 부분에 await를 붙이기만 하면 된다.
원래 workP() 함수는 setTimeout() 함수를 이용했기 때문에 비동기적으로 처리되지만 await를 붙여 workP(3) 함수가 완료되기 전가지 그 밑 구문은 실행하지 않게 된다.
즉 async/await를 이용하게 되면 비동기로 처리하고 싶은 함수에 async를 붙이고, 비동기 처리를 할 특정 부분에 await를 붙이기만 하면 되니 Promise보다 직관적이고 많이 사용하게 되는 패턴 중 하나다.
비동기 상황에서의 예외 처리
자바스크립트 문법에 어긋났거나 문법이 맞더라도 자바스크립트 내부에 정의되지 않는 코드나 함수를 참조하는 경우 예외가 발생한다.
이때는 자바스크립트에서 자체적으로 오류를 발생하게 된다.
1. 사용자 정의 오류
function sum(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw 'type of arguments must be number type';
}
console.log(a + b);
}
sum(1, '4');
우리가 원하는 규칙은 두개의 인자 타입이 number여야 하고 그렇지 않을 경우 throw를 통해 예외를 발생시켰다.
이때의 오류는 자바스크립트 내부에서 발생시키는 예외가 아닌 우리가 직접 정의해준 오류이다.
2. 일번적인 예외 처리
// catch 해주지 않은 부분은 실행되지 않음
function f2() {
console.log('this is f2 start');
throw new Error('에러'); // Error 객체 - 해당하는 콜스택 정보가 담겨있다.
console.log('this is f2 end'); // 실행되지 않음.
}
function f1() {
console.log('this is f1 start');
try {
f2();
} catch (e) {
console.log(e);
}
console.log('this is f1 end');
}
f1();
//this is f1 start
//this is f2 start
//Error: 에러
//this is f1 e
예외가 발생할 수 있는 부분을 try() 함수 내에 넣고 try()내부에서 예외가 발생한다면 그 예외를 어떻게 처리할 것인지 catch()부분에서 처리를 해준다.
3. 비동기 상황에서의 예외 처리
- Promise의 catch()이용하기
Promise가 포함되어 있는 함수의 실행부 뒤에 .catch(e ⇒ 를 통해 오류를 잡아 주면 된다.function wait(sec) { return new Promise((resolve, reject) => { setTimeout(() => { reject('error!'); }, sec * 1000); }); } wait(3).catch(e => { console.log('1st catch ', e); });
- Promise의 then()이용하기
wait(3).then(() => { console.log('Success'); //성공했을 경우 }, e => { console.log('Catch in then', e); //실패했을 경우 })
- Promise의 async/await의 예외 처리
async 함수를 사용할 경우 Promise와 동일하게 예외 처리를 해주면 된다.async function myAsyncFunc() { throw 'myAsyncFunc Error!'; } function myPromiseFunc() { return new Promise((resolve, reject) => { reject('myPromiseFunc Error!'); }); } const result = myAsyncFunc().catch(e => { console.log(e) }); const result2 = myPromiseFunc().catch(e => { console.log(e) });
function wait(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('throw Error!');
}, sec * 1000);
});
}
async function myAsyncFunc() {
console.log(new Date());
try {
await wait(2); // Promise를 기다리는 중...
} catch (e) {
console.error(e);
}
console.log(new Date());
}
const result = myAsyncFunc();
await를 사용했을 경우 try catch 또는 .catch를 사용하면 된다.
await 구문을 사용하게 되면 예외가 발생되는 시점이 try가 감싸고 있는 시간과 일치하기 때문이다.
'공부방' 카테고리의 다른 글
npm 명령어와 node.js 모듈의 관하여 (0) | 2022.08.17 |
---|---|
자바스크립트 동기/비동기 부셔버리기 (0) | 2022.08.12 |
Node.js 첫걸음 (0) | 2022.07.26 |
[운영체제] 프로세스란????????????????????? (0) | 2022.04.24 |
백준 15781번 헬멧과 조끼 : 파이썬 (0) | 2021.12.29 |