0. 기초지식
1) 동기/ 비동기
- 동기 : 서버에 요청을 보냈을 때 응답이 돌아와야 다음 동작을 수행
- 비동기 : 응답 상태와 상관없이 다음 동작을 수행
- 비동기적으로 처리하는 경우
- Ajax Web API 요청 : 서버쪽에서 데이터를 받아와야 하는 경우
- 파일 읽기 : 서버에서 파일을 읽어야 하는 경우
- 암호화/복호화 : 바로 처리되지 않고, 어느정도 시간이 걸리는 경우
- 작업 예약 : setTimeout을 사용하여 비동기 처리 하는경우
- JS는 동기적 언어이지만 비동기적으로 작동할 수 있게 할 수 있다.
2)비동기 처리 방식
2-1)콜백 지옥
- 콜백 함수는 함수 안에서 어떤 특정 시점에 호출되는 함수를 말한다.
- 그림과 같이 콜백 함수를 연속적으로 사용할 때 가독성이 매우 떨어진다.
2-2)Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error());
}, 1000);
});
myPromise
.then(n => {
console.log(n);
})
.catch(error => {
console.log(error);
});
- ES6부터 도입된 비동기를 좀더 편히 처리하기 위한 기능
- resolve는 new Promise가 만들어 질 때 자동으로 실행된다.
- resolve와 reject는 JS가 자체적으로 제공하는 콜백
- resolve : 작업이 성공한 경우, 결과를 나타내는 value와 함께 호출
- reject : 에러 시 error와 함께 호출
- Promise의 3가지 상태(state)
- Pending : 대기, 비동기 처리 로직이 아직 완료되지 않은 상태
- Fulfilled : 성공
- Reject : 실패
2-3)async/await
async function logTodoTitle() {
try {
var user = await fetchUser();
if (user.id === 1) {
var todo = await fetchTodo();
console.log(todo.title); // delectus aut autem
}
} catch (error) {
console.log(error);
}
}
- ES8문법으로 가장 최근에 나왔으며, 콜백함수와 promise의 단점을 보안하고 읽기 좋게 해준다.
- 함수 앞에 async를 붙이고, 호출할 비동기 함수 앞에 await를 붙인다.
- async를 붙이면 해당 함수는 항상 promise를 반환
- await를 만나면 promise가 처리 될 때 까지 기다린다.
3) 클로저
3-1) 어휘적 범위 지정(Lexicla Scoping)
function init() {
var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
function displayName() { // displayName() 은 내부 함수이며, 클로저다.
alert(name); // 부모 함수에서 선언된 변수를 사용한다.
}
displayName();
}
init();
- 위 코드 처럼 init 함수 내부에 있는 diplayName이 init 함수의 name을 가져다 쓸 수 있다.
- 만약 diplayName에도 name이 있다면 this.name으로 써야할 것이다.
- 이렇게 함수가 중첩된 상황에서 어떻게 변수를 처리하는 지 알 수 있으며 '어휘적 범위 지정'의 예다.
- "lexical"이란 어휘적 범위 지정 과정에서 변수가 어디에서 사용 가능한지 알기 위해 그 변수가 소스코드 내에서 어디에서 선언되었는지 고려한다는 것을 의미한다.
- 중첩된 함수는 외부 범위에서 선언한 변수에도 접근할 수 있다.
3-2) 클로저 예시
function makeAdder(x) {
var y = 1;
return function(z) {
y = 100;
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
//클로저에 x와 y의 환경이 저장됨
console.log(add5(2)); // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
//함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산
//클로저와는 관계 없지만 아래와 같이 작성해도 실행된다.
console.log(makeAdder(5)(2))
- add5와 add10은 둘다 클로저이다. 함수 본문 정의는 공유하지만 서로 다른 맥락적 환경을 저장
- 리턴되는 함수에서 y는 1에서 100으로 변경된다. 이는 클로저가 리턴된 후에도 외부함수의 변수들에 접근 가능한 것을 보여주는 것이며, 클로저에 단순히 값 형태로 전달되는 것이 아니라는 것을 의미한다.
- 클로저는 어떤 데이터(어휘적 환경)와 그 데이터를 조작하는 함수를 연관시켜주기 때문에 유용하다.
- 결론적으로 오직 하나의 메소드를 가지고 있는 객체를 일반적으로 사용하는 모든 곳에 클로저를 사용할 수 있다.
3-3) 클로저를 활용하여 프라이빗 메소드 흉내내기
- 자바처럼 해당 클래스가 가지는 함수를 호출하는 것처럼 보여질 수 있다.
var counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
})();
console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1
3-4) 클로저 스코프 체인
- 세가지 범위
- 지역 범위(Local Scope, Own scope)
- 외부 함수 범위(Outer Functions Scope)
- 전역 범위(Globalscope)
// 전역 범위 (global scope)
var e = 10;
function sum(a){
return function sum2(b){
return function sum3(c){
// 외부 함수 범위 (outer functions scope)
return function sum4(d){
// 지역 범위 (local scope)
return a + b + c + d + e;
}
}
}
}
console.log(sum(1)(2)(3)(4)); // log 20
var s = sum(1);
var s1 = s(2);
var s2 = s1(3);
var s3 = s2(4);
console.log(s3) //log 20
1. 기초지식 문제와 해답
- Node.js를 한마디로 정의하면?
- javaScript 런타임 플랫폼
- 자바스크립트에서 비동기를 동기처럼 처리할 수 있는방법
- callback
- Promise
- async/await
- async () => 'Value' 를 일반 함수 표현식으로 표현해주세요.
- () => Promise.resolve('Value')
- +'1234' 의 반환 값은 무엇인가요?
- 1234
- 연산자에 의해 숫자로 캐스팅 된다
- +10 -> 1* 10 -> 10
- -10 -> -1 * 10 -> -10
- -(-10) -> -1 * -10 -> 10
- 1*'1234' -> 1 * Number('1234') -> 1234
- 함수 바깥, 후행에 선언된 변수를 함수 안에서 참조할 수 있는 이유는?
- Hoisting이 일어나 변수는 이미 선언된 상태이므로 구문 해석시 문제가 발생하지 않는다.
- try-catch 안에 있는 async 함수에서 await 키워드를 사용하지 않았을 때 에러가 발생하면 어떻게 동작하나요?
- await 키워드가 없으면 프로미스에 reject를 별도로 달지 않았을 경우 에러는 유실된다.(unhandledRejection)
- https://stackblitz.com/edit/typescript-agy2dp.
- Arrow function에서의 this와 일반 Function에서의 this가 다르게 동작하는 이유는?
- Arrow function은 lexical scope로 동작하며, 일반 Function은 Dynamic scope로 동작하기 때문이다.lexical scope로 동작하게 되면 변수/함수가 정의된 위치의 context를 사용하며, dynamic scope로 동작하게 되면 변수/함수가 호출된 위치의 context를 사용한다. (관심사가 다름)dynamic scope로 동작하는 함수는 원하는 context를 별도로 주입할 수 있다.(apply, call, bind)
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions.
- Closure란 뭔가?
- 자바스크립트는 함수를 리턴하는 경우 클로져를 형성해서 리턴한다.클로져가 생성될 때 하나의 환경이 만들어지는데, 유효 범위 내에 있는 모든 지역 변수가 포함된 환경이 구성된다. 이 환경을 lexical environment 라고 부른다.한마디로, 클로져는 lexical environment와 function의 조합이라고 볼 수 있다.
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures.
- Q. 자바스크립트가 Closure를 이용해 private property를 구현 할 방법은?
- lexical environment에서만 존재하는 변수를 조작할 수 있도록 클로져에서 별도의 함수를 내보낸다.IIFE를 이용하면 간단하게 가능하다.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#emulating_private_methods_with_closures .
3. 참고 자료
1)동기/비동기 : https://velog.io/@daybreak/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC
2)비동기화 하는 JS방법 : https://velog.io/@daybreak/Javascript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC
3)클로저,어휘적 범위 지정 등 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures#let%EA%B3%BC_const%EB%A5%BC_%EC%82%AC%EC%9A%A9%ED%95%9C_%EB%B2%94%EC%9C%84_%EC%A7%80%EC%A0%95