설모의 기록

[우아한테크캠프] 15일차 본문

일상/우아한테크캠프

[우아한테크캠프] 15일차

HA_Kwon 2018. 7. 21. 16:55



JavaScript 의 기초


오늘 배운 var, let, const 키워드와 함수에 대해 정리한 글입니다.

오늘은 CHROME 의 개발자도구 사용법과 JavaScript 의 기초 문법을 공부했습니다. JavaScript 는 매우 유연한 언어이며 컴파일러 언어가 아닌 한줄 한줄 읽어가며 실행하는 인터프리터 언어입니다. 또한 함수 단위로 Context 를 가지는 특징을 가지고 있습니다. 이 때문에 ES6 부터 let, const 키워드가 등장하기도 했습니다.


오늘 Crong 의 강의에서 배운 내용 중 Ojbect 와 Array 에 대해 정리해보겠습니다.




Object

클래스라는 틀을 이용해서 인스턴스를 생성하는 Java와는 달리 JavaScript는 특별한 클래스 없이 쉽게 객체를 생성할 수 있습니다. 간단한 객체 생성의 예제는 아래와 같습니다.

var woowaCamp = {
masters: [
{ name: "pobi", major: "java" },
{ name: "crong", major: "javascript" },
{ name: "honux", major: "linux" }
],
team: {
"team1": [],
"team2": [],
"team3": [],
"team4": [],
"team5": [],
"team6": [],
"team7": [
{ name: "hyeona", age: "24" },
{ name: "jongwhan", age: "30" },
{ name: "minseok", age: "26~27" },
{ name: "juha", age: "27" }
],
"team8": []
},
period: "2018.07.03 ~ 2018.08.31"
}

위와 같이 JavaScript 에서의 객체는 'key-value' 의 쌍으로 이루어져 있습니다. value에는 기본값뿐만 아니라 배열과 객체까지도 넣을 수 있습니다. 위와 같이 객체를 생성하면 실제 객체의 모습은 아래와 같습니다.


위와 같이 리터럴 방식으로 객체를 생성하는 방법 이외에도 아래와 같이,

var woowaCamp = new Object();
woowaCamp.period = "2018.07.03 ~ 2018.08.31";
...

이렇게 객체를 생성할 수도 있지만, 이런 방식은 key-value 를 하나하나 입력해주어야 하기 때문에 코드 길이도 길어지고 가독성에도 좋지 않아 피하는 코드입니다.




Array

JavaScript 에서 Array 는 Object 의 key 개념이 없는 객체라고 보시면 됩니다. key 를 따로 지정하지 않고 들어온 순서대로 0 부터 시작하는 인덱스를 갖습니다. 그 인덱스를 마치 key 와 같이 사용하는 형태입니다. 간단한 예제는 아래와 같습니다.


배열 생성

var team7 = [
{name: "hyeona", age: "24"},
{name: "jongwhan", age: "30"},
{name: "minseok", age: "26~27"},
{name: "juha", age: "27"}
]

배열에는 모두 같은 타입의 값만 넣지 않아도 되며, 객체나 배열 또는 여러 primitive type 값들을 섞어서 넣어도 괜찮습니다. 

간혹 배열을 아래와 같이 생성하는 경우가 있지만 이 패턴 또한 굳이 사용하지 않습니다. 그 이유는 다음과 같습니다.


var arr = new Array("HA", "JH", "JW", "MS"); // arr = ["HA", "JH", "JW", "MS"];

var arr = new Array(3); // arr = [empty * 3];

첫 번째 예제와 같이 배열을 생성하면 본인의 의도대로 배열이 생성됩니다. 그러나 주의해야 할 점은 두 번째 예제입니다.

두 번째 예제에서의 의도는 3 이라는 Number 타입 하나가 들어간 배열을 생성하기 위함이었는데, 실제로는 비어있는 길이 3짜리의 배열이 생성됩니다. 게다가 브라우저마다 초기값으로 넣어주는 것마저 다르기 때문에 프로그램의 버그를 발생시킬 수 있습니다. (위의 empty 는 크롬에서 제공합니다.)

따라서 본인 혹은 동료를 헷갈리게 하는 위와 같은 초기화는 피하고, 리터럴 형식으로 배열을 생성하는 것을 추천합니다.


이번에는 Array 의 prototype 에 있는 foreach, filter, map, reduce 메소드 사용법에 대해 알아보겠습니다.


foreach, filter, map, reduce


1. foreach

foreach 는 배열이나 object 의 value 를 하나하나 순회하며 value 를 이용해 수행해야 할 작업이 있을 때 사용하는 함수입니다. 이를 이용해 간단하게 사용한 예제는 아래와 같습니다.

const arr = ["hyeona", "jongwhan", "juha", "minseok"];
arr.forEach( value => console.log(value) );
// hyeona
// jongwhan
// juha
// minseok



2. filter

filter 는 특정 기준에 만족하는 값들만 필터링하고 싶을 때 사용하는 함수입니다. 간단한 사용 예제는 아래와 같습니다.

const arr = ["", 0, "true", "jk", undefined, null, false];
arr.filter(value => !value);




map 은 배열이나 object 를 순회하며 특정 작업을 수행한 후 그것의 결과값들로 이루어진 새로운 배열을 반환하는 함수입니다. 간단한 사용 예제는 다음과 같습니다.

