본문 바로가기

JAVASCRIPT

자바스크립트 중급 학습

let, const, var

var는 한번 선언된 변수를 다시 선언할 수 있다.
var name = 'Mike';
console.log(name);  //Mike
var name = 'Jane';
console.log(name); //Jane
var는 선언하기 전에 사용할 수 있다.
console.log(name); //undefined
var name = 'Mike';
var name;  호이스팅
console.log(name); //undefined
name = 'Mike';
변수의 생성과정
var 1.선언 및 초기화 단계
2.할당 단계
let 1.선언 단계
2.초기화 단계
3.할당 단계
const 1.선언 + 초기화 + 할당

const gender;
gender = 'male';  error
스코프
var 함수 스코프(function-scoped)
let, const 블록 스코프(block-scoped)

!생성자 함수

객체 리터럴 let user = {
  name: 'Mike',
  age: 30,
}
생성자 함수 function User(name, age) { 첫 글자는 대문자로
  this.name = name;
  this.age = age; 
}

let user1 = new User('Mike', 30);
let user2 = new User('Jane', 22);
let user3 = new User('Tom', 17); new 연사자를 사용해서 호출
new 함수명(); 호출시 this = {}
return this; 자동으로 반환 및 User 알고리즘 동작
메소드 추가 this.sayName = function() {
  console.log(this.name);
}

let user5 = new User('Han', 40);
user5.sayName(); // 'Han'

!객체 메소드(Object methods), 계산된 프로퍼티(Computed property)

계산된 프로퍼티 let a = 'age';

const user = {
  name : 'Mike',
  [a] : 30 // age : 30
}
Object.assign() : 객체복제 const newUser = Object.assign({}, user); 매개변수가 빈객체에 병합

newUser.name = 'Tom';
console.log(user.name); // 'Mike' 객체가 서로 다름

Object.assign({ gender:'male' }, user); 프로퍼티 하나 추가 단 키가 같은 프로퍼티면 덮어쒸움

const user = {
  name : 'Mike'
}
const info = {

  age : 20
}
....
Object.assign(user, info1, info2) 세개 객체마다 다른 키값이 있는 프로퍼티들을 user에 합쳐짐
Object.keys() : 키 배열 반환 const user = {
  name : 'Mike';
  age : 20,
  gender : 'male',
}
Object.keys(user); user객체안에 키들이 배열로 반환
// ["name", "age", "gender"]
Object.values() : 값 배열 반환  const user = {
  name : 'Mike';
  age : 20,
  gender : 'male',
}
Object.values(user); user 객체안에 값들이 배열로 반환
// ["Mike", 20, "male"]
Object.entries() : 키/값 배열 반환 const user = {
  name : 'Mike';
  age : 20,
  gender : 'male',
}
Object.entries(user); 

[
  ["name","mike"],
  ...
} 배열로 반환 후 배열로 감싸줌
Object.fromEntries() : 키/값 배열을 객체로 const arr
[
  ["name","Mike"],
  ["age",30],
  ["gender","male"]
];
Object.fromEntries(arr);

{
  name : 'Mike',
  ...
} 배열에서 객체로 반환

심볼(Symbol)

const a = Symbol(); 유일한 식별자 new를 붙이지 않습니다.
console.log(a)  //Symbol()
console.log(b)  //Symbol()
a === b;  //false
a == b;  //false
const id = symbol('id');
const id2 = symbol('id');  유일성 보장

id  //Symbol(id)
id2  //Symbol(id)
id === id2  //false
id == id2  //false
property key : 심볼형 const id = Symbol('id');
const user = {
  name : 'Mike',
  age : 30,
  [id] : 'myid'
}
user  //{name: "mike", age: 30, Symbol(id): "myid"}
user[id]  //"myid" 잘 동작함
Object.keys(user);
Object.values(user);
Object.entries(user);
["name", "age"]
["Mike", 30]
[Array(2), Array(2)] 
for(let a in user) {} for in 문 사용불가 심볼형은 건너뜀
const user = {
  name: 'Mike',
  age: 30
}

const id = Symbol('id');
user[id] = 'myid';
원본 데이터를 건드리지 않고 속성을 추가함
Symbol.for() : 전역심볼

