[앱개발 종합반] 1주 2일차 개발일지(1주 5-7강, 숙제)


📱TIL App.102

1. JavaScript 기초 연습하기

1) 배열에서 특정 원소의 개수 구하기

let fruitList = ["apple", "banana", "banana", "grape", "strawberry", "apple", "grape", "apple"];

let count = 0;
for (let i = 0; i< fruitList.length; i++) {
  let fruit = fruitList[i];
  if (fruit == "apple") {
    count++;
  }
}

console.log(count);  // 3

특정 원소를 세는 데 쓰일 기준 변수(count)는 for문 바깥에 위치시켜야 하는데, 그 이유는 변수를 반복문 안에 위치시키는 경우 for문이 실행될 때마다 count도 함께 초기화되기 때문이다.



2) JSON 데이터에서 원하는 조건의 값 출력하기

JSON 데이터란 array와 object의 복합 구조를 나타낸다. 아무리 긴 JSON 데이터라도, array와 object의 복합 구조이기 때문에 반복문과 조건문 사용이 가능하다.

let mise_list = [
{
MSRDT: "201912052100",
MSRRGN_NM: "도심권",
MSRSTE_NM: "중구",
PM10: 22,
PM25: 14,
O3: 0.018,
NO2: 0.015,
CO: 0.4,
SO2: 0.002,
IDEX_NM: "좋음",
IDEX_MVL: 31,
ARPLT_MAIN: "O3",
},
...
{
MSRDT: "201912052100",
MSRRGN_NM: "동남권",
MSRSTE_NM: "강동구",
PM10: 24,
PM25: 14,
O3: 0.016,
NO2: 0.02,
CO: 0.4,
SO2: 0.002,
IDEX_NM: "좋음",
IDEX_MVL: 39,
ARPLT_MAIN: "PM25",
},
];

// 나의 코드
for (let i=0; i<mise_list.length; i++) {
  if (mise_list[i].IDEX_MVL < 40) {
    console.log(mise_list[i].MSRSTE_NM);
  }
}

// 예시 코드
for (let i=0; i<mise_list.length; i++) {
  let mise = mise_list[i];
  if (mise["IDEX_MVL"] < 40) {
    let gu_name = mise["MSRSTE_NM"];
    let gu_mise = mise["IDEX_MVL"]
    console.log(gu_name + " : " + gu_mise);
  }
}

예전에 object를 배울 때는 주로 dot notation을 사용했었는데, 스파르타에서는 웹/앱개발 모두 bracket notation을 쓰시는 듯하다. 역시 강사분 코드는 좀 다르다… 내 코드는 길이는 더 짧지만 조잡한 느낌이 있고, 나중에 같은 변수를 다시 사용할 수 없다. 장기적인 관점에서 코드를 오래 쓰려면, 또 한눈에 코드 작성자가 무엇을 나타내고자 했는지 알아볼 수 있게 하려면 코드를 좀 더 분리해서 쓰는 것이 좋겠다.

for문 안 첫 줄, 배열의 각 원소를 또다른 변수로 설정하는 것은 예전에 혼자 예제를 풀 때는 생각해본 적 없는 코드였다. Array의 각 element가 object고, 그 object의 key-value pair를 출력값으로 이용하고자 할 때, 이 방법을 이용하면 변수 길이를 줄이고 효과적으로 원하는 작업을 수행할 수 있을 것이다.


2. 앱개발에 자주 쓰이는 함축적인 JavaScript

우리는 React Native로 앱을 개발할 것이기 때문에, 최신 버전의 자바스크립트 문법(ES6)에서 사용되는 함축적이고 간결한 문법을 배워볼 것이다.

1) 화살표 함수

// 기존 방식(리터럴 방식)
let a = function() {
  console.log("function");
}
a();  // function

기존 함수의 정의에서는 변수를 함수 자체로 표현하는 리터럴 방식을 사용했다.

// 화살표 함수
let a = () => {
  console.log("arrow function");
}
a();  // arrow function

function 키워드가 빠지는 대신 화살표 모양(=>)의 기호를 사용해 함수임을 나타낸다.



2) 비구조 할당(destructuring)

let blog = {
  owner: "yendoz",
  url: "https://yendoz.github.io/",
  getPost() {
    console.log("Learn ES6");
  }
}

비구조 할당은 object에서 key-value 값들을 빠르게 꺼내는 데 사용된다. object에서는 ‘key : value’ 형태가 고정되어 있기 때문에 키에 굳이 “ “ 표시를 줄 필요는 없다.

// 기존 할당 방식
let owner = blog.owner;
let getPost = blog.getPost();

