[JS] TIL 4. 객체와 배열 다루기
in PROGRAMING STUDY on Javascript
객체
1.1 배열과 객체의 특징과 사용을 배열 및 객체 구조를 포함하여 서술하라.
1.2 객체 속성(property)의 추가, 삭제, 조회에 대해서 코드 예와 함께 서술해라.
1.3 배열과 객체, 반복문을 응용하여 능숙하게 대량의 정보를 다룰 수 있는가? 예를 들어 서술해라.
배열 다루기
2.1 배열과 반복문을 활용하여 실생활에서 접할 수 있는 간단한 문제를 예로 들어 해결 방법을 서술하시오.
2.2 문자열과 배열의 형태 변환을 돕는 메소드를 서술해라.
2.3
for문
을 대체하여,forEach
,map
,filter
,reduce
,slice
등의 메소드를 이용해 배열을 원하는 형태로 만들 수 있는가. 그 예를 들어라.2.4 어떤 메소드가 Mutable/Immutable 한지 불변성의 의미를 포함하여 서술해라.
2.5 변성을 유지하는 것이 왜 좋은가?
2.6 함수형 프로그래밍의 특징을 아는데로 서술해라.
Codestates의 소프트웨어 엔지니어링 강의를 듣고 정리한 필기입니다. 😀
1. 객체(Object)
1.1 구문
let userFirstName = 'River';
let userLastName = 'Park';
let userEmail = 'river.nameless@gmail.com';
let userCity = 'Seoul';
let user2FirstName = 'Angelina';
let user2LastName = 'Jolie';
let user2Email = 'jolieisgod@fakemail.com';
let user2City = 'California';
회원주소(프로필)를 만든다고 가정해보자. 회원 한 명의 주소록을 만드는 데에 변수가 자그마치 4개나 필요하다. 여기서 한 사람을 추가한다면 변수는 8개, 한 사람을 더 추가한다면 변수가 12개나 필요할 것이다.
여기서 문제는 비단, 변수를 많이 선언해야 한다는 것뿐일까? 가장 핵심적인 문제는 변수끼리 아무런 관계가 없다는 것이다. 사람 볼 때야 변수들이 user로 시작하기 때문에 상관관계가 있어 보이지만, 컴퓨터는 그렇지 않다는 것이다. 변수는 데이터를 이름으로 구분할 뿐, 서로 어떤 관계도 이어주지 않는다는 사실을 기억하자.
let user1 = [
'River',
'Park',
'river.nameless@gmail.com',
'Seoul'
];
let user2 = [
'Angelina',
'Jolie',
'jolieisgod@fakemail.com',
'California';
]
그렇다면 TIL 3에서 배운 배열은 어떨까?
얼핏 보면 user 별로 나누었기 때문에 관계성이 있어 보인다. 컴퓨터도 한 한 사람의 정보라는 것을 알 수 있다. 하지만, 우리가 배열 안의 요소에 접근하기 위해서는 몇 번째 인덱스에 무슨 데이터가 들어가 있어야 하는지 알아야 한다. 이것을 모를 경우 몇 번째 인덱스에 무슨 데이터가 들어가 있는지 알기 위해서는 인덱스를 각각 찍어봐야 한다. 즉, 배열에 대한 구조를 알고 있는 사람만이 이 배열을 사용할 수 있다는 뜻이다.
let user1 = {
firstName : 'River',
lastName : 'Park',
email : 'river.nameless@gmail.com',
city : 'Seoul'
};
let user2 = {
firstName : 'Angelina',
lastName : 'Jolie',
email : 'jolieisgod@fakemail.com',
city : 'California'
};
그럴 때 사용하는 것이 객체이다. 객체는 주소록처럼, 한 사람에 대한 정보들이 하나의 변수 안에 담겨야 할 때 적합하다. firstName
, lastName
, email
, city
는 key
(키, 혹은 property
라고도 부른다.)라고 불리고, 뒤에 나오는 스트링은 값(value) 라고 불린다. 키 (key) 와 값(value)은 :
(콜론)으로 구분하고, 다른 키와는 ,
(콤마)로 구분한다. 이 모든 요소는 중괄호(curly bracket)로 감싸져 있다. 즉, 객체는 중괄호로 감싸진 키와 값의 쌍(key-value pair)으로 이루어져 있다.
1.2 키와 값에 접근하기
user1.firstName; // => 'River' : Dot notation
user1['firstName']; // => 'River' : Bracket notation
user1[firstName]; // => error : Uncaught ReferenceError: firstName is not defined
객체 값에 접근하는 방법은 총 두 가지가 있다. Dot notation 과 Bracket notation이라고 하는 것이다.
▶ Dot notation의 형태는 익숙할 것이다. Array의 길이를 검색할 때(배열명.lenght
) 본 형태이다.
▶ Bracket notation은 대괄호(Square Bracket)로 감싸진 형태를 하고 있다. 대괄호 안에 키 이름을 써줘야 하는데, 꼭 따옴표(큰따옴표 혹은 작은따옴표)로 감싸줘야 한다. 만약 따옴표로 안 감싸 줄 경우 변수로 취급된다.
user1.'River' // => error : Uncaught SyntaxError: Unexpected string
user1.River // => undefined
user1['River'] // => undefined
user1[River]; // => error : Uncaught ReferenceError: River is not defined
Object.keys(user1); // => ["firstName", "lastName", "email", "city"]
객체의 키 이름이 필요할 때는 어떻게 해야할까?
애석하게도 값(value)에 접근하기 위해 키(key)를 사용했을 때와는 달리 키(key)에 접근할 때는 값(value)으로 접근할 수 없다. 또한, firstName
혹은 lastName
키(key) 하나하나 접근 또한 어렵다. 객체의 키 이름에 접근하는 방법은 `Object.keys()`라는 메소드를 사용하는 것인데, 이것은 객체의 키 목록을 배열의 형태로 가지고 온다.
배열처럼 객체에도 for...in..
문이 존재한다. Object.keys()
와 마찬가지로 모든 키 값을 출력한다.
동일한 방법으로 값(value)에도 접근이 가능하다.
1.3 객체의 길이
user1.length; // => undefined
user1[1] // => undefined
객체는 길이를 알 수 없다. 순서가 있어 인덱스로 접근이 가능했던 배열과는 달리 객체는 인덱스가 존재하지 않기때문이다. 객체명.length
도 객체명[인덱스]
도 접근할 수 없다.
1.2 키와 값에 접근하기에서 키와 값에 접근하기 위해서 for문
이 아니라, for... in...문
만 언급하고, 모든 키값을 출력하는 방법뿐이 없다고 소개한 이유도 객체에는 인덱스, 즉 길이가 존재하지 않기 때문이다.
1.4 객체의 추가와 수정
user1['age'] = 27 // => "27"
user1
// => { firstName: "River",
// lastName: "Park",
// email: "river.nameless@gmail.com",
// city: "Seoul",
// age : 27 }
객체에 새로운 키와 값을 추가하는 것은 간단한 일이다. 《 객체명[새 키 이름] = 새 값
》 을 해주면 맨 마지막에 추가된다.
user1['firstName'] = 'RIVER' // => "RIVER"
user1
// => { firstName: "RIVER",
// lastName: "Park",
// email: "river.nameless@gmail.com",
// city: "Seoul",
// age : 27 }
그렇다면 새 키 이름이 아니라 기존에 있던 이름으로 해주면 어떻게 될까? 그러니까. 《 객체명[새 키 이름] = 새 값
》 **이 아니라, 《 **객체명[기존 키 이름] = 새 값
》으로 해주면 말이다.
위 코드를 보면 마지막에 firstName : 'RIVER'
가 추가되는 것이 아니라, 기존에 있던 firstName
의 값이 수정되는 것을 볼 수 있다. 1.2 키와 값에 접근하기에서 “키(key)에 접근할 때는 값(value)으로 접근할 수 없다.“라는 말을 기억하는가? 여기서 그 이유를 알 수 있다. 키(key)는 중복이 불가능하지만 값(value)은 가능하기 때문이다. 때문에 기존 키 값(객체명[기존 키 이름] = 새 값
)에 새 값을 넣어주면 새로운 키와 값이 추가되는 것이 아니라 기존 키의 값이 수정된다.
1.4 객체의 삭제
delete user1.age // => true
delete user1 // => false
객체의 요소를 삭제하기 위해서는 《 delete 객체이름.키
》를 해주면 된다.
2. 배열 다루기
2.1 추가 및 삭제 (push
, pop
, unshift
, shift
)
let user = [
'River',
'Park',
'river.nameless@gmail.com',
'Seoul'
];
user.push(27); // => 5 : 맨 뒤에 추가해주면서 추가 후의 배열 길이를 출력
user.push('student', 'female'); // => 7 : 여러개도 추가 가능.
user.unshift('RIVER'); // => 4 : 맨 앞에 'River'를 추가 후, 배열의 길이를 출력
user.pop(); // => 'female' : 맨 마지막 값을 삭제 후, 삭제한 값을 출력
user.shift(); // => 'RIVER' : 맨 앞의(0번째 인덱스) 값을 삭제 후, 삭제한 값을 출력
.push()
: 맨 뒤에 element 추가.pop()
: 맨 뒤에 element 삭제.unshift()
: 맨 앞의 element 추가.shift()
: 맨 뒤의 element 삭제
2.2 조회 (indexof
)
user.indexOf('River'); // => 0 : 찾고자 하는 요소가 배열 안에 존재하면 인덱스 값을 출력
user.indexOf('없는단어'); // => -1 : 찾고자 하는 요소가 배열 안에 없으면 -1 출력
.indexof()
: element 포함 여부 확인. (있으면 인덱스값을, 없으면 -1을 출력)
2.3 배열 자르기 (slice
)
let user = [
'River',
'Park'
];
user.slice(0,1); // => ["River"]
user; // => ["River", "Park"] : 원본이 변하지 않는 새로운 배열을 만듬
user.slice(0); // => ["River", "Park"] : 괄호 안에 0을 주면 모두 가지고 온다.
let userFirstName = user.slice(0,1);
userFirstName // => ["River"]
.slice(시작 인덱스, 끝 인덱스 +1 )
: 원본이 변하지 않는 새로운 배열을 만들며, 배열의 일부부분을 잘라낼 수 있다. (2,3 번 인덱스만 가지고오고 싶으면user.slice(2,4)
로 해주면 된다.)
2.4 forEach
, map
, filter
// object가 세 개가 담긴 배열.
// object는 인물의 특징을 담고 있으며, 프로그래밍을 하다보면 많이 보게될 패턴이다.
// 한 사람의 목록이 담겨있고, 그것들이 쌓여있는, 일종의 데이터베이스 형태.
let users = [
{ name : 'River', age : 27},
{ name : 'Angelina', age : 45},
{ name : 'Minnie', age : 22}
];
// 각 사람의 이름을 출력해보자.
for (let el of users) {
console.log( 'Name : ' + users[el].name);
}
/*
*=> Name : River
* => Name : Angelina
* => Name : Minnie
*/
// 다른 방법이 없을까?
function printName(user) {
console.lgo('Name : ' + user.name);
}
users.forEach(printName))
/*
=> Name : River
=> Name : Angelina
=> Name : Minnie
*/
.forEach( )
: 메서드는 주어진 함수를 배열 요소 각각에 대해 실행한다.
let users = [
{ name : 'River', age : 27},
{ name : 'Angelina', age : 45},
{ name : 'Minnie', age : 22}
];
function getName(user) {
return user.name;
}
gitName({ name : 'River', age : 27}) // => "River"
users.map(getName); // => ['River', 'Angelina', 'Minnie'] : 배열의 형태로 출력
.map( )
: 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.
let users = [
{ name : 'River', age : 27},
{ name : 'Angelina', age : 45},
{ name : 'Minnie', age : 22}
];
// 25 이상인 사람만 모아 배열로 출력하고자 한다.
function moreThan25(user) {
return user.age > 25;
}
users.filter(moreThan25);
/*
=> [
{ name : 'River', age : 27},
{ name : 'Angelina', age : 45}
];
*/
.filter(조건)
: 메서드는 주어진 Array 중 조건을 통과하는 요소를 모아 새로운 배열로 반환한다.
2.5 reduce (reducer, [initialValue])
reduce의 작동원리는 배열의 축소이다. 배열에서 문자열로, 배열에서 숫자로, 배열에서 객체로, 여러 개의 값이 담긴 배열을 줄여서(reduce) 최종적으로 하나의 값으로 만드는 과정이다. 여기서 배열을 하나의 값으로 만드는 함수를 리듀서(reducer)라고 한다
▶ 리듀스 함수의 파라미터는 누적값(accumulator), 현재 엘리먼트(value), 인덱스(index), 원본배열(array) 순이다.
function reducer ( accumulator, value, index, array ) {
// TODO : accumulator에 값을 누적시킨다.
return accumulator // 새롭게 누적된 값
}
let expectedResult = {
'Seoul': 0,
'California': 0
}
users.reduce(reducer, expectedResult)