<script src="./00/index.js"></script>
<script async src="./00/index.js"></script>
<script defer src="./00/index.js"></script>
async 를 사용하면 html을 파싱하는 동안 스크립트를 만나게 되면 파싱을 계속 진행하면서, 스크립트를 다운 받게 된다. 스크립트 다운로드가 완료되면 해당 스크립트를 실행하고, 실행하는 동안 HTML 파싱은 멈춘 후 스크립트 실행이 끝난 후 문서를 일게된다.
하지만 async는 순서가 보장이 되지 않는다는 단점이 있다.이것을 해결하기 위한 defer 이다.
defer는 스크립트를 만났을 때, html 파싱을 멈추지 않고, 끝까지 수행한 후 </html>
을 만났을 때 실행된다. html 파싱을 모두 끝낸 후에 스크립트를 실행하기 때문에 dom 요소를 사용하는 코드가 제대로 동작하지 않았을 때의 문제가 해결된다.
let num = 42;
let name = 'john';
let isTrue = true;
let person = {name: 'Alice', age: 30};
let fruits = ['apple', 'banana', 'orange'];
[num, name, isTrue, person, fruits].forEach((element) => {
console.log(typeof element);
});
let length = 16; // Number
let lastName = 'Brown'; // String
let score = [10, 20]; //
let x = {
firstName: 'Nick',
lastName: 'Doe',
}; // Object
let fruits2 = fruits;
console.log(fruits === fruits2) //true
console.log(type of f2) // object, 사실은 배열인데 버그임
==
과 ===
==
) : 피연산자들의 데이터 같으면 참을 반환(자료형 검사 x)===
): 피연산자들의 데이터가 같으면 참을 반환 (자료형 검사o)B1 &&(and) B2 : B1이 참이면 B2 실행
조건문은 if문, switch문
let lamp = false;
if (lamp === true) {
console.log('The lamp is on');
} else {
console.log('The lamp is off');
}
const area = '서울';
switch (area) {
case '서울':
console.log('서울입니다.');
break;
case '경기':
console.log('경기입니다.');
break;
case '제주':
console.log('제주입니다.');
break;
default:
console.log('서울, 경기, 제주 중에 선택해주세요');
break;
}
const f1 = ['a', 'b', 'o'];
let i = 0;
while (i < fruits.length) {
console.log(fruits[i]);
i++
}
for (let index of arr) {
console.log(index); // index는 배열의 index값이 나온다.
}
for (let key in obj) {
console.log(key); // key는 객체의 key값이 나온다.
}
for(let index in arr) {
console.log(index) // index는 배열의 index 값이 나온다.
}
//함수 선언식
function func(){}
//함수 표현식
const func = function(){} //익명함수
const func2 = function sum() {}// 네이밍 함수
//화살표 함수
const func = () => {}
//생성자 함수
const newFunc = new Function()
함수 표현식은 호이스팅이 가능하다
함수 선언식은 let, const로 선언할 시 호이스팅이 불가능하다.
js 코드의 선언문을 최상단을 올리는 것
console.log(a) // undefined
var a = 10;
console.log(a) //10
a는 error가 떠야하는 undefined가 뜬다 호이스팅이 작동한다는 증거이다
함수 선언은 전체가 호이스팅 돼서 함수 선언 전에 호출이 가능하다.
console.log(add(2,3))//5
function add(x,y){
return x+y
}
실행 컨텍스트는 자바스크립트가 실행되기 위해 필요한 환경을 제공하는 객체이다.
모든 소스코드는 실행에 앞서 평가 과정을 거치며 코드를 실행하기 위한 준비를 한다.
즉 '소스코드 평가', '소스코드 실행' 과정으로 나누어 처리한다.
자세히 풀어쓰면 실행 컨텍스트는 식별자(변수, 함수, 클래스 이름)을 등록하고 관리하는 스코프와 코드 실행 순서를 관리하는 구현한 내부 매커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리한다.
식별자와 스코프는 실행 컨텍스트의 렉시컬 환경으로 관리하고 실행 순서는 실행 컨텍스트 스택으로 관리한다.
실행 컨텍스트를 생성하는 방법은 아래와 같다.
1. 전역 컨텍스트: 자바스크립트가 로드되면 생성되고 스크립트가 종료될때까지 유지된다.
2. 함수 컨텍스트: 함수를 호출할때 생성된다.
3. eval 컨텍스트: eval 함수를 호출할때 생성된다.
4. 모듈 컨텍스트: 모듈 코드가 실행될때 생성된다.
let hello = 'hi'
function speak() {
let hello = 'bye'
console.log('^^')
}
speak()
console.log('end')
let이 변수 중복되는 것처럼 보이지만 그렇지 않다.
환경이 다른 컨텍스트이기에 즉 스코프(유효범위)가 다르기에 speak 함수가 실행될 때 콜스택에 새로운 컨텍스트가 생성되고 거기서 hello가 쓰인 후 speak 함수가 끝나면 hello 변수도 사라진다. 전역 컨텍스트에 전역변수로 선억된 hello는 남아있다.
function outer() {
let x = 10;
function inner() {
let a = x
console.log(x) // 아우터를 통해 외부 스코프인 outer 변수의 x에 접근
}
inner()
}
outer() // 10
스코프 체인으로 통해 내부에서 외부 변수에 접근 가능하다.
하지만 밖에서는 내부에 접근이 가능하지 않다.
이때 클로저는 외부 함수가 종료되었음에도 내부 함수에서 외부함수에 선언된 변수를 여전히 참조할 수 있는 현상이다.
const도 이미 할당된 값을 변경하는 건 가능하다.
const user = {}
user.name = 'abc'
user.name = '1'
const.log(user.name) //1
delete user.name
user.name = '3'
console.log(user.name) //3
user의 주소값이 변경하는 것이 아니기 때문에 가능 const는 재할당 할 수 없고 속성값만 변경할 수 있다.
왜냐 객체이니까 참조형이라 가능하다.
자신을 호출한 객체를 가리킨다.
const person = {
name: 'Alice',
age: 30,
speak() {
console.log(`hello ${this.name}`);
},
};
함수를 사용해서 객체를 생성하는게 생성자 함수
기본형태가 함수이기에 매개변수를 사용할 수 있다.
생성자함수는 대문자로 시작
변수 생성 키워드는 this를 사용
function Person(name, age){
//this= {} this에 빈 객체가 생성되는게 생략되어있다.
this.name = name
this.age = age
//return this가 생략되어 있다.
}
//호출 시 new 연산자와 함께 사용
let person = new Person('jin', 30)
console.log(person)
모든 함수는 prototype 이라는 속성을 가지고 있으며, 이를 통해 해당 함수로 생성된 객체들이 공통으로 사용할 메서드와 속성을 정의할 수 있다.
[[prototype]]
객체에 정의된 메서드와 속성은 해당 생성자 함수로 생성된 모든 인스턴스에서 공유된다. 이는 메모리 효율성을 높이고 코드 재사용성을 증가시킴function Person(name, age){
//this= {} this에 빈 객체가 생성되는게 생략되어있다.
this.name = name
this.age = age
//return this가 생략되어 있다.
}
Person.prototype.greet = function () {
console.log(`hello my name is ${this.name}`)
}
//호출 시 new 연산자와 함께 사용
//인스턴스 생성
let person = new Person('jin', 30)
let person2 = new Pseron('kim', 20)
console.log(person)
person.greet() // hello my name is jin
person2.greet() // hello my name is kim
// 두 객체는 서로 같지 않음
console.log(person === pseron2) // false
//그러나 프로토타입 객체는 같음
console.log(person.__proto__ === person2.__proto__) //true
원래 생성된 인스턴스 프로토타입에 접근할 때 pseron.__proto__.grett()
이렇게 접근해야하지만 생략해도 접근하게 설게됐다.
Objetct -> Person prototype object -> function Person() {} -> person 으로 __proto__
가 브릿지 역할을 한다.
call() 함수를 호출하여 특정 객체를 함수 내에서 this로 사용할 수 있도록하는 메서드 call() 첫번째 매개변수는 함수 내에서 사용할 this객체를 전달 받고, 두 번째 매개변수는 호출할 함수에 전달된다.
function Shape(color) { this.color = color; this.getColor = function () { return this.color;
};
}
function Rectangle(color, width, height) {
Shape.call(this, color); // 부모 생성자 함수 호출 즉 Shape 호출 call(this, color)로 Shape의 this.color로 넘겨진다.
this.width = width;
this.height = height;
this.getArea = function () {
return this.width * this.height;
};
this.getColor = function () {
return this.color;
};
}
const rect2 = new Rectangle(10, 20, 'blue');
console.log(rect2.getColor());
### 클래스
> 클래스는 class 키워드를 사용해서 선언
> 내부에 constructor 메서드를 가지고 있다.
> sugar syntax라고 부름
```javascript
class Shape {
constructor(color, width, height) {
this.color = color;
this.width = width;
this.height = height;
}
getColor() {
return this.color;
}
}
const shape1 = new Shape();
shape1.color = 'red';
console.log(shape1.getColor());
class Rectangle extends Shape {
constructor(color, width, height) {
super(color); //자신이 상속받은 클래스의 생성자를 호출
this.width =width
this.height =height
}
getArea() {
return this.width * this.height;
}
}
const rect1 = new Rectangle('blue', 20, 20);
console.log(rect1.getColor());
console.log(rect1.getArea());
자식클래스에서 메서드 재정의하기
class Rectangle extends Shape {
constructor(color, width, height) {
super(color);
this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height;
}
getColor() { //오버라이딩
return 사각형은 ${this.color}색입니다.
;
}
}
console.log(rect1.getColor()); //사각형은 blue색입니다.
#### setter, getter
>set: 값을 설정하는 메서드
>get: 값을 가져오는 메서드
set 키워드가 추가된 이후 speed 의 값이 세팅= 할당에는 무조건 set이 관여한다.
```javascript
class Car {
constructor(speed) {
this.speed = speed;
}
getSpeed() {
return this.speed;
}
set speed(value) {
this.speed = value;
}
}
const car1 = new Car(-100);
console.log(car1.getSpeed());
speed에 _
를붙여 getter, setter 변경하면 에러가 나지 않는다. 관례상 언더바를 사용 클래스의 speed는 _speed
가 됨
class Car {
constructor(speed) {
this.speed = speed;
}
getSpeed() {
return this._speed;
}
set speed(value) {
this._speed = value < 0 ? 0 : value;
}
}
const car1 = new Car(-100);
console.log(car1.getSpeed());
console.dir(car1);
이럴 경우 문제가 this.speed 참조가 불가능하기에 코드 수정을 해야한다. 그래서 getter 사용하여 기존 코드 수정 없이 속성 값을 설정하고 읽기 가능
class Car {
constructor(speed) {
this.speed = speed;
}
getSpeed() {
return this.speed;
}
set speed(value) {
this._speed = value < 0 ? 0 : value;
}
get speed() {
return this._speed;
}
}
const car1 = new Car(-100);
console.log(car1.getSpeed());
console.dir(car1);
외부에서 해당 속성에 접근해 바꾸려할때는 private 선언을 한다. 그래서 외부 은닉, 캡슐화 를 실행
class Car {
#speed; // private
constructor(speed) {
this.#speed = speed;
}
getSpeed() {
return this.#speed;
}
setSpeed(value) {
this.#speed = value < 0 ? 0 : value;
}
}
const car1 = new Car(-100);
console.log(car1.getSpeed()); // 0
car1.setSpeed(150);
console.log(car1.getSpeed()); // 150
console.dir(car1); // #speed 비공개 속성은 콘솔에서 보이지 않습니다.
static 키워드를 사용해 정의된 속성이나 메서드를 클래스 자체에 속하면, 인스턴스가 아닌 클래스 이름을 통해 접근할 수 있다. 이는 인스턴스를 생성을 하지 않아도 사용할 수 있다.
class MathUtils {
static APP_NAME = "Math Utils";
constructor(number) {
this.number = number;
}
static add(a) {
return ++a;
}
}
const mathInstance = new MathUtils(10);
console.log(MathUtils.APP_NAME); // Math Utils
console.log(mathInstance.APP_NAME); // undefined
console.log(MathUtils.add(10)); // 11
기본 자료형을 객체로 다루기 위해 js의 숨겨진 기능
number-> Number()
string -> String()
boolean -> Boolean()
기본자료형들을 객체와 같은 참조 자료와 같은 접근을 할 때 하나의 객체로 감싸버린다.
const a = 'hello'; // a는 기본자료형이다.
const b = new String('hello'); //객체로 래핑된다.
console.log(a.length);
자동으로 래퍼 객체로 변환되기에 toFiexd, toString 메소드를 사용할 수 있다.
메서드 사용 후 다시 기본자료형으로 변환된다.
push,shift,unshift,join,sort,reverse
자주쓰는 문자 내장 객체
split, charAt, concat, indexOf, includes, slice
자바스크립트의 클로저는 내부 함수에서 외부함수를 가리키는 기능
함수 실행 컨텍스트가 종료되지 않는 코드적 특징 일종의 스냅샷을 찍는 현상
클로저는 내부 함수가 자신이 선언된 환경의 외부 변수들을 기억하고, 함수 실행 컨텍스트가 종료된 후에도 그 변수들에 접근할 수 있게 해준다.
let i = 0;
function outer() {
return function inner() {
return ++i;
};
}
const counter = outer();
console.log(counter()); //1
console.log(counter()); //2
console.log(counter()); //3
클로저는 참조값이 가비지 컬렉터의 수거대상이 되지 않으므로 메모리 소모가 존재한다.
웹페이지의 구조화된 표현을 의미하며, 웹 브라우저가 HTML 문서를 자바스크립트로 제어할 수 있도록 객체로 변환된 형태
dom은 트리자료구조로 tree 구조 특징은 루트라는 최상단이 있고 나무처럼 가지가 뻗어나가는 구조이다.
html 문서를 파싱(해석)하게 되면 dom 트리구조로 변환된다.
// 속성값으로 선택 (단일)
document.getElementById(id);
// 태그 이름으로 선택(복수)
document.getElementsByTagName(name);
// 클래스 속성값으로 선택(복수)
document.getElementsByClassName(class);
// css 선택자 방식으로 선택(단일) !!!
document.querySelector(css_selector);
// css 선택자 방식으로 선택(복수) !!!
document.querySelectorAll(css_selector);
// form 태그 바로 접근하기
document.forms[index];
document.form_name;
// 스타일 변경 [문서객체].style.[css 속성]
document.getElementById("p").style.color = "red";
// 속성 추가 [문서객체].setAttribute("속성명", "속성값");
document.getElementById("p").setAttribute("class", "red-text");
// 속성 제거 [문서객체].removeAttribute("속성명");
document.getElementById("p").removeAttribute("class");
// 콘텐츠 조작
document.getElementById("p").innerHTML = "<h1>hello</h1>";
document.getElementById("p").innerText = "hello";
// 삭제
document.getElementById("p").remove(); // p 태그 삭제
const div = document.querySelector("div");
const p = document.querySelector("p");
div.removeChild(p); // div의 자식 태그인 p 태그 삭제
const result = new Calculator(10)
.add(5)
.subtract(3)
.multiply(2)
.divide(4)
.getResult();
console.log(result);
표준 내장 객체는 메서드 체이닝을 사용 가능하다.
자바스크립트 이벤트는 웹 페이지에서 사용자와 상호 작용할 때 발생하는 사건을 의미
document.querySelector("p").addEventListener("click", function(){
alert("클릭하셨습니다.");
});
querySelectorAll로 찾으면 NodeList가 반환된다.
NodeList는 array가 아니기 때문에 array의 메서드 사용할 수 없다. 즉 유사배열 객체이다.
그래서 Array.from()
으로 새로운 array 인스턴스를 생성한다.
매개 변수로 함수를 전달 받아서, 함수 내부에서 실행한다.
순서를 보장받기 위해 사용한다.
function task1() {
console.log("task1");
}
function task2() {
setTimeout(() => {
console.log("task2");
}, 1000);
}
function task3() {
console.log("task3");
}
task1();
task2();
task3();
console.log("done");
순서를 보장 받을 수 없다.
function task1(callback) {
console.log("task1");
callback();
}
function task2(callback) {
setTimeout(() => {
console.log("task2");
callback();
}, 1000);
}
function task3() {
console.log("task3");
}
task1(() => {
task2(() => {
task3();
console.log("done");
});
});
task1(); // TypeError: callback is not a function
순서는 보장 받지만 콜백 함수가 중첩되어 콜백 지옥이 발생하여 가독성을 저하한다.
javascript의 비동기 작업의 완료 또는 실패를 나타내는 객체
function task1() {
return new Promise((resolve, reject) => {
console.log("작업1");
resolve();
});
}
function task2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("작업2");
resolve();
}, 1000);
});
}
function task3() {
return new Promise((resolve, reject) => {
console.log("작업3");
resolve("task3 done"); // then으로 매개변수 전달 가능
// reject("task3 fail")
});
}
task1()
.then(() => task2())
.then(() => task3())
.then(() => {
console.log("완료");
})
.catch((error) => {
// reject 처리
console.error("오류 발생:", error);
})
.finally(() => {
console.log("final");
});
그래도 가독성이 부족해 보인다.
가독성과 사용성 때문에 개선하였다.
async 키워드는 함수 선언 앞에 사용되어 해당 함수가 비동기 함수임을 나타냄 비동기 함수는 항상 promise를 반환하며, 이 함수 내부에서 await 키워드 사용가능
await는 Promise가 해결될 때 까지 기다렸다가 그 결과를 반환한다.
async function getApple() {
await delay(2000);
return '🍎';
}
async function getBanana() {
// throw new Error('error');
await delay(4000);
return '🍌';
}
getApple().then((apple) => console.log(apple));
getBanana()
.then((banana) => console.log(banana))
.catch((err) => console.log(err));
await을 사용하여 처리하면 동기적으로 실행은 되지만 시간이 오래 걸리기에 해결하고자 사용
async function pickFruits() {
const response = await Promise.all([getApple(), getBanana()]);
console.log(response);
const response2 = await Promise.race([getApple(), getBanana()]);
console.log(response2);
const [apple, banana] = await Promise.allSettled([getApple(), getBanana()]);
console.log(apple.value, banana.value);
}
pickFruits();
하지만 서버 서능이 좋아야함 자원 소모가 심한편이기 때문 그리고 하나라도 에러가 나면 모두 가져오지 않는다.
Promise.allSettled를 사용해 정상적인것만 가져온다.
배열이나 객체에서 원하는 값을 추출하여 변수에 할당하는 것
const numbers = [1, 2, 3, 4, 5];
// 배열에서 값을 추출하여 변수에 할당
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
const {name, age} = {
name: 'john',
age: 25,
};
console.log(name);
console.log(age);
function speak({name, age}) {
console.log('hello', name);
console.log('your age is', age);
}
speak({name: 'john', age: 25});
타입스크립트는 데이터 타입 명시가 필요함
function sum(a: number, b:number):number{
return a + b
}
const a = sum(10, 20)
console.log(a)
const a: string = 'hello';
const b: number = 1;
const c: boolean = true;
const d: null = null;
const e: undefined = undefined;
const f: symbol = Symbol();
const g: object = new Object();
const h: object = {};
// const h: {name:string} = {name: 'jane'};
const i: [] = [];
const j: Array<[]> = [];
const k: [boolean] = [true];
const l: string[] = ['hello'];
const m: [string, number] = ['hello', 1];
//const m: [string | number] = ['hello', 1]; // Error
//const m: (string & number)[] = ['hello', 1]; // Error
//const m: (string | number)[] = ['hello', 1]; // OK
//const m: Array<string | number> = ['hello', 1]; // OK
const n: () => void = function () {};
const o: (a: number, b: number) => number = function (a, b) {
return a + b;
};
const p: (a: number, b: number) => number = (a, b) => a + b;
타입스크립트에서 함수의 매개변수를 옵션으로 설정하려면 ?
를 붙이면 된다. 매개변수가 전달 되지 않았을 때 undefined로 간주된다. 그래서 생략 가능
type 키워드를 사용하여 타입 별칭 정의할 수 있다.
// type 키워드를 사용하여 가독성을 올려줌
type TSumFn = (a: number, b: number) => number;
const j: TSumFn = (a, b) => a + b;
type TStiring = string;
const hello: TStiring = 'hello world!';
type TNumber = number;
const num: TNumber = 10;
type TStringArray = string[] | null;
const likeFood: TStringArray = ['kimchi', 'pizza', 'hambuger'];
const disLikeFood: TStringArray = null;
type TUser = object;
//명시적으로 직접 타입을 지정해줄 수 있음
type TGender = 'male' | 'female';
type TUserPick = {
name: string;
age: number;
address: string;
// ?를 사용하면 선택적으로 사용할 수 있음 옵셔널체이닝임
gender?: TGender;
};
const user: TUser = {
name: 'kim',
age: 20,
address: 'seoul',
};
const user2: TUserPick = {
name: 'kim',
age: 20,
address: 'seoul',
gender: 'female',
};
// & 연산자를 사용하여 두 타입을 합칠 수 있습니다.
type TPerson = {
name: string;
age: number;
};
type MyWorker = Person & {
company: string;
//readonly을 사용하면 읽기 전용으로 설정할 수 있습니다. 이 경우 값을 변경할 수 없습니다.
readonly position: string;
getMoney?: (amount: number) => number;
};
// 이렇게 합칠 수 있다.
type Employee = Person & MyWorker;
const worker: MyWorker = {
name: 'Smith',
age: 33,
company: 'apple',
position: 'developer',
getMoney(amount: number) {
console.log(`나는 ${amount} 을 받았습니다.`);
return amount;
},
};
const worker2: Employee = {
name: 'Smith',
age: 33,
company: 'apple',
position: 'developer',
};
코드의 구조를 정의하고 타입을 명시하는 역할, 객체처럼 선언 인터페이스는 같은 이름으로 병합할 수 있다.
interface IPerson {
name: string;
age: number;
}
interface IPerson {
gerder: string;
}
type은 같은 이름을 만들 때 에러가 나지만 interface는 확장이 된다.
interface IPerson {
name: string;
age: number;
}
interface IGender extends IPerson {
gerder: string;
}
const employee: IGender = {
name: "sun",
age: 20,
gerder: "femail",
};
extends 로 확장이 가능하다.
const employee: IPerson & IWoker = {
name: "string",
age: 20,
gerder: "string",
company: "string",
position: "string",
};
const employee: IPerson | IWoker = {
name: "string",
age: 20,
gerder: "string",
company: "string",
// position: "string",
};
&
와 |
로도 확장이 가능하다.
Pick 메서드를 사용해 특정 인터페이스의 지정된 속성을 가져옴
Omit 메서드를 사용해 해당 속성을 제외한 나머지 속성을 가져올 수 있음
interface IUser {
name: string;
age: number;
gerder: string;
adress: string;
}
interface IInfo {
name: string;
age: number;
}
interface IInfo1 extends Pick<IUser, "name" | "age"> {}
type IInfo2 = Pick<IUser, "name" | "age">;
interface IInfoOmit1 extends Omit<IUser, "gender" | "address"> {}
type IInfoOmit2 = Omit<IUser, "name" | "age">;
제네릭 함수를 사용하면 함수를 호출할 때 마다 다른 유형의 매개변수를 사용할 수 있다.
즉 타입을 함수의 파라미터 처럼 사용하는 것 타입을 유동적으로 받을 수 있게 된다.
function getSize1(values: number[] | string[] | (number | string)[]) {
return values.length;
}
function getSize<T>(values: T[]): number {
return values.length;
}
getSize<number>([1, 2, 3]);
getSize(["1", "2", "3"]); // 타입 자동추론
getSize([1, 2, 3, "1", "2", "3"]);
type getSize2<T> = (values: T[] | T) => number;
const arrFunc: getSize2<T> = (values) => {
return "string" === typeof values || Array.isArray(values)
? values.length
: 0;
};
CRA가 아닌 vite로 설치하는 이유는 2022년 이후 업데이트가 되지 않고 있고 vite에 성능이 좋기 때문
JSX는 javscript XML 의 약자로 자바스크립트를 확장한 문법
<></>
사용본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 1기 과정(B-log) 리뷰로 작성 되었습니다.