기존에는 object의 각 value값에 접근하고자 할 때 새로운 변수를 설정해 그 값을 담았다.


// 비구조 할당 방식
let {owner, getPost} = blog;
console.log(getPost);
/* 
  ƒ getPost() {
     console.log("Learn ES6");
   }
*/

단, 비구조 할당 방식을 사용할 때는 원래 object의 키 값과 변수 이름이 동일해야 한다. 키 값과 다른 이름의 변수를 정의하고 값을 출력하면 undefined가 출력된다.


// 함수로 object를 넘길 때의 비구조 할당 방식
let blogFunction = ({owner, url, getPost}) => {
  console.log(owner);
  console.log(url);
  console.log(getPost());
}

blogFunction(blog);
/*
  yendoz
  https://yendoz.github.io/
  Learn ES6
*/

위 코드에서는 blogFunction이라는 새로운 변수를 설정하고, parameter로 비구조 할당 방식을 사용해 object를 pass했다. 바로 blog를 pass하는 것과의 차이점은, 비구조 할당 방식으로 parameter가 전달되었기 때문에 함수 안에서 key 값을 바로 변수로 사용할 수 있다는 점이다. Object를 그대로 넘기면 함수 안에서 key 값에 대한 변수를 새로 선언해야 하므로 코드가 길어진다.

더 자세한 내용은 Destructuring and Spreading 읽어보기!



3) 리터럴(Template strings, Template literals)

back-tick( ) 키를 이용하면 \n과 같은 escape sequence를 이용하지 않고도 줄바꿈을 자유롭게 할 수 있다. 엔터 키를 사용했을 때 빈 공간을 줄바꿈으로 인식해 자동으로 줄바꿈을 해 준다.

또, 아래와 같이 ${}를 사용해 문자열 중간에 변수를 넣을 수 있다. 기존 방식보다 가독성이 좋고 읽기도 편하다. ‘‘나 ““가 아닌 back-tick 키를 사용해야 변수를 출력할 수 있다.

// 기존 방식
let name = "yendoz";
let myNameIs = "My name is " + name + "!";
console.log(myNameIs);
// My name is yendoz!


// 리터럴 방식
let myNameIs = `My name is ${name}!`
console.log(myNameIs);
// My name is yendoz!



4) 객체 리터럴

객체 리터럴을 사용해 object를 짧게 구성하는 방법을 배워보자.

// 기존 방식
let name = "yendoz"
let job = "developer"

let user = {
  name: name,
  job: job
}

console.log(user);
// {name: 'yendoz', job: 'developer'}

기존 방식에서는 객체(object)에 변수를 넣고 싶을 때, 넣으려는 변수를 미리 정의한 후 또다시 객체를 정의해서 변수를 넣었다.


let name = "yendoz"
let job = "developer"

let user = {
  name,
  job
}

console.log(user);
// {name: 'yendoz', job: 'developer'}

내가 처음 설정한 변수와 object에서의 key의 이름이 같고, object의 key에 그 변수를 할당하는 구조라면, key를 명시할 필요 없이 변수 이름만 입력해도 key-value pair가 자동 생성된다. 이렇듯 축약형을 쓰면 코드를 더 간결하고 가독성 있게 쓸 수 있다.



5) map

반복문에서 for문 대신 map을 사용하면 더 짧고 간결하게 코드를 작성할 수 있다.

// 기존 `for`문 사용
let numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i]);
}

for문을 사용하면 기본적으로 코드가 3줄 이상이며, for문의 실행 횟수를 위해 array의 length값을 알고 있어야 한다. map을 사용하면 array의 길이를 알아야 할 필요 없이, 더 짧은 코드로 반복문을 실행할 수 있다. map은 array에 사용되는 higher order function으로, parameter로 callback 함수를 받아 주어진 array에 대해 실행시킨다. array와 map은 연결 연산자(.)로 연결한다.

let numbers = [1, 2, 3, 4, 5];
numbers.map((value, i) => {
  console.log(`[${i}] ${value}`);
})
/*
  [0] 1
  [1] 2
  [2] 3
  [3] 4
  [4] 5
*/

함수가 실행될 때마다 map은 array에서 값을 하나씩 꺼내서 넘기는데, 위 예시에서는 주어진 배열에서의 element(원소, value)와 index값(i)을 받아 이를 [index] value 형태로 출력한다.


🤔 QnA

처음에는 아래 코드와 같이 출력 순서와 parameter의 순서가 동일하도록 i, value 순으로 parameter를 pass했는데 두 값이 바뀌어 나왔다.