const id1= Symbol.for('id');
const id2 = Symbol.for('id');
> 하나의 심볼만 보장받을 수 있음
> 없으면 만들고, 있으면 가져오기 때문
> Symbol 함수는 매번 다른 Symbol 값을 생성하지만,
> Symbol.for 메소드는 하나를 생성한뒤 키를 통해 같은 Symbol을 공유

id1 === id2;  //true
Symbol.keyFor(id1)  //"id" 변수를 넣어주면 할당한 이름이 가져와짐
description const id = Symbol('id 입니다.');
id.description;  //"id 입니다." 전역심볼이 아니면 keyFor을 사용못함 대신 description을 사용하여 이름을 알수있음
숨겨진 Symbol key 보는법 Object.getOwnPropertySymbols(user);  //[Symbol(id)] 심볼들만 볼수있음
Reflect.ownKeys(user); ["name", "age", Symbol(id)] 심볼형 키를 포함한 모든 객체에 키를 보여줌

Number, Math

let num1 = 5.1;
let num2 = 5.7;
Math.ceil(num1);  // 6
Math.ceil(num2);  // 6  소주점 상관없이 오름
let num1 = 5.1;
let num2 = 5.7;
Math.floor(num1);  // 5
Math.floor(num2);  // 5  소주점 상관없이 내림
let num1 = 5.1;
let num2 = 5.7;
Math.round(num1);  // 5
Math.round(num2);  // 6  반올림 메소드
let userRate = 30.1234;
요구사항 : 소수점 둘째자리 까지 표현(셋째 자리에서 반올림)
Math.round(userRate * 100) / 100  //  30.12
100을 곱하고 round 반올림후 100을 나눈다
let userRate = 30.1234;
요구사항 : 소수점 둘째자리 까지 표현(셋째 자리에서 반올림)
userRate.toFixed(2);  //  "30.12"
숫자를 인수로 받아 그 숫자만큼 소수점 이하 계수를 반영
let userRate = 30.1234; userRate.toFixed(2);  //  "30.12"
userRate.toFixed(0);  //  "30" 소수계수 0 이라 정수만 반영
userRate.toFixed(6);  //  "30.123400" 소수계수 6이라 뒤에는 0으로 반영
let userRate = 30.1234; userRate.toFixed(2);  //  "30.12"
Number( userRate.toFixed(2));  //  30.12 넘버를 이용해 숫자형으로 바꿔준다
let x = Number('x');  //  NaN isNaN(x)  //  true  NaN 확인하는법
parselInt() : 정수만 반환 let margin = '10px';
parseInt(margin);  //  10  문자가 뒤에 있으면 앞에 숫자 반환
Number(margin);  //  NaN
let redColor = 'f3';
parseInt(redColor);  //  NaN 문자가 앞에 있으면 NaN 반환

let redColor = 'f3';
parseInt(redColor);  //  NaN
parseInt(redColor, 16);  //  243  16진수로 반환
parseInt('11', 2);  //  3   2,10진수로 반환
parseFloat() : 소수점 반환 let padding = '18.5%';

parseInt(padding);  //  18 소수점 이하만 반환
parseFloat(padding);  //  18.5 소수점까지 반환
Math.radom() : 0 ~ 1 사이 무작위 숫자 생성 Math.random() 메소드를 선언할때 마다 0 ~ 1 사이 숫자 생성
//  0.26484487894564484
1 ~ 100 사이 임의의 숫자를 뽑고 싶다면? Math.floor(Math.random()*100)+1
Math.random()  //  숫자를 생성 예시 0.6789
*100 //  100을 곱한다
Math.floor  //  소수점 이하를 버린다 내림 67
+1  //  1를 더해줌 floor시 0이 나올 수 있기 때문에
Math.max() : 최대값 , Math.min() : 최소값 Math.max(1, 4, -3, 5, 10, 9, 4.45);  //  10
Math.min(1, 4, -3, 5, 10, 9, 4.45);  //  -3 
Math.abs() : 절대값 Math.abs(-1)  //  1
Math.pow(n, m) : 제곱 Math.pow(2, 10);  //  1024  2의 10승을 구함
Math.sqrt() : 제곱근 Math.sqrt(16)  //  4  루트16은 4가 된다.

