728x90
바인딩
암시적 바인딩 (Implicit Binding)
객체 내부에 메서드를 가지는 경우. this = 객체
const implicit = {
name: 'Aaron',
method: function() { console.log(this.name) },
method_shorten() { console.log(this.name) }, // 콜론, function 생략 가능. 축약형
}
implicit.method() // Aaron
implicit.method_shorten() // Aaron
명시적 바인딩 (Explicit Binding)
this를 사용하는 함수에 명시적으로 객체를 할당해주면 메서드가 된다.
call, bind, apply 사용하여 명시적 바인딩이 가능하다. 그러나 일시적으로만 바인딩된다.
const explicit = {
name: 'Aaron',
}
function method() { console.log(this.name) }
method.call(explicit) // Aaron 엮기 + 실행
method.bind(explicit)() // Aaron 엮고, 실행은 따로 해주어야 함.
method.apply(explicit) // Aaron 엮기 + 실행
자바스크립트 객체
자바스크립트 객체는 new 키워드를 쓰지 않고, {} 내부에 메서드 + 필드를 정의한 json 형식으로 객체를 만들 수 있다.
- 필드는 명시적 정의 혹은 암시적 정의
- 명시적 정의 -> {} 내부에서 필드명을 써주기
- 암시적 정의 -> 생성자 안에서 this 접근자를 사용해 값 할당
- private의 경우 암시적 정의 해서는 안된다. 오류 발생
- private 필드, 메서드
- 필드명 혹은 메서드명 앞에 #을 붙인다.
class User {
#first_name;
#last_name;
constructor(first_name, last_name) {
this.#first_name = first_name;
this.#last_name = last_name;
}
information() {
console.log(`${this.#fullname} - 사람 이름 입니다.`)
}
get #fullname() {
return `${this.#first_name} ${this.#last_name}`;
}
set fullname(value) {
[this.#first_name, this.#last_name] = value.split(" ")
}
}
const user = new User('Aaron', 'Ryu');
user.fullname = 'Aaron Ryu'
Object.getOwnPropertySymbols(user)
console.log(user.first_name) // undefined
console.log(user.last_name) // undefined
console.log(user.fullname) // undefined
console.log(user.information()) // 'Aaron Ryu - 사람 이름 입니다.'
- 자바스크립트의 getter와 setter는 get, set 키워드를 사용해서 만들 수 있다. 또한 getter, setter 사용 시 메서드를 호출하는 것이 아닌, 필드를 호출하는 것처럼 보인다.
- 자바스크립트에서는 동일한 이름을 가지는 private, public 필드를 만들 수 있다. 둘은 # 키워드를 사용해 구분되며, 서로 다른 필드로 취급되기 때문에 주의해야 한다.
- 위 코드에서 user.first_name이라는 필드에 접근한 것처럼 보인다. 그러나 이는 private 필드에 접근한 것이 아닌, 동명의 public 필드에 대해서 접근하려는 시도이므로 존재하지 않는 필드에 접근한 것이다. 그래서 undefined가 출력되었다.
스크립트
- 스크립트는 쪼개서 여러 개 넣을 수 있다.
- 단, 위에서 넣은 것부터 순차적으로 가져오게 된다.
- 의존성 문제 때문에 맨 위에는 라이브러리 관련된 script 넣어야 한다.
- script 태그
- 성능 문제
- 의존성 관리 어려움 -> 개발자가 신경써서 순서를 맞춰서 넣어줘야 한다.
- 전역 스코프 문제 -> 전역 스코프로 변수 이름 충돌이나 오염 발생
- 코드 재사용의 어려움
- 라이브러리 스크립트의 성능 문제
- 다운로드의 문제
- 실행의 문제
- DOM 로드 지연
- 다운 받은 js 파일 모두 로드 및 실행을 하는 데 오랜 시간이 소요됨
- DOM 접근 불가
- 다운 받은 js 실행 시 스크립트 아래 위치한 DOM 요소에 접근 불가능
- 스크립트 로드 시점 DOM 로드에 의존
- 스크립트가 html 아래에 존재하는 경우, DOM 완성이 될 때까지 스크립트 늦게 실행
- DOM 로드 지연
- 성능 개선 방법론
- 비동기로 script의 라이브러리를 다운로드
스크립트 성능 개선 방법론
- Defer : 실행 지연 스크립트
- DOM 요소가 모두 파싱 완료될 때까지 로딩된 스크립트를 실행하지 않는다.
- 보통 큰 스크립트부터 작은 스크립트 순차적으로 실행함. (실행 순서 보장)
- 사용 예시
- DOM 요소 접근이 필요한 경우
- 스크립트 파일끼리 의존성을 가지는 경우 (순서 보장이 필요한 경우)
- Async : 실행 비동기 스크립트
- 스크립트 로딩이 끝나면, DOM 요소의 파싱 작업을 멈추고 바로 스크립트를 실행한다.
- 실행 순서 비보장. Load-First Order (먼저 로드된 스크립트부터 실행)
- 사용 예시
- 방문자 수 카운터, 광고 관련 스크립트
- 독립적인 역할을 하는 서드파티 스크립트에 적합
ESM vs CJS
- ESM (ECMAScript Modules) : import / export
- 모듈 스코프 지원. 전역이 아닌 필요한 모듈만 가져다 쓸 수 있도록 함
- 브라우저에서 import와 export를 완벽하게 지원하지 않아 Webpack과 같은 모듈 번들러 함께 사용
- 비동기 동작 지원. => 다운로드와 실행의 분리 => 보다 간편한 비동기 처리를 위한 Top-Level-Await 지원
- import는 디스크 혹은 네트워크에서 데이터를 비동기적으로 먼저 읽어온다 (= 파싱)
- 실행 전에 모두 파싱 => 높은 보안.
- 파싱은 정적 분석에 사용된다.
- 정적 분석
- 실행 불필요
- 문법 오류 및 잠재적 버그 발견
- 모듈 의존성 분석
- Tree shaking
- 정적 분석을 통하여 사용되지 않는 모듈을 제외한 번들링. => 파일 크기를 줄이고 성능을 높임
- named export : 이름을 붙여서 export
- => 꼭 그 이름으로만 import 해야 한다.
- default export : 명칭 변경 가능
- => 한 파일에 하나만 export
- CJS (Common JS) : required / module.exports
- 웹 브라우저가 아닌 웹 서버에서 자바스크립트 모듈을 쓰려면 파일 단위 모듈화가 절실하다.
- 변수 함수의 모듈화 필요
- Node에서는 CJS가 지배적이다.
- 비동기 동작 미지원. => 동기로 동작. 로드와 실행이 동시 => Top-Level-Await 미지원
- 필요할 때마다 가져와서 쓰기 때문에 정적 분석 불가능
- 일반적으로 CJS는 Node.js(서버)에서 사용, ESM은 브라우저에서 사용
- CJS를 지원하는 것이 중요한 이유 : Next.js 활용한 SSR 사용 서비스를 위해 CJS 지원 필요
- ESM을 지원하는 것이 중요한 이유 : Tree-shaking을 지원하는 ESM이 브라우저 성능에 중요
+) 리액트 사용 시 Webpack 아닌 Vite를 사용한다. Vite는 알아서 필요한 라이브러리들을 Tree-Shaking한다.
Callback
- 함수를 파라미터로 넘겨서, 필요할 때 사용할 수 있도록 실행권을 해당 함수로 위임한다.
- 콜백 그 자체로는 어떠한 비동기적인 함의도 없다.
- 다만 비동기는 언제 끝날지 모르기 때문에 콜백이 필요함
- 비동기에게는 콜백이 가장 필수적인 요소임
- 콜백 지옥의 원인
- 이전 콜백함수의 리턴값이 다음 콜백 함수의 파라미터로 사용되기 때문에.(실행에 필요하기 때문에)
Promise
Promise = Callback + Asynchronous
즉, 프로미스는 비동기를 포함한 콜백
프로미스를 Producer-Consumer Pattern on Asynchronous라고 하기도 한다.
- Executor (실행자) = Asynchronous (Callee) = Producer. 파라미터를 주입
- Executee (피실행자) = Callback = Consumer. 파라미터를 받아 수행됨.
Callee가 Callback에게 파라미터를 넘겨주기까지 딜레이 발생
=> 비동기 처리
Promise 상태
- pending : 초기 상태 => 프로미스에 값이 담기지 않은 상태
- fulfilled : 성공 상태 => then 내부에 정의된 resolve(성공 콜백)로 처리
- rejected : 실패 상태 => catch 내부에 정의된 reject(실패 콜백)로 처리
Promise 처리 방식 (체이닝)
- then : 내부에 성공 콜백 정의
- catch : 내부에 실패 콜백 정의
- finally : 내부에 성공, 실패 상관 없는 콜백 정의
- new Promise(pending).then(resolve).catch(reject)
- then, catch, finally로 나누는 이유는 다음과 같다.
- 체이닝이 가능함
- 콜백을 다양하게 사용할 수 있다. (인터페이스를 사용하는 것처럼)
- Promise 체이닝에서 리턴값은 항상 프로미스로 감싸져있기 때문에 체이닝이 가능하다.
- await
- Promise가 처리될 때까지 기다린다.
new Promise((resolve, reject) => { // caller 함수 (asynchronous 함수). Promise 정의 하자마자 실행됨.
const result = producing()
if (result.success) resolve(result.body) // resolve를 반환하면, then이 콜백함수의 파라미터로 받아서 사용
if (result.failed) reject(result.error) // reject를 반환하면, catch가 콜백함수의 파라미터로 받아서 사용
})
.then((body) => { consuming(body) }) // then 내부에 성공 콜백 함수
.catch((error) => { consuming(error) }) // catch 내부에 실패 콜백함수
// Promise Chaining 무한으로 가능. 항상 Promise로 감싸져 있다.
// Promise.resolve 혹은 Promise.reject를 반환. (만약 아직 실행되지 않았다면, pending 상태의 Promise)
Promise 비동기 함수의 구동 시점
- 프로미스 안의 비동기(Asynchronous = Caller = Executor) 함수는, 프로미스 정의 시 구동된다.
- 주의 : await 했을 때가 아님. await은 그저 값을 받으려고 기다리는 것 뿐임.
Promise 사용 시 주의사항
- Promise Hell 방지를 위해서, then 내부에서 다음 콜백을 호출하지 않는다.
- 현재 콜백함수의 실행 값(리턴값)을 다음 콜백함수의 파라미터로 넘겨주기 위해서는 Promise Chaining을 활용한다.
- 그렇지 않은 경우 무조건 반환을 위해서는 return 대신 resolve를 사용해 반환한다.
- 실패 시에는 reject를 사용해 반환한다.
728x90
'ASAC' 카테고리의 다른 글
Docker Image와 Github Actions를 사용한 CI/CD 자동화 (1) | 2024.10.30 |
---|---|
[ASAC 06] Docker, CI/CD 기본 개념 (1) | 2024.10.28 |
[ASAC 06] 자바스크립트 일급함수, Hoisting, Scope Chaining (0) | 2024.10.16 |
[ASAC 06] AWS VPC와 서브넷 구성 / Bastion Tunneling, NAT (6) | 2024.10.08 |
[ASAC 06] GitHub 명령어 정리 (1) | 2024.09.27 |