let numbers = [1, 2, 3, 4, 5];
numbers.map((i, value) => {
  console.log(`[${i}] ${value}`);
})
/* 
  [1] 0
  [2] 1
  [3] 2
  [4] 3
  [5] 4
*/


map 공식 문서를 찾아 읽어보니 syntax가 아래와 같았다. map이 parameter로 받는 함수는 element, index, array를 parameter로 받을 수 있으며 그 순서가 정해져 있다.

const modifiedArray = arr.map(function(element, index, arr) {
  return element;
})

더 자세한 내용은 map 읽어보기!



6) 자바스크립트 파일 모듈화(module system)

실제 개발을 할 때는 자바스크립트 파일 이외의 여러 파일들이 생성된다. 예를 들어, 사칙연산과 같은 함수들만 담겨 있는 파일이 있을 수도 있고, 서버와 상호작용하는 로직이 담겨 있는 파일이 있을 수도 있다. 이러한 경우 필요한 자바스크립트 파일을 불러올 수 있으며, 이를 module system이라고 한다.

① export와 import

  • export : 외부에서 쓸 수 있는 준비 키워드

  • import : 외부에서 쓸 수 있는 준비된 함수를 불러오는 키워드

export는 해당 자바스크립트 파일이 파일 외부에서도 사용될 수 있다고 선언하는 키워드이며, importexport 선언된 다른 파일을 해당 자바스크립트 파일 안으로 가져오는 키워드이다.

util.js 파일 안의 두 가지 함수를 밖으로 내보내고 싶다면, 함수 앞에 export 키워드를 붙이면 된다.

// util.js 파일
export function square(x) {
  return x * x;
}
export function plusTwo(number) {
  return number + 2;
}


외부 파일인 index.js 파일에 util.js 파일을 불러와 해당 파일의 함수를 사용하려면, 아래 코드와 같이 import...from을 사용한다. 파일 이름에서 함수 이름을 꺼내는 식으로 함수를 불러온다.

// index.js 파일
import {square, plusTwo} from './util.js';
console.log(square(2));  // 4
console.log(plusTwo(3));  // 5


② export default

export default 키워드가 함수 앞에 붙어있다면, 그 함수가 든 파일 자체를 새로운 이름으로 명명해 함수를 불러올 수 있다.

// util.js 파일
export default function square(x) {
  return x * x;
}

// app.js 파일
import k from '.util.js';
console.log(k(4));  // 16


3. 복습 숙제

1) map을 이용해 배열에서 특정 원소의 갯수 구하기

  • ‘딸기’의 개수 구하기
// 'map' 사용
let fruit_list = ['사과','','','','포도','포도','딸기','포도','','수박','딸기'];

let count = 0;
fruit_list.map((element) => {
  if (element === '딸기') {
    count++;
  }
  console.log(count);
});  // 2

map은 array의 각 element를 돌면서 주어진 함수에 따라 element를 변화시키며, 새로운 array를 return한다. map도 하나의 반복문이기 때문에, 기준 변수(count)를 map 안에 위치시키면 count가 매번 초기화된다. 따라서 count의 정의는 map 바깥쪽에서 이루어져야 한다.

처음에는 아래 코드와 같이 map을 변수에 넣고, count를 return해 값을 출력하려고 했으나 map은 변하는 count 값을 담은 배열을 출력했다. 0, 1, 2는 count 값을 나타낸다.

// X
let fruit_list = ['사과','','','','포도','포도','딸기','포도','','수박','딸기'];

let count = 0;
let strawberry = fruit_list.map((element) => {
  if (element === '딸기') {
    count++;
  }
  return count;
});
console.log(strawberry);
// (11) [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2]


element를 돌며 정확히 ‘딸기’의 개수만 출력하고 싶다면, 조건에 맞는 element만 남긴 배열을 출력하는 filter를 사용할 수 있다.

// 'filter' 사용
let fruit_list = ['사과','','','','포도','포도','딸기','포도','','수박','딸기'];

let strawberry = fruit_list.filter((element) => 
  element === '딸기'
);

console.log(strawberry.length);  // 2



2) 이메일 판별하기 함수 만들기

① @가 있는지 없는지 확인(indexOf 사용)

function checkEmail(email) {
  if (email.indexOf('@') == -1) {
    console.log('이메일이 아닙니다.');
  } else {
    console.log('이메일이 맞습니다.');
  }
}

checkEmail('yendoz@gmail.com');  // 이메일이 맞습니다.
checkEmail('yendoz$gmail.com');  // 이메일이 아닙니다.

