이번 파트는 문제만 블로깅하는거보단 개념적인 측면에서 먼저 확실하게 짚고 넘어가야 할 거 같다. 대충 대충 넘기다가는 또 리액트 들어가서 호되게 당할게 뻔하기 때문에..
객체는 특정 키의 값을 가져와 활용하는 방법도 있지만, 반대로 객체에 특정 키를 만들고 값을 할당하는 방법 또한 있다.
const information = {
name: '김행갬'
}
우선 information이라는 객체를 하나 만들고, 그 안에 name이라는 key와 value 값을 할당해주었다. 여기에 키 하나를 생성하고, 그 키에 값을 할당해주려고 할때, 평소와 같으면 이런식으로 생성을 했을 것이다.
information.developes = 'facebook'
이런 방식으로도 물론 할당이 가능하지만, 이러한 경우에는 키와 값이 항상 정해져 있게 된다. 그렇다면 키와 값을 변수를 통해 받아온다면 어떻게 될까?
const verb = 'developes';
const project = 'facebook';
information[verb] = project;
이런 방식으로 키와 값을 할당하면, 변수 verb와 project가 가지는 값에 따라 다른 키와 다른 값을 가지는 것이 가능해진다! WOW!
우리는 배열을 순회할 때 for 문을 사용했다. for 문을 사용하면 같은 계산을 여러번 하는 것을 한 번의 코딩으로 해결할 수 있게끔 해준다. 배열은 명확하게 정해진 순서가 있었기 떄문에, 순서에 따라 인덱스에 접근할 수 있었지만, 객체는 명확하게 순서가 정해지지 않기 때문에, 어떤 순서에 따라 객체의 키에 접근하게 될지 알 수 없다. 이러한 객체의 순회를 "순서가 보장되지 않은 순회" 라고 부른다.
그렇다면 객체에 있는 모든 키에 한번씩 접근하기 위해 객체의 반복문을 작성하려면 어떠한 방법들을 사용해야 할까?
Object.keys
메서드는 어떤 객체가 가지고 있는 키들의 목록을 배열로 리턴하는 메서드이다. 이는 객체의 내장 메서드가 아닌, Object
(객체 생성자)가 직접 가지고 있는 메서드이다.
const developer = {
name: '김행갬',
age: 26,
field: 'Front-end'
handsome: true,
}
Object.keys(developer) // ['name', 'age', 'field', 'handsome']
Object.keys
메서드는 객체 키들의 목록을 배열로 리턴한다고 했다. 배열은 명확하게 정해진 순서가 있기 때문에, 이것으로 우리는 반복문을 사용할 수 있다.
const keys = Object.keys(developer) // ['name', 'age', 'field', 'handsome']
for (let i = 0; i < keys.length; i++) {
const key = keys[i] // 각각의 키
const value = developer[key] // 각각의 키에 해당하는 각각의 값
console.log(value) // ['
}
Object.keys
메서드 외에도 Object.values
, Object.entries
와 같은 Object
생성자의 메서드들이 ES6 문법에 추가되 었다. Object.values
는 객체의 키가 아닌 값으로 배열을 리턴하고, Object.entries
는 객체의 키와 값의 쌍으로 이루어진 길이 2짜리 배열로 이루어진 배열을 리턴한다.
const values = Object.values(obj)
// values === ['김행갬', 26, 'Front-end', true]
const entries = Object.entries(obj)
/*
entries === [
['name', '김행갬'],
['age', 26],
['field', 'Front-end'],
['handsome', true]
]
*/
객체를 순회하는 두 번째 방법은 for-in 문이다. for
문과 같은 종류의 문법이지만, 객체 순회 외에도, 일반적인 배열을 순회할때도 유용하게 사용할 수 있다.
const arr = ['coconut', 'banana', 'pepper', 'coriander']
for (let i = 0; i < arr.length; i ++) {
console.log(i)
console.log(arr[i])
}
// for-in 문을 사용해 축약한 문법
for (let i in arr) {
console.log(i)
console.log(arr[i])
}
for-in 문을 사용하면 for
문에서 자주 사용되는 for(let i = 0; i < arr.length; i ++)
와 같은 문법을 간단하게 축약할 수 있다. 이 for-in 문은 인덱스의 값으로 무엇을 할당하고, 반복문이 몇번 돌아가야 할 지를 자바스크립트 엔진 내부에서 자동하게 결정하게 된다.
const developer = {
name: '김행갬',
age: 26,
field: 'Front-end'
handsome: true,
}
for (let key in developer) {
const value = developer[key]
console.log(key)
console.log(value)
}
이렇게 객체를 가지고 for-in 문을 사용하면, for-in 문의 인덱스에 해당하는 변수가, 숫자가 아닌 객체의 각각의 키에 해당하는 문자열을 할당받게 된다. 그렇다면 공부한 내용들을 활용해서 문제를 풀어보도록 하자!
아래 설명을 읽고 getExamResult 함수를 구현하세요.
인자 scores 는 다음과 같은 객체입니다. 객체의 요소의 갯수 및 키의 이름들은 달라질 수 있습니다. 객체의 값은 다음 9가지 문자열 중에서 하나를 가지고 있습니다.
- 'A+', 'A', 'B+', 'B', 'C+', 'C', 'D+', 'D', 'F'
{ '생활속의회계': 'C', '논리적글쓰기': 'B', '독일문화의이해': 'B+', '기초수학': 'D+', '영어회화': 'C+', '인지발달심리학': 'A+', }
인자 requiredClasses 는 다음과 같이 문자열로 된 배열입니다.
['영어회화', '기초수학', '공학수학', '컴퓨터과학개론']
다음 조건을 만족하는 객체를 리턴하도록 함수를 구현해주세요.
1. scores 객체가 가지고 있는 키들은 새로운 객체에 포함되어야 합니다. 단, 그 값들은 다음 원리에 따라 숫자로 바뀌어 할당되어야 합니다.
- A+ => 4.5
- A => 4
- B+ => 3.5
- B => 3
- C+ => 2.5
- C => 2
- D+ => 1.5
- D => 1
- F => 0
requiredClasses
배열의 요소로는 존재하지만,scores
의 키로는 존재하지 않는 항목이 있다면, 해당 요소는 새로운 객체의 키가 되고, 값으로 0을 가져야 합니다. 위에서 예시로 묘사된 객체와 배열이 인자로 들어왔다면, 다음과 같은 객체과 리턴됩니다. 요소간 순서는 다를수 있지만, 채점에 무관합니다.{ '생활속의회계': 2, '논리적글쓰기': 3, '독일문화의이해': 3.5, '기초수학': 1.5, '영어회화': 2.5, '인지발달심리학': 4.5, '공학수학': 0, '컴퓨터과학개론': 0, }
const getExamResult = (scores, requiredClasses) => {
const result = {};
let grade = {
'A+' : 4.5,
'A' : 4,
'B+' : 3.5,
'B' : 3,
'C+' : 2.5,
'C' : 2,
'D+' : 1.5,
'D' : 1,
'F' : 0
}
for (let i=0; i < requiredClasses.length; i++) {
let keys = requiredClasses[i];
result[keys] = 0;
}
for (let scores_key in scores) {
let scores_value = scores[scores_key];
let grade_value = grade[scores_value];
result[scores_key] = grade_value;
}
return result;
}
솔직히 문제를 처음 읽고 든 생각은
우선 scores 객체가 가지고 있는 키들을 새로운 객체에 포함하고, 값을 숫자로 바꾸어야 하기 때문에 새로운 객체인 grade에 값을 숫자로 바꿔서 할당시키는 것 까지는 이해가 되었다.
2번째 조건이 문제였는데, scores의 키로는 존재하지 않지만 requiredClasses의 배열의 요소로 존재하는 항목을 새로운 객체의 키로 추가하여 값을 0으로 리턴해 준 뒤, 모든 객체와 배열이 인자로 들어왔다면, requiredClasses 배열의 요소를 키로 가지고, 숫자로 바뀌어 할당된 grade 객체의 값들을 값으로 가지는 객체를 리턴해야 한다.
우선 헷갈렸던 점이, scores의 키로 존재하지 않지만 requiredClasses의 배열의 요소로 존재하는 항목을 새로운 객체에 추가하여 값을 0으로 리턴해주는 것과, 각 배열과 객체 요소들에 대하여 어떻게 접근해야 하는지에 대한 점이었다.
requiredClasses 배열에만 존재하는 과목(요소)들을 추가해주기 위해서, for문으로 requiredClasses를 순회하며 0을 값으로 리턴하는 과목들을 key로 result 객체에 추가해주었다. 이러면 scores에 포함되지 않은 과목들도 추가되어 모든 과목들이 result안에 key로 존재할 수 있게 된다.
그 다음에는 for-in 문을 사용하여 scores 객체를 순회하며 scores_key라는 변수를 인덱스 값으로 가진 뒤, scores_value라는 변수에 scores[scores_key]
값을 할당해 주었다. 그러면 scores_value라는 변수는 C, A+, D, B+
과 같은 값을 가지게 된다. 그리고 이 scores_value
변수를 grade[scores_value]
와 같이 선언하여 문자를 숫자로 바꾸어 할당해 준 뒤, 이를 grade_value
변수에 할당해 준다.
마지막으로, result[scores_key] = grade_value;
구문을 통해 result 객체에 scores_key
를 키로 갖고 grade_value
를 값으로 갖는 프로퍼티들을 추가해주면? scores와 requiredClasses의 모든 과목을 키로 갖고 숫자로 치환된 값들을 가지는 새로운 객체가 return되게 된다!
function convertGrade(grade) {
const convert = {
'A+' : 4.5,
'A' : 4,
'B+' : 3.5,
'B' : 3,
'C+' : 2.5,
'C' : 2,
'D+' : 1.5,
'D' : 1,
'F' : 0
}
return convert[grade];
}
function getExamResult(scores, requiredClasses) {
const result = {};
for(const property in scores) {
result[property] = convertGrade(scores[property])
}
requiredClasses.forEach(subject => {
if(!(subject in scores)) {
result[subject] = 0;
}
})
return result;
}
사실 이 문제는 첫번째 for문만 접근에 성공했고, 뒷 부분은 구글에서 다른 기수분들이 해결한 방법을 참고하여 풀 수 있었던 문제였다. 사실 블로깅을 하면서도 잘 이해가 되지 않아서 코드를 다시 한번 하나씩 뜯어보며 작성할 수 있었고, 작성이 완료된 지금도 완벽하게 이해했다고는 생각되지 않는다.. 객체의 키를 변수로 접근하는 방법과, for-in 문이 여태 자바스크립트를 어느 정도 공부해왔음에도 몹시 낯선 느낌이었다. 해당 부분들은 다시 한번 공부하면서 확실하게 짚고 넘어가야겠다!