!String methods

length : 문자열 길이 let desc = '안녕하세요.';
desc.length  //  6
특정 위치에 접근 let desc = '안녕하세요.';
desc[2]  //  '하'
desc[4] = '용';
console.log(desc);  //  안녕하세요. 배열과 다르게 바꿀수 없음
toUpperCase() , toLowerCase() : 대문자, 소문자로 바꿈 let desc = "Hi guys.";
desc.toUpperCase();  //  "HI GUYS"
desc.toLowerCase();  //  "hi guys"
str.indexOf(text) let desc = "Hi guys. Nice to meet you.";
desc.indexOf('to');  //  14
desc.indexOf('man');  //  -1 찾는 문장이 없을시 -1반환
if(desc.indexOf('Hi') > -1 {
  console.log('Hi가 포한된 문장입니다.');
Hi는 인덱스 0이기 때문에 false 나옴 그래서 -1를 넣어줌
str.slice(n, m) : 시작점 과 양수면 그 숫자 음수면 끝에서부터 let desc = "abcdefg";

desc.slice(2)  //  "cdefg"
desc.slice(0, 5)  //  "abcde"
desc.slice(2, -2)  //  "cde"
str.substr(n, m) : n부터 시작, m개를 가져옴 let desc = "abcdefg";
desc.substr(2,4)  //  "cdef"
desc.substr(-4,2)  //  "de"
str.repeat(n) : n번 반복 let hello = "hello!";
hello.repeat(3);  //  "hello! hello! hello!"

!Array methods

arr.splice(n, m) : 특정 요소 지움 let arr = [1,2,3,4,5];
arr.splice(1,2);

console.log(arr);  //  [1,4,5]  [1,2,3,4,5] 인덱스 1 부터 2개 지워짐
arr.splice(n, m, x) : 특정 요소 지우고 추가 let arr = [1,2,3,4,5];
arr.splice(1, 3, 100, 200);

console.log(arr);  //  [1, 100, 200, 5]  [1,2,3,4,5] 인덱스 1부터 3개 지워지고 지워진 자리에 100, 200 추가

let arr = [1,2,3,4,5];
arr.splice(1, 0, 100, 200);  //  [1, 100, 200, 2, 3, 4, 5] 인덱스 1앞에 추가됨
arr.splice() : 삭제된 요소 반환 ler arr = [1,2,3,4,5];
let result = arr.splice(1,2);

console.log(arr);  //  [1,4,5]
console.log(result);  // [2,3]
arr.slice(n, m) : n부터 m까지 반환 let arr = [1,2,3,4,5];
arr.slice(1, 4);  //  [2,3,4] 
arr.concat(arr2, arr3 ..) : 합쳐서 새배열 반환 let arr = [1,2];
arr.concat([3,4]);  //  [1,2,3,4]
arr.concat([3,4], [5,6]);  //  [1,2,3,4,5,6]  
arr.concat([3,4],5,6);  //  [1,2,3,4,5,6]  5랑6을 각각 전달해도 반환은 동일함

arr.forEach(fn) : 배열 반복 let users = ['Mike', 'Tom', 'Jane'];
users.forEach((item, index, arr) => {
});  item: Mike, Tom, Jane / index: 0,1,2 를 가르킴
arr.indexOf / arr.lastIndexOf : 인덱스 번호 반환 let arr = [1,2,3,4,5,1,2,3];
arr.indexOf(3);  //  2
arr.indexOf(3,3)  //  7
arr.lastIndexOf(3);  //  7
arr.includes() : 포함하는지 확인 let arr = [1,2,3];
arr.includes(2);  //  true 배열내 포함 
arr.includes(7);  //  false 배열내 미포함
arr.find(fn) / arr.findIndex(fn) : 첫번째 true 값만 반환하고 끝 만약 없으면 undefined를 반환 let arr = [1,2,3,4,5];
const result = arr.find((item) => {
  return item % 2 === 0;
});

console.log(result);  //  2 값 하나만 반환 하고 끝

let userlist = [
  {name: "Mike", age: 30},
  {name: "Jane", age: 27},
  {name: "Tom", age: 10},
];
const result = userlist.find((user) => {
  if(user.age < 19) {
    return true;
  }return false;
}

console.log(result);  //  {name: "Tom", age: 10}  findIndex 작성시 조건에 맞는 인덱스 번호 반환
arr.filter(fn) : 만족하는 모든 요소를 배열로 반환 let arr = [1,2,3,4,5];
const result = arr.filter((item) => {
  return item % 2 === 0;
});

console.log(result);  //  [2,4]  find랑 다르게 조건에 맞는 모든요소들을 반환 배열로!
arr.reverse() : 역순으로 재정렬 let arr = [1,2,3,4,5]
arr.reverse()  //  [5,4,3,2,1] 
arr.map(fn) : 함수를 받아 특정 기능을 시행하고 새로운 배열을 반환 let userlist = [
  {name: "Mike", age: 30},
  {name: "Jane", age: 27},
  {name: "Tom", age: 10},
];

const newUserList = userlist.map((user, index) => {
  return Object.assign({}, user, {
    id: index + 1,
    isAdult: user.age > 19,
  });
});

console.log(newUserList);
//  {name: "Mike", age: 30, id: 1, isAdult: true},
...
console.lof(userlist);
// {name: "Mike", age: 30}, 본래 객체는 건드리지 않음
...
Array.isArray() : 배열요소인지 찾는 매소드 let user = {name: "Mike", age: 30,}
let userList = ["Mike", "Tom", "Jane"]

console.log(typeof user, typeof userList)  //  object
console.log(Array.isArray(user), Array.isArray(userList))
//  user: false, userList: true 

!arr.sort() / arr.reduce()

arr.sort() : 배열 재정렬 !배열 자체가 변경되니 주의 let arr = [27, 8, 5, 13]
arr.sort()
console.log(arr);  //  [13,27,5,8]  앞자리 숫자로 인식해 정렬함

let arr = [27,8,5,13]
arr.sort((a,b) => {
  return a -b;
})
console.log(arr);  //  [5,8,13,27] 
a가 크면 양수를 리턴 같으면 0 a가 작으면 음수를 리턴
즉 a가 작으면 앞으로 a가 크면 그대로
https://lodash.com/ :정렬해주는 라이브러리 _.sortBy(arr)  숫자든 객체든 문자든 원하는 기준으로 정렬
arr.reduce() : 배열을 돌면서 원하는 값을 반환 (누적 계산값, 현재값) => { return 계산값 }
let arr = [1,2,3,4,5]
const result = arr.reduce((prev, cur) => {
  return prev + cur;
}, 0)
console.log(result)  //  15
현재 초기값 0이 prev에 들어감 순회하면서 현재값을 더함
let userList = [
  {name: "Mike", age:30},
  {name: "Tom", age:10},
  {name: "Jane", age:27},
  {name: "Sue", age:26},
  {name: "Harry", age:45},
]
//모든 나이 합산 함수
let result = userList.reduce((prev, cur) => {
  return (prev + cur.age);
}, 0)
console.log(result)  //  196

//이름이 세자리인사람 함수
let result = userList.reduce((prev, cur) => {
  if(cur.name.length === 3) {
    prev.push(cur.name);
  }
  return prev;
}, [])
console.log(result)  //  ["Tom", "Sue"]

구조 분해 할당 (Destructuring assignment)

Destructuring assignmaent 구조 분해 할당 구문은 배열이나 객체의 속성을 분해해서 그 값을 변수에 담을 수 있게 하는 표현식
배열 구조 분해 let [x, y] = [1, 2]
console.log(x)  //  1
console.log(y)  //  2  x는 1이 들어감 y는 2가 들어감
let users = ["Mike", "Tom", "Jane"] let [user1, user2, user3] = users
console.log(user1)  //  "Mike"
console.log(user2)  //  "Tom"
console.log(user3)  //  "Jane"

let user1 = users[0]
let user2 = users[1]
let user3 = users[2]   할당이 이런식으로 들어감
let srt = "Mike/Tom/Jane" let [user1,user2,user3] = str.split('/')
console.log(user1)  //  "Mike"
console.log(user2)  //  "Tom"
console.log(user3)  //  "Jane"  split 사용(배열로 나눠짐) 기준점 요소로 원소가 나눠짐
배열 구조 분해 : 기본값 let [a,b,c] = [1,2]  c는 undefind
let [a=3, b=4, c=5] = [1,2]
console.log(a)  // 1
console.log(b)  // 2
console.log(c)  // 5  1,2는 잘들어오고 c는 기본갓으로 할당
배열 구조 분해 : 일부 반환값 무시 let [user1,  ,user2] = ["Mike", "Tom", "Jane", "Tony"]
user1 = "Mike"
user2 = "Jane"  "Tom은 공백으로 건너뛰고 "Tony"는 무시
배열 구조 분해 : 바꿔치기 새로운 변수 선언하고 할당 필요 없이
[a,b] = [b,a]  사용하면 a랑 b가 서로 바뀐다
객체 구조 분해 let user = {name: "Mike", age:30}
let {name, age} = user
name  //  "Mike"
age  //  30  각 name,age 변수에 user.name 과 user.age를 봄
객체 구조 분해 : 새로운 변수 이름으로 할당 let {name:userName, age:userAge} = user
userName  //  "Mike"
userAge  //  30  키의 이름을 바꿀 수 있음
객체 구조 분해 : 기본값 let user = {name: "Mike", age:30}
let {name, age, gender} = user  gender undefined가 나옴
let {name, age, gender = "male"} = user  기본값을 할당한다 만약 user 객체에 gender가 있을시 그 값을 사용

!나머지 매개변수, 전개구문 (Rest parameters, Spread syntax)

인수전달 function showName(name) {}  (name) 개수 제한 없음
arfuments >함수로 넘어 온 모든 인수에 접근
>함수내에서 이용 가능한 지역 변수
>length / index
>Array 형태의 객체
>배열의 내장 메서드 없음 (forEach, map)

funcrion showName(name) {
  console.log(arguments.length);
  console.log(arguments.[0]);
  console.log(arguments.[1]);
}
showName("mike", "Tom")  //  
>2
>"Mike"
>"Tom"
나머지 매개변수(Rest parameters) function showName(...names) {
  console.log(names);
}

showName()  //  []
showName("Mike")  //  ["Mike"]
showName("Mike", "Tom")  //  ["Mike", "Tom"] 
names 배열안에 인수들이 들어감
function add(...numbers) {
  let result = 0;
  numbers.forEach((num) => (result += num));
  console.log(result);
}
add(1,2,3)  //  6
add(1,2,3,4,5,6,7,8,9,10)  //  55
...numbers 는 배열이랑 length가 있기 때문에 for문 사용가능
forEach문 배열메서드 사용가능
function add(...numbers) {
  let result = numbers.reduce((prev, cur) => prev + cur);
  console.log(result);
}
add(1,2,3)  //  6
add(1,2,3,4,5,6,7,8,9,10)  //  55
reduce() 도 사용가능
user 객체를 만들어 주는 생성자 함수
function User (name, age, ...skills) {
  this.name = name;
  this.age = age;
  this.skills = skills;
}

const user1 = new User("Mike", 30, "html", "css")
const user2 = new User("Tom", 25, "JS", "React")
const user3 = new User("Jane", 10, "English")
console.log(user1)  //  {name:"Mike", age:30, skills: Array(2)}
console.log(user2)  //  {name:"Tom", age:25, skills: Array(2)}
console.log(user3)  //  {name:"Jane", age:10, skills: Array(1)}
나머지 매개변수는 배열로 들어옴
전개 구문(Spread syntax) : 배열 / 객체 let arr1 = [1,2,3]
let arr2 = [4,5,6]
let result = [0,...arr1,...arr2,7,8,9]  //  {0 ~ 9] 중간에 넣어도 됨

let user = {name:"Mike"}
let mike = {...user, age:30}
mike  //  {name:"Mike", age:30} 객체도 가능


전개 구문(Spread syntax) : 복제 let user = {name:"Mike", age:30}
let user2 = {...user}
user2.name = "Tom"
console.log(user.name)  //  "Mike"
console.log(user2.name)  //  "Tom"  객체복제 assign처럼 작동
arr1 을 [4,5,6,1,2,3] 으로
let arr1 = [1,2,3]
let arr2 = [4,5,6]

let result = [...arr2, ...arr1]
console.log(result)  //  [4,5,6,1,2,3]
user 객체의 모든 원소 병합
let user = {name:"Mike"}

let info = (age:30}
let fe = ["JS", "React"]
let lang = ["korean", "English"]
user = Object.assign({}, user, info, { skills: []});
fe.forEach((item) => { user.skills.push(item);});
lang.forEach((item) => { user.skills.push(item);});
console.log(user)  // 
{name: 'Mike', age: 30, skills: [ 'JS', 'React', 'Korean', 'English' ]}  코드가 복잡함 

user = {
  ...user,
  ...info,
  skills: [
    ...fe,
    ...lang,
  ],
};
console.log(user);  //
{name: 'Mike', age: 30, skills: [ 'JS', 'React', 'Korean', 'English' ]}  코드가 단순함

클로저 (Closure)

어휘적 환경(Lexical Environment)

let one;
one = 1;

function addOne(num) {
  console.log( one + num);
}
addOne(5)
전역 Lexical 환경 : one : 1 / addOne : function
내부 Lexical 환경: num : 5
함수 내부를 먼저 참조후 없을 시 외부를 참조함
어휘적 환경(Lexical Environment) 다른 문제

function makeAdder(x) {
  return function(y) { !
    return x + y;
  }
}

const add3 = makeAdder(3) !
console.log(add3(2))
전역 Lexical 환경 : makeAdder : function / add3 : 초기화X
makeAdder Lexical 환경 : x : 3
익명함수 Lexical 환경 : y : 2
! y 를 가지고 있고 상위함수인 makeAdder 의 x 에 접근 가능
! add3 함수가 생성된 이후에도 상위함수인  makeAdder 의 x 에 접근 가능
클로저(Closure)란? >함수와 렉시컬 환경의 조합
>함수가 생성될 당시의 외부 변수를 기억
>생성 이후에도 계속 접근 가능

setTimeout / setInterval

setTimeout : 
setInterval : 
일정 시간이 지난 후 함수를 실행
일정 시간 간격으로 함수를 반복
function showName(name) {
  console.log(name);
}
setTimeout(showName, 3000, "Mike")
"Mike"인수는 함수 첫번째 인수로 전달
clearTimeout(tId) 예정된 타임아웃을 없앤다
const tId = function showName(name) {
  console.log(name);
}
setTimeout(showName, 3000, "Mike")

clearTimeout(tId)

상수를 선언하면 스케줄링을 취소 함
function showName(name) {
  console.log(name);
}
const tId = setInterval(showName, 3000, "Mike")
3초마다 함수가 실행한다  //  "Mike"  "Mike"  "Mike"
중간에 중단하려면 clearInterval(tId) 를 선언

!call, apply, bind

call call 메서드는 모든 함수에서 사용할 수 있으며, this를 특정값으로 지정할 수 있습니다.
const mike = {
  name: "Mike",
}
const tom = {
  name: "Tom",
}

function update(birthyear, occupation) {
  this.birthYear = birthyear;
  this.occupation = occupation;
}

update.call(mike, 1999, "teacher")
console.log(mike)  //
{name: "Mike", birthYear: 1999, occupation: "teacher"}

this로 사용할 mike 전달
두번째 매개변수 부터는 함수가 사용할 매개변수를 참조
apply apply는 함수 매개변수를 처리하는 제외하면 call과 완전히 같습니다. call은 일반적인 함수와 마찬가지로 매개변수를 직접 받지만, apply는 매개변수를 배열로 받습니다.
const nums = [3, 10, 8, 5, 1];

const minNum = Math.min.apply(null, nums);
// = Math.min.apply(null, [3, 10, 8, 5, 1])

const maxNum = Math.max.call(null, ...nums);
// = Math.max.apply(null, 3, 10, 8, 5, 1)

console.log(minNum)
console.log(maxNum)
call은 직접받고, apply 는 매개변수를 배열로 받는다
bind 함수의 this 값을 영구히 바꿀 수 있습니다.
const user = {
  name: "Mike",
  showName: function() {
    console.log(`hello, ${this.name}`);
  },
};

user.showName();

let fn = user.showName;

fn.call(user);
fn.apply(user);

const bindFn = fn.bind(user);

bindFn();  //  'hello, Mike'
점 앞이 this를 가르키는데 fn만 호출시 this가 없어 name이 안나옴 그래서 call, apply, bind 를 사용하여 명시해준다.

!상속,프로토타입(Prototype)

hasOwnProperty() 해당 내장객체 프로퍼티만 있으면 트루 그외 flase
const car = {
  wheels: 4,
  drive() {
    console.log("drive...");
  },
};

const bmw = {
  color: "red",
  navigation: 1,
};

bmw.__proto__ = car;

for(p in bmw) {
  console.log(p);
}  //  color,  navigation,  wheels,  drive
bmw.color  //  red  
bmw.wheels  //  4
bmw 객체의 color 있으니 탐색후, 멈춘다.
bmw 객체의 wheels 없으니 __proto__ 까지 탐색후, 멈춘다.
x5객체를 만들고 bmw을 상속을 한다.
const x5 = {
  color: "white",
  name: "x5",
};

x5.__proto__ = bmw;
x5.color  //  white  
x5.navigation  //  1
x5 객체의 color가 white 있으니 탐색후, 멈춘다.
x5 객체의 navigation 없으니 bmw__proto__ 까지 탐색후 있으니 탐색후, 멈춘다. Prototype Chain
Object.keys/values  해당 객체의 내장 객체인 키 값만 호출 할 수있다. 
생성자 함수 사용
const car = {
  wheels: 4,
  drive() {
    console.log("drive...");
  },
};

const Bmw = function (color) {
  this.dolor = color;
};

const x4 = new Bmw("red");
const z4 = new Bmw("blue");

x4.__proto__ = car;
z4.__proto__ = car;

생성자 함수가 생성하는 객체의 proto을 prototype의 직접 설정합니다. 하나씩 객체의 proto를 넣어줄 필요 없다.
const Bmw = function (color) {
  this.dolor = color;
};

Bmw.prototype.wheels = 4;
Bmw.prototype.drive = function () {
  console.log("drive..");
};

const x4 = new Bmw("red");
const z4 = new Bmw("blue");


z4 instanceof Bmw  //  true 해당 객체가 생성자 함수로 부터 생성 됐는지 확인
z4.constructor === Bmw  // true 해당 생성자 함수가 맞는지  true,false 반환
const Bmw = function (color) {
  this.dolor = color;
};

Bmw.prototype = {
  constructor: Bmw,
  wheels: 4,
  drive() {
    console.log("drive..");
  },
};

const x4 = new Bmw("red");
const z4 = new Bmw("blue");

console.log(z4.constructor === Bmw)
프로토타입을 덮어서 작성시 constructoe가 flase가 나온다.
그래서 수동으로 constructor을 명시할 수 있다.

!클래스(Class)

생성자 함수의 new를 없앰
const User = function (name, age) {
  this.name = name;
  this.age = age;
  this.showName = function () {
    console.log(this.name);
  };
};

const tom = User("Tom", 20);  //  undefined
생성자함수의 new를 없애고 실행시키면 return 값이 없기 때문에 undefined가 뜬다 (생성자함수는 error가 안뜨고 정상적으로 나온다.)


class 함수의 new를 없앰
class User2 {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  };
  showName() {
    console.log(this.name);
  };
};

const mike = User2("Mike", 30);  //  typeerror "new"
클래스는 new 없이는 error가 뜬다. 클래스로 생성된 constructor는 class 를 가지고 있기 때문에 new없이 실행시 에러가 발생하도록 설계함
Class : 상속은 extends를 사용함
class Car {
  constructor(color) {
    this.color = color;
    this.wheels = 4;
  }
  drive() {
    console.log("drive..");
  }
  stop() {
    console.log("STOP");
  }
}

class Bmw extends Car {
  park() {
    console.log("PARK");
  }
}

const z4 = new Bmw("blue");
클래스로 선언한 메소드는 프로토타입 밑으로 들어간다.
z4.drive()를 치면 z4객체안에서 찾는다. 없으면 상속한 Car프로토타입까지 탐색후, 멈춘다.
Class : 메소드 오버라이딩(method Overriding)
class Bmw extends Car {
  park() {
    console.log("PARK");
  }
  stop() {
    super.stop();
    console.log("OFF");
  }
}
상속을 받아온 Bmw 클래스에 stop()메소드를 중복시 덮어씌우게 된다. OFF가 나온다. 이와 같이 super.stop()을 선언하여 Car의 메소드도 같이 나온다.
Class : 오버라이딩(overriding)
class Bmw extends Car {
  constructor() {
    this.navigation = 1;
  }
  park() {
    console.log("PARK");
  }
}
인수를 넣어주고 super을 넣어줌
  constructor(color) {
    super(color);
    this.navigation = 1;
  }
constructor에서 this를 사용하기 전에, super 을 명시해야 부모 생성자를 반드시 먼저 호출해야 한다.
constructor는 빈객체를 만들고 this는 빈객체를 가르킴
하지만, 자식 클래스는 건너뜀
자식 constructor에도 부모와 동일한 인수 작업을 넣어줘야함

!Promise

const pr = new Promise((resolve, reject) => {
  //code
});
함수로 전달 받음
인수는 resolve, reject 이다.
resolve는 성공할 때 실행되고, reject는 실패할 때 실행됨
어떤 일을 완료하고 실행되는 함수를 콜백(callback)함수다
new Promise
state : pending(대기)  초기는 대기상태
result : undefinded 

//resolve(value) 호출  true

state : fulfilled(이행됨)
result : value

//reject(error)  호출  flase

state : rejected(거부됨)
result : error

new 생성한 프로미스는 객체를 갖는다.
state와 result를 갖는다.

resolve(성공) 하면 fulfilled가 호출됨
이때 result는 resolve함수로 전달 된 값

rejected(실패) 하면 rejected가 호출됨
이때 result는 reject 함수로 전달 된 값

const pr = new Promise((resolve, reject) => {
  setTimeout(()=>{
    resolve("OK");
  },3000)
});

const pr = new Promise((resolve, reject) => {
  setTimeout(()=>{
    reject(new Error("error.."));
  },3000)
});
3초뒤 실행 result는 OK로 반환
state:pending(대기)  =>  stata:fulfilled(이행됨)
result:undefined       =>   result:'OK'   

3초뒤 실행 result는 error반환
state:pending(대기)  =>  stata:rejected(거부됨)
result:undefined       =>   result:error    
pr.then(
  function(resilt){},
  function(err){}
);
pr.then(
  function(result){}
).catch(
  function(err){}
)  //  이와 같이 catch문을 바꿀수 있음 동작은 똑같음
pr.then(
  F()
).catch(
  F()
).finally(
  function(){
    console.log('---주문 끝---')
  }
)
finally는 이행이든 거부든 처리가 완료되면 실행
console.log("시작");
f1()
  .then((res) => f2(res))
  .then((res) => f3(res))
  .then((res) => console.log(res))
  .catch(console.log)
  .finally(() => {
    console.log("끝");
  });
//  시작 -> 1번주문완료 -> 2번주문완료 -> 3번주문완료 -> 끝
연결 되는 프로미스를 프로미스 체이닝(Promise chaining)
이라고 한다.
!가져온 데이터 순으로 화면을 그릴수 있다.
상품을 한번에 다 받아오는 메서드 : Promise.all
Promise.all([f1(), f2(), f3()]).then((res) => {
  console.log(res);
});
//  ["1번주문완료, "2번주문완료", "3번주문완료"]
각 프로미스로 넘겨준 값이 배열로 넘어옴
setTimeout이 3초가 최대라 3초 안에 다받아옴
모두 이행 되어야 값을 사용할수 있다.
reject 사용시 new Error() 어떠한 데이터도 못 얻는다.
!하나라도 정보가 누락될 경우 페이지를 보여주면 안될때 
사용한다.
하나라도 먼저 반환되면 끝내는 메서드 : Promise.race
Promise.race([f1(), f2(), f3()]).then((res) => {
  console.log(res);
});
1번 주문 완료
//  1번 res나오고 이미 1번이 나와서 2번 rej은 무시한다.

'JAVASCRIPT' 카테고리의 다른 글

자바스크립트 함수 및 기술들 복습자료  (1) 2024.02.05