const arr = ["hyeona", "jongwhan", "juha", "minseok"];
var teamArr = arr.map(value => "team7 " + value);
console.log(teamArr);
// ["team7 hyeona", "team7 jongwhan", "team7 juha", "team7 minseok"];



4. reduce

reduce 는 인덱스를 하나씩 증가시키며 해당 인덱스의 값과 다음 인덱스의 값으로 특정 작업을 수행한 후 하나의 결과로 합치고 싶을 때 사용하는 함수입니다. 간단한 사용 예제는 다음과 같습니다.

const arr = [1, 25, 45, 33, 2, 100, 78, 65];
var max = arr.reduce((prev, next) => {return Math.max(prev, next)});
console.log(max); // 100




배열이나 객체를 생성하면 __proto__ 속성이 눈에 띄는데요. 자주 사용하지는 않지만 의미를 파악하기 위해 정리하겠습니다.


__proto__

JavaScript에서는 __proto__ 속성을 이용해 객체지향인 척 코드를 구현할 수 있습니다. 일반적으로 객체를 생성하면 __proto__ 는 본인의 prototype 을 가리키고 있습니다. JavaScript 에서 prototype 은 Java에서 static 으로 생각하시면 이해가 쉬울 것입니다. 예를 들면, Array 의 prototype 에는 push(), pop() 과 같은 메소드가 있고 Array 객체는 모두 이 메소드를 공유해 사용합니다.

배열의 prototype 에 work 라는 함수를 추가한 후 간단한  배열을 생성해보겠습니다.

Array.prototype.work = function () {
return "woowa-tech-camp";
}

var arr = new Array();


arr 을 찍어보면 __proto__ 프로퍼티가 있으며, 클릭해보면 다양한 메소드와 함께 제가 정의한 work 라는 메소드도 있습니다. 즉, arr 의 __proto__ 타입은 아래와 같이 Array 의 prototype 을 가리키고 있습니다.

JavaScript 에서 최상위는 Object 입니다. 따라서 Array를 포함한 모든 객체는 그 객체의 __proto__ 를 따라가보면 Object 가 있을 것입니다.

이러한 __proto__ 체인을 이용해 객체지향적으로 객체를 표현할 수 있습니다. 간단한 예시를 보겠습니다.


function Parent(name) {
this.name = name || "father and mother";
}

Parent.prototype.say = function () {
return "eat breakfast!!!!!";
}


function Child(age) {
this.age = age || 20;
}


Child.prototype = new Parent();

var hyeona = new Child(24);

위의 코드를 실행해 객체를 생성한 후 크롬에서 찍어보면 위의 이미지와 같은 형태를 보실 수 있습니다. hyeona 라는 객체의 __proto__ 에는 new Parent() 가 연결되어 있으며그 것의 __proto__ 는 Parent.prototype 에 연결되어 있습니다. 더 나은 이해를 위해 아래의 그림으로 보겠습니다.


먼저 hyeona 라는 객체에 24라는 age 속성이 있고, __proto__ 는 new Parent() 객체를 가리키게 됩니다. 그리고 그 Parent 객체는 "father and mother" 라는 name 프로퍼티를 가지고 있으며, __proto__ 속성을 따라가보면 Parent.prototype 을 만날 수 있습니다. 따라서 아래와 같은 시도를 해볼 수 있습니다.


console.log(hyeona.age);    // 24
console.log(hyeona.name); // father and mother
console.log(hyeona.say()); // eat breakfast!!!!!

첮 번째 예제는 잘 이해되실거라 생각합니다. 

두 번째 예제를 보면 hyoena 의 객체 자체에 name 이라는 속성이 없으므로 __proto__ 를 따라가 new Parent() 의 father and mother 를 출력합니다.

마찬가지로 세 번째 예제를 보면, hyeona.say() 메소드를 호출하면 hyeona 객체에서 찾아본 후 없으면 __proto__ 프로퍼티가 가리키고 있는 new Parent() 로 따라가 찾아봅니다. 그 곳에도 없기 때문에 Parent 객체의 __proto__ 가 가리키고 있는 Parent.prototype 으로 가서 찾게 됩니다. 

이 패턴은 부모의 this 에 추가된 속성까지도 자식이 물려받는다는 점이 단점입니다.



위의 단점을 없애는 방법 중 한 가지는 다음과 같습니다.

function Parent(name) {
this.name = name || "father and mother";
}

Parent.prototype.say = function () {
return "eat breakfast!!!!!";
}


function Child(age) {
this.age = age || 20;
}


Child.prototype = Parent.prototype;

var hyeona = new Child(24);

위와 같이 수정하면 __proto__ 체인은 아래와 같습니다.



위의 그림과 같은 체인이 되기 때문에 hyeona 객체는 new Parent() 의 name 속성을 갖지 않고 Parent.prototype 에 있는 속성들만 물려받습니다. 따라서 아래 코드의 실행 결과는 다음과 같습니다.

console.log(hyeona.age);    // 24
console.log(hyeona.name); // undefined



이렇게 __proto__ 속성을 이용한 방법은 많이 있으니 찾아보거나 직접 실행해보시는 것도 좋을 것 같습니다.


참고서적


'일상 > 우아한테크캠프' 카테고리의 다른 글

[우아한테크캠프] 20일차  (8) 2018.07.28
[우아한테크캠프] 14일차  (0) 2018.07.19
[우아한테크캠프] 13일차  (1) 2018.07.18
[우아한테크캠프] 12일차  (1) 2018.07.18
[우아한테크캠프] 10일차  (0) 2018.07.14
Comments