indexOf는 string(문자열)에서 특정 문자의 index를 출력하며, 특정 문자가 없을 경우 -1을 return한다. 특정 문자가 나타나지 않았을 때의 값이 -1이라는 점을 이용해 조건문을 작성할 수 있다.



  • 해설 코드
function checkEmail (email) {
  if (email.indexOf('@') < 0) {
    console.log("이메일이 아닙니다.");
  } else {
    console.log("이메일이 맞습니다.");
  }
}

강의 해설 코드에서는 ‘@’가 존재하지 않는다는 조건을 indexOf('@') < 0으로 표현했다. 실제로 string(문자열)의 index는 0부터 시작되기 때문에, ‘@’가 존재한다면 0 이상의 값을 가질 것이다.


② ‘자바스크립트 이메일 정규표현식’을 검색해 정규 표현식(regular expression)으로 구현해보기

function verifyEmail(email) {
  let regex = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;

  if (email.match(regex) != null) {
    console.log('이메일이 맞습니다.');
  } else {
    console.log('이메일이 아닙니다.');
  }
}

verifyEmail('.yendoz@gmail.com');  // 이메일이 아닙니다.
verifyEmail('yend_oz@gmail.com');  // 이메일이 맞습니다.
verifyEmail('yendoz6@gmail.c');  // 이메일이 아닙니다.
verifyEmail('yend__oz@gmail.com');  // 이메일이 아닙니다.
verifyEmail('yend__oz@.gmail.com');  // 이메일이 아닙니다.

‘자바스크립트 이메일 정규표현식’을 검색해 나온 이 사이트를 참고했다. match(regexp)는 문자열이 해당 패턴(regexp)과 일치하는지 아닌지를 검사한다. regex 부분이 복잡한데, 하나씩 분석해 보자. 관련 노트는 Regular expressions 참고!

/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;

정규 표현식(regular expression)에서는 / / 안에 내가 찾고자 하는 패턴을 넣는다. / / 뒤에는 g, i, m 등 여러 flag를 붙일 수 있다. 위의 코드에서는 i flag(ignore cases)가 사용되었는데, 이는 알파벳 대소문자를 구별하지 않고 패턴을 찾겠다는 뜻이다.

  • ^$은 각각 문자열의 시작과 끝을 의미한다.

  • [0-9a-zA-Z]는 하나의 문자가 [] 안에 위치한 규칙을 따른다는 뜻으로 0부터 9까지의 숫자, a부터 z까지의 영어 소문자 또는 A부터 Z까지의 영어 대문자인 경우를 나타낸다.

  • ()는 그룹으로 묶는 것을 뜻한다.

  • ?는 0개 또는 1개의 문자가 올 수 있음을 뜻하며, {0, 1}과 같은 의미이다. [-_.]?은 ‘-‘, ‘_’, ‘.’이 오지 않거나, 한 번만 올 수 있다는 뜻이다.

  • *는 0개 이상의 문자가 연속될 수 있음을 뜻하며, {0, }과 같은 의미이다.

  • {}은 문자의 개수를 나타내며, {2, 3}은 2글자에서 3글자 사이를 뜻한다.(.com, .co, .net, .kr 등)

  • @.은 각각 이메일에서의 @와 .을 찾기 위함이다.



  • 해설 코드
function checkEmail(email){
  //이메일 정규식
  let emailRule = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
  if(!emailRule.test(email)){
    console.log("이메일이 아닙니다.");
  }else{
    console.log("이메일이 맞습니다.");
  }
}

checkEmail("gunhee21@gmail.com");
checkEmail("gunhee21#gmail.com");

해설: 정규 표현식은 문자열에 나타는 특정 문자 조합과 대응시키기 위해 사용되는 패턴입니다. 자바스크립트에서, 정규 표현식 또한 객체입니다. 이 패턴들은 RegExpexec()test() method, 그리고 문자열(string)의 match(), replace(), search(), split() method와 함께 쓰입니다.

위 정규 표현식은 ‘@’ 가 이메일에 있는지 없는지를 판별하면서 동시에 ‘@’ 기준으로 앞뒤에 특수문자가 들어가면(ex) gunhee2#1@gmail) 이메일이 아님을 알려주는 간단한 정규표현식입니다.

‘gunhee@gmail’처럼 도메인 뒤에 ‘.com’이 없는 경우를 판별하려면 또 다른 정규표현식을 찾아 적용해야 합니다.

//도메인에 .com이 없는 경우까지 판별
function email_check( email ) {    
  let regex=/([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
  return (email != '' && email != 'undefined' && regex.test(email)); 
}

console.log(email_check('gunhee21@gmail'));  // false


Categories:

Updated:

Leave a comment