학생별 점수를 아래와 같은 형식으로 콘솔에 출력
내 코드 ⬇️
let scores = [{name: '홍길동', korean: 80, math: 90, english: 90},
{name: '고길동', korean: 90, math: 80, english: 80},
{name: '신길동', korean: 70, math: 80, english: 70}];
console.log(`----------- --------- --------- --------- --------- ---------
학생이름 국어 영어 수학 합계 평균
----------- --------- --------- --------- --------- ---------
`);
for (i = 0; i < scores.length; i++) {
let sum = scores[i].korean + scores[i].math + scores[i].english;
let avg = (sum / 3).toFixed(1);
console.log(` ${scores[i].name} ${scores[i].korean} ${scores[i].english} ${scores[i].math} ${sum} ${avg}`);
};
예시 코드 ⬇️
// 배열에 학생별 점수를 추가
let scores = [];
scores.push({name: '홍길동', korean: 80, math: 90, english: 90});
scores.push({name: '고길동', korean: 90, math: 80, english: 80});
scores.push({name: '신길동', korean: 70, math: 80, english: 70});
// 타이틀 출력
console.log('----------\t---------\t---------\t---------\t--------- ---------');
console.log('학생이름\t국어\t영어\t수학\t합계\t평균');
console.log('----------\t---------\t---------\t---------\t--------- ---------');
// 학생별 점수 출력
scores.forEach(score => {
const total = score.korean + score.math + score.english;
const average = total / 3;
console.log(`${score.name}\t\t${score.korean}\t\t${score.english}\t\t${score.math}\t\t${total}\t\t${average.toFixed(1)}`);
});
속성 이름과 속성값을 가지고 있는 변수 이름이 동일한 경우 → 속성 이름을 생략
속성 이름과 함수(메서드) 이름이 동일한 경우
→ function 키워드와 함께 생략
let name = "John";
const obj = {
age: 21,
name: name,
getName: function getName() {
return this.name;
}
};
console.log(obj); // {age: 21, name: 'John', getName: f}
console.log(obj.getName()); // John
const obj2 = {
age: 21,
name,
getName() {
return this.name;
}
};
console.log(obj); // {age: 21, name: 'John', getName: f}
console.log(obj.getName()); // John
사용 예 1) 매개변수를 객체로 반환하는 함수를 정의하는 경우
function returnObject(age, name) {
return { age: age, name: name };
}
console.log(returnObject(20, "홍길동")); // {age: 20, name: "홍길동"}
function returnObject2(age, name) {
return { age, name }; // <= 편하다 !!!!!
}
console.log(returnObject2(20, "홍길동")); // {age: 20, name: "홍길동"}
사용 예 2) 로그를 출력할 때
const age = 20;
const name = "홍길동";
// 변수가 가지고 있는 값을 로그로 출력 => 변수 이름과 함께 출력되어야 내용 파악이 용이
console.log("age", age); // age 20
console.log("name", name); // name 홍길동
console.log(\`age = ${age}, name = ${name}\`); // age: 20, name: 홍길동
console.log({age, name}); // {age: 20, name: "홍길동"} <= 편하다!!!!
아주 유용하게 쓰일 수 있다 !
변수를 이용해서 객체 속성의 키를 만드는 방법
//속성 이름(key)과 속성 값(value)을 전달받아 객체를 반환하는 함수를 정의
function returnObject(key, value) {
/*
const obj = {}; // 빈 객체 정의
obj[key] = value;
return obj;
*/
return { [key]: value };
}
console.log(returnObject("name", "John")); // { name: "John" }
여기서 그냥 { key: value } 라고 하면 { key: "John" } 이렇게 나온다.
활용 예시 ⬇️
// 속성 이름이 일련번호 형태를 가지는 객체를 반환하는 함수
function returnObject2(key, value, no) {
/*
const obj = {};
obj[key + no] = value;
return obj;
*/
return { [key + no]: value };
}
console.log(returnObject2("name", "John", 1)); // {name1: "John"}
console.log(returnObject2("name", "Jane", 2)); // {name2: "Jane"}
아주아주 중요 ! ⭐️⭐️⭐️⭐️⭐️ 배열이 가지고 있는 값들을 쭉 풀어서 나열해준다.
console.log(Math.max(10, 20, 1, 30, 3, 2)); // 30
console.log(Math.max([10, 20, 1, 30, 3, 2])); // NaN
const numbers = [10, 20, 1, 30, 3, 2];
console.log(Math.max(numbers)); // NaN
console.log(Math.max(numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], numbers[5])); // 30
// 이럴 때 필요한 게 전개연산자!!
console.log(Math.max(...numbers)); // 30 . 배열이 가지고 있는 값들을 쭉 풀어서 나열해준다.
사용 예 1) 배열의 값을 복사할 때
let a = 10;
let b = 1;
console.log(a); // 10
console.log(b); // 10
let arr1 = [1, 2, 3];
let arr2 = arr1;
console.log(arr1); // [1, 2, 3]
console.log(arr2); // [1, 2, 3]
a = 20;
console.log(a); // 20
console.log(b); // 10
arr1[0] = 10;
console.log(arr1); // [10, 2, 3]
console.log(arr2); // [10, 2, 3]
위의 문제(객체와 배열을 복사할 때 참조가 복사되는 문제)를 해결
주소가 아닌 '값'을 복사하는 것이 필요하다.
let arr3 = [1, 2, 3];
let arr4 = [];
for (let i = 0; i < arr3.length; i++) {
arr4[i] = arr3[i];
}
console.log(arr3); // [1, 2, 3]
console.log(arr4); // [1, 2, 3]
arr3[0] = 10;
console.log(arr3); // [10, 2, 3]
console.log(arr4); // [1, 2, 3]
위 코드를 더 예쁘게 할 때 스프레드 연산자 사용! 리액트에서 상태 변경 리렌더링할 때 사용된다. ⭐️⭐️⭐️⭐️⭐️
// 전개 연산자를 이용해서 배열의 값을 복사
let arr5 = [1, 2, 3];
let arr6 = [...arr5];
console.log(arr5); // [1, 2, 3]
console.log(arr6); // [1, 2, 3]
arr5[0] = 10;
console.log(arr5); // [10, 2, 3]
console.log(arr6); // [1, 2, 3]
사용 예 2) 객체의 값을 복사할 때
let obj1 = { age: 23, name: '홍길동' };
let obj2 = obj1;
console.log(obj1); // {age: 23, name: '홍길동'}
console.log(obj2); // {age: 23, name: '홍길동'}
obj1.age = 200;
console.log(obj1); // {age: 200, name: '홍길동'}
console.log(obj2); // {age: 200, name: '홍길동'} // 주소가 복사되어서 이런 결과가 나타남
// 객체 값이 복사될 수 있도록 하자!!
let obj3 = { age: 23, name: '홍길동' };
let obj4 = { ...obj3 };
console.log(obj3); // {age: 23, name: '홍길동'}
console.log(obj4); // {age: 23, name: '홍길동'}
obj3.age = 200;
console.log(obj3); // {age: 200, name: '홍길동'}
console.log(obj4); // {age: 23, name: '홍길동'}
사용 예 3) 객체를 복사하는 과정에서 새로운 속성을 추가하거나 속성의 값을 변경하는 경우⭐️⭐️⭐️⭐️⭐️
let obj1 = { age: 23, name: '홍길동' };
obj1.age = 40; // 객체의 속성값을 변경
obj1.colors = ['red', 'blue', 'green']; // 객체에 새로운 속성을 추가
console.log(obj1); // { age: 40, name: '홍길동', colors: [ 'red', 'blue', 'green' ]}
// obj1과 동일한 속성을 가지는 obj2를 정의하고, name 속성의 값을 고길동으로 변경
/*
let obj2 = { ...obj1 };
obj2.name = '고길동';
*/
// 전개 연산자로 복사한 name 속성의 값을 덮어씀
let obj2 = { ...obj1, name: '고길동' };
console.log(obj2); // { age: 40, name: '고길동', colors: [ 'red', 'blue', 'green' ]}
// obj1과 동일한 속성을 가지는 obj3를 정의하고, email 속성을 추가
// 전개 연산자로 복사한 객체에 email 속성을 추가
let obj3 = { ...obj1, email: "go@test.com" };
console.log(obj3); // { age: 40, name: '홍길동', colors: [ 'red', 'blue', 'green' ], email: 'go@test.com'}
사용 예 4) 배열 또는 객체를 결합할 때
배열은 index가 있기 때문에 순서가 중요하다.
객체를 key로 접근하기 때문에 값을 덮어쓰므로 주의해야 한다.
// 두 배열을 결합
const arr1 = [ 1, 2, 3 ];
const arr2 = [ 3, 4, 5 ];
const arr3 = [ ...arr1, ...arr2 ];
console.log(arr3); // [ 1, 2, 3, 3, 4, 5 ]
const arr4 = [ ...arr2, ...arr1 ];
console.log(arr4); // [ 3, 4, 5, 1, 2, 3 ]
// 두 객체를 결합
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { c: 33, d: 4, e: 5 };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3); // { a: 1, b: 2, c: 33, d: 4, e: 5 }
const obj4 = { ...obj2, ...obj1 };
console.log(obj4); // { c: 3, d: 4, e: 5, a: 1, b: 2 }
사용 예 5) 배열 요소를 함수의 개별 인수로 전달할 때
function sum (a, b, c) {
return a + b + c;
}
const numbers = [10, 20, 30];
console.log(sum(...numbers));
console.log(Math.max(10, 20, 30));
console.log(Math.max(...numbers));
함수의 인수를 배열로 수집하는 방법
함수가 전달받은 가변 인수를 처리할 때 사용
/*
function sum(a, b) {
const result = a + b;
console.log(result);
}
sum(10, 20); // 30
sum(10, 20, 30); // 60 원하는데 ,, 고정된 개수의 인자 외에는 무시되어서 30이라고 나온다.
sum(10, 20, 30, 40); // 100 원하는데 ,, 고정된 개수의 인자 외에는 무시되어서 30이라고 나온다.
*/
// 이를 개선하기 위해 나온 Rest Pagameter
function sum(...args⭐️) {
console.log(args);
let result = 0;
for (let i = 0; i < args.length; i++) {
result += args[i];
}
console.log(result);
}
// 배열로 들어간다!!
sum(10, 20); // 30
sum(10, 20, 30); // 60
sum(10, 20, 30, 40); // 100
가변 길이의 매개변수. 가변 길이의 인자값을 받아들일 때 사용한다.
배열 데이터(요소)를 변수에 나눠서 할당
// 배열 요소의 값을 변수에 할당
const arr = [ 1, 2, 3, 4, 5 ];
// 배열 인덱스를 이용해서 개별 변수에 배열이 가지고 있는 값을 할당
let a = arr[0];
let b = arr[1];
console.log({ a, b }); // 단축 속성명!! { a: 1, b: 2 }
// c, d, e, f 변수에 arr 배열에 첫 번째 인덱스의 값부터 차례로 할당
let [ c, d, e, f ] = arr; // 배열 비구조화 할당 ⭐️⭐️⭐️⭐️⭐️
console.log({ c, d, e, f }); // { c: 1, d: 2, e: 3, f: 4 }
두 변수의 값을 교환
let x = 10;
let y = 20;
console.log({x, y}); // {x: 10, y: 20}
let temp = x;
x = y;
y = temp;
console.log({x, y}); // {x: 20, y: 10}
// 배열 비구조화를 이용해서 두 변수의 값을 교환
x = 10;
y = 20;
console.log({x, y}); // { x: 10, y: 20}
[x, y] = [y, x]; // [비구조화 할당] = [배열 선언] ⭐️⭐️⭐️⭐️⭐️
console.log({x, y}); // {x: 20, y: 10}
배열의 크기보다 변수의 개수가 많은 경우
const arr = [1, 2];
const [a, b, c] = arr;
console.log({a, b, c}); // { a: 1, b: 2, c: undefined⭐️ }
// 기본값 설정이 가능
const [d, e = 20⭐️, f = 30] = arr;
console.log({d, e, f}); // {d: 1, e: 2, f: 30} arr에서 할당하기 때문에 e는 arr의 2가 된다.
배열의 일부값을 변수에 할당할 경우 => 할당하지 않을 자리는 비워둠
const arr = [ 1, 2, 3, 4 ,5 ];
let [a, b, c, d, e] = arr;
console.log({a, b, c, d, e}); // {a: 1, b: 2, c: 3, d: 4, e: 5}
// 변수 x에 첫 번째 값을, y에 세 번째 값을, z에 5번째 값을 할당하고 싶다.
let [x, , y, , z] = arr; ⭐️
console.log({x, y, z}); // {x: 1, y: 3, z: 5}
배열의 값을 할당하고 남은 나머지를 새로운 배열로 만드는 경우 (rest parameter와 비구조화 같이 쓰는 예시)
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// arr 배열의 첫 번째 값을 first 변수에 넣고, 나머지 값을 rest 이름의 배열에 추가
const [first, ...rest] = arr; ⭐️
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5, 6, 7, 8, 9, 10]
객체는 순서가 없고 key를 이용해서 식별한다.
// 객체 비구조화를 할 때는 객체의 속성명(key)이 중요
const obj1 = { age: 21, name: "홍길동" };
const obj2 = { age: 43, name: "고길동" };
// obj1의 age와 name 속성의 값을 age와 name 변수에 할당
/*
let age = obj1.age;
let name = obj1.name;
*/
let { age, name } = obj1; // 객체 비구조화 할당 = 객체 요소의 값
console.log({ age, name }); // {age: 21, name: '홍길동'} <= 단축 속성명을 이용해서 변숙 가지고 있는 값을 출력
// 객체에 존재하지 않는 변수의 기본값 설정
let { age: newAge, name: newName, email = "default" } = obj1; // 이렇게 alias 걸어주면 undefined 가 아니다..!
console.log({ newAge, newName, email }); // {newAge: 21, newName: '홍길동', email: 'default'}
const obj1 = { age: 21, name: "홍길동", email: 'hong@test.com'};
// obj1 객체의 age 속성의 값을 hongAge 변수에 할당하고, 나머지 값을 rest 이름의 객체에 할당
const { age: hongAge, ...rest } = obj1;
console.log(hongAge); // 21
console.log(rest); // {name: "홍길동", email: "hong@test.com"}
하나의 집합을 다른 형태의 집합으로 바꾸는 것
1:1 n:n 관계 !
모집합과 map() 이후 집합이 형태는 달라져도 개수는 똑같다.
map 안에는 콜백함수가 들어온다.
(p94)
const source = [1, 4, 9, 16];
// source 배열의 값을 두 배수한 결과 배열(twoTimes)을 만들어서 출력
// 방법1. for문을 이용한 방법
{
const twoTimes = [];
for (let i = 0; i < source.length; i++) {
// twoTimes.push(source[i] * 2);
twoTimes[i] = source[i] * 2;
}
console.log(twoTimes); // [ 2, 8, 18, 32 ]
}
// 방법2. map() 메서드를 이용
{
const twoTimes = source.map(value => value * 2);
console.log(twoTimes); // [ 2, 8, 18, 32 ]
}
{
const func = (value) => value * 2;
const twoTimes = source.map(func);
console.log(twoTimes); // [ 2, 8, 18, 32 ]
}
{
const func = function(value) {return value * 2; };
const twoTimes = source.map(func);
console.log(twoTimes); // [ 2, 8, 18, 32 ]
}
{
const twoTimes = source.map(function(value) {
return value * 2;
});
console.log(twoTimes); // [ 2, 8, 18, 32 ]
}
{
function func(value) {
return value * 2;
}
const twoTimes = source.map(func);
console.log(twoTimes); // [ 2, 8, 18, 32 ]
}
// 여러 맵 함수를 연결해서 사용 (2배한 걸 10배하기 !)
{
const twoTimes = v => v * 2;
const tenTimes = v => v * 10;
const plusTwo = v => v + 2;
const result = source.map(plusTwo).map(twoTimes).map(tenTimes);
console.log(result); // [ 220, 460, 920, 1840 ]
result = source.map(twoTimes).map(tenTimes).map(plusTwo);
console.log(result); // [ 22, 42, 82, 162 ]
}
모집합 중에 일정 조건을 만족하는 것으로만 걸러내는 것
모두 다 통과할 수도(모두), 한 개도 통과 못 할 수도 있다(0개).
const words = [ 'spring', 'summer', 'fall', 'winter', 'destuction', 'creation', 'rebirth' ];
// 길이가 여섯 글자 이상인 단어만 추출
{
const newWords = [];
for (let i = 0; i < words.length; i++) {
if (words[i].length >= 6) {
newWords.push(words[i]);
}
}
console.log(newWords); // ['spring', 'summer', 'winter', 'destruction', 'creation', 'rebirth']
}
// 가장 간단하다 !
{
const newWords = words.filter(w => w.length >= 6);
console.log(newWords); // ['spring', 'summer', 'winter', 'destruction', 'creation', 'rebirth']
}
{
function func(w) {
return w.length >= 6;
}
const newWords = words.filter(func);
console.log(newWords); // ['spring', 'summer', 'winter', 'destruction', 'creation', 'rebirth']
}
{
const func = function(w) {
return w.length >= 6;
}
const newWords = words.filter(func);
console.log(newWords); // ['spring', 'summer', 'winter', 'destruction', 'creation', 'rebirth']
}
{
const newWords = words.filter(function(w) {
return w.length >= 6;
})
}
const numbers = [ 1, 3, 4, 6, 11, 14 ];
// 짝수만 추출해서 10배수한 결과를 출력
console.log(numbers.filter(n => n % 2 === 0).map(n => n * 10)); // [40, 60, 140]
const even = numbers.filter(n => n % 2 === 0);
const evenTenTimes = even.map(n => n * 10);
console.log(evenTenTimes); // [40, 60, 140]
집계 !!
결과가 하나로 축약되는 것
합계, 평균, 최댓값, 최솟값을 구할 때 사용
// 배열 요소들의 합계
{
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
console.log(sum); // 15
}
{
let sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 15
}
매개변수 2개이다.
(누적기, 현재값)
앞 연산의 결과 반환값이 누적기 !
0은 초깃값, cur 에 1이 처음에 들어가는 것이다.
init값을 안 넣어주면 1이 초깃값, 2가 cur로 들어가게 된다.
풀어서 쓰면 ⬇️
init value를 설정한 경우
{
let sum = numbers.reduce((acc, cur) => {
const result = acc + cur;
console.log(acc, cur, result)
return result;
}, 0);
console.log(sum); // 15
}
init value 없을 때 !
{
let sum = numbers.reduce((acc, cur) => {
const result = acc + cur;
console.log(acc, cur, result)
return result;
});
console.log(sum); // 15
}
Q. numbers 배열의 각 항목의 값에 13을 곱한 결과 중 짝수의 합을 구하시오.
내 코드 ⬇️
const numbers = [ 1, 2, 3, 4, 5 ];
console.log(numbers.map(n => n * 13).filter(n => n % 2 === 0).reduce((acc, cur) => acc + cur, 0));
예시 코드 ⬇️
const numbers = [ 1, 2, 3, 4, 5 ];
// 예제 1) numbers 배열의 각 항목의 값에 13을 곱한 결과 중 짝수의 합을 구하시오.
// ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~ ~~
// map filter reduce
const f1 = n => n * 13;
const f2 = n => n % 2 === 0;
const f3 = (a, c) => a + c;
const result = numbers.map(f1).filter(f2).reduce(f3, 0);
console.log(result); // 78
const result1 = numbers.map(f1);
const result2 = result1.filter(f2);
const result3 = result2.reduce(f3, 0);
console.log(result1); // [ 13, 26, 39, 52, 65 ]
console.log(result2); // [ 26, 52 ]
console.log(result3); // 78
// 콜백함수를 직접 정의
const result4 = numbers
.map(n => n * 13)
.filter(n =? n% 2 === 0)
.reduce((a, c) => a + c, 0);
Q. numbers 배열에서 짝수를 추출해서 13을 곱한 결과의 합계를 구하시오.
const result2 = numbers.filter(f2).map(f1).reduce(f3, 0);
console.log(result2); // 78
😇 로직이 변경되어도 쉽게 반영 가능하다 !!
Q. 점수가 80점 이상인 학생의 이름을 출력하시오.
내 코드 ⬇️
const students = [
{ name: '홍길동', age: 16, score: 88 },
{ name: '홍길서', age: 18, score: 78 },
{ name: '홍길남', age: 20, score: 98 },
{ name: '홍길북', age: 22, score: 68 }
];
const f1 = students.filter(student => student.score >= 80).map(student => student.name);
console.log(f1);
예시 코드 ⬇️
const f1 = student => student.score >= 80;
const f2 = student => student.name;
console.log(students.filter(f1).map(f2));
students.filter(f1).map(f2).forEach(name => console.log(name));
Q. 점수가 80점 이상이고, 나이가 20세 이상인 학생의 이름을 출력
const f3 = student => student.age >= 20;
const result = students.filter(f1).filter(f3).map(f2);
// 각 과목의 점수를 추출해서 합계를 계산
const ksum = scores.map(s => s.korean).reduce((a, c) => a + c, 0);
const esum = scores.map(s => s.english).reduce((a, c) => a + c, 0);
const msum = scores.map(s => s.math).reduce((a, c) => a + c, 0);
// 특정 과목의 점수를 추출해서 합계를 계산(반환)하는 함수를 정의
const sum = subject => scores.map(s => s[subject⭐️]).reduce((a, c) => a + c, 0); // subject로 변수로 들어온 값을 활용 !
// footer 출력
console.log('-----------\t----\t----\t----\t----\t----');
console.log(`총점\t\t${ksum}\t\t${esum}\t\t${msum}\t`);
console.log(`총점\t\t${sum('korean')}\t\t${sum('english')}\t\t${sum('math')}\t`);
console.log('-----------\t----\t----\t----\t----\t----');
여기서 s[subject] 이해를 덧붙이자면 객체의 키값을 변수로 가져오는 것이다. 그래서 대괄호를 사용한다!
챗지피티와 공부하자,, 문제를 만들어서 풀어보쟈 !
왁 !!! 1시간 일찍 끝났다 행복하다 ,,,
하루만에 html/css, 이틀만에 JavaScript를 다 나가다니 믿을 수가 없다...
그렇다고 내용이 부실하다거나 너무 코드 따라치는 느낌일까봐 걱정했는데 전혀 그렇지 않고 엄청 세세하고 원리를 이해하는 느낌으로 진도를 나가셨다!!
설명도 진짜 잘해주시고 실습도 적절했던 것 같다 굳굳
이해하는 데 힘든 건 없었는데 찬찬히 다시 많이 읽어봐야할 것 같다,,
그리고 미리 프론트 개념을 좀 알고 있으니까 꽤 괜찮은 것 같기도 하다.
몰랐던 개념이 보충되고 머릿속에서 정립된 느낌(?)
근데 이렇게 빠르게 많고 깊은 내용을 나가다 보니 나중에 백엔드 배울 때 좀 걱정된다 ..!! 올해 여름에 백엔드 스터디를 했지만 여전히 백엔드 잘 모르는지라,, 이렇게 빠르게 진도를 나가면 내가 잘 따라갈 수 있을지 조금 걱정된다 >....< 미리 예복습 잘 해서 백엔드도 적응할 수 있게 해야겠다!!
오늘 수업에서 확실하게 map, filter, reduce 를 그림 예시로 정확히 이해하고 넘어가니까 새로웠다.
map 함수 react 프로젝트하면서 엄청 많이 썼었는데 이때까지는 단순 컴포넌트 순회할 때만 쓰는 느낌인 줄 알았다.
오늘 수업 이후 알게된 정보를 바탕으로 map 함수를 사용하면 내가 필요한 객체의 키를 사용해서 원하는 객체의 정보만 쏙쏙 뽑아내 사용할 수 있어 유용하게 쓰일 것 같았다.
넘넘 신기하고 DB 다루는 느낌이라 재밌었다 ㅎㅎ
멋쟁이사자처럼 데모데이가 3일 뒤라... 난 마저 API 연결하러 가보겠다,, ㅠㅠ 주말에도 ☠️,.,.,.,. 다들 HAPPY 연말 보내시길 🥹