Kotlin과 Java차이

  • 함수를 선언할때 'fun'이라는 키워드를 사용한다.
  • 파라미터 이름 뒤에 파라미터 타입을 쓴다.  Java의 경우 'String[] args'로 타입을 먼저 쓰고 이름을 쓰지만, 코틀린은 'args:Array<String>'형식을 사용한다.
  • 최신 프로그래밍 추세에 따라 문장 끝에 세미콜론을 붙이지 않아도 된다.
  • 함수의 반환값이 없는 경우,'void'를 표시하지 않고 생략한다.

'공부내용정리 > 안드로이드' 카테고리의 다른 글

Java의 정적 유틸리티 클래스  (0) 2021.08.25
코틀린 함수  (0) 2021.08.25
코틀린 val과 var의 차이  (0) 2021.08.11
Kotlin 변수  (0) 2021.08.08
Kotlin에 대하여  (0) 2021.08.06

Kotlin의 특징

  • 코틀린은 'Java'와 100% 상호 호환되면서도 더 현대적이고 간결하다. 때문에 Java와 코틀린 코드를 하나의 프로젝트에서 섞어 사용할 수도 있다.
  • 'Null Pointer Exception'이 발생할 수 있는 코드를 금지하고 Null에 대해 안전한 코드를 간결하게 표현 할수 있도록 지원한다.
  • 코틀린은 '타입 추론'을 지원한다. 때문에 정적 타입 지정 언어가 가진 정확성과 성능을 보장하면서도 동적타입 언어와 같은 간결함을 유지할 수 있다.
  • 람다 표현식을 지원한다. 코틀린의 람다 표현식은 'Java 8'부터 지원되는 람다 표현식 보다 더 간결하다.
  • '객체 지향'프로그래밍과 '함수형'프로그래밍 스타일을 모두 지원한다.
  • 코틀린의 '확장 함수'는 기존 클래스의 변경 없이 클래스의 기능을 추가하는 것이 가능하다.
  • 코틀린은 이미 널리 쓰이는 '코드 패턴을 간결화 할수 있도록 설계' 되었다.예를들면 'getter,setter'를 묵시적으로 제공하고 자주 쓰이는 'Singletone 패턴'은 'object'로서 지원한다.
  • 코틀린의 함수는 '일급 객체'로서 다른 함수의 파라미터로 전달 가능하고 함수의 반환 값을 함수 형태로 반환할수 있어 '높은 추상화가 가능'하다
  • 코틀린의 'Android Extension'을 사용하면 'findViewId()'함수로 접근해야 했던 코드들을 줄일 수 있어 소스코드를 획기적으로 간결하게 유지할 수 있다.
  • 코틀린은 유명 IDE 제작 회사인 JetBrain이 만든 언어로, 같은 회사에서 만든 Intellij및 Android Studio IDE에서 매우 잘 지원되는 언어이다.

'공부내용정리 > 안드로이드' 카테고리의 다른 글

Java의 정적 유틸리티 클래스  (0) 2021.08.25
코틀린 함수  (0) 2021.08.25
코틀린 val과 var의 차이  (0) 2021.08.11
Kotlin 변수  (0) 2021.08.08
Kotlin과 Java차이  (0) 2021.08.06

이번에는 컴포넌트의 props라는 개념에 대해서 알아보자.props는 properties의 줄임말이다. 우리가 어떠한 값을 컴포넌트에게 전달해줘야 할 때, props를 사용한다.

 

props의 기본 사용법

예를 들어서, App컴포넌트에서 Hello컴포넌트를 사용할떄 name이라는 값을 전달해주고 싶다고 가정해보자. 그러면 이렇게 코드를 작성하면 된다.

 

App.js

 

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello name="react" />
  );
}

export default App;

 

이제 Hello컴포넌트에서 name값을 사용하고 싶을땐 어떻게 사용하면 되는지 알아보자.

 

Hello.js

 

import React from 'react';

function Hello(props) {
  return <div>안녕하세요 {props.name}</div>
}

export default Hello;

컴포넌트에게 전달되는 props는 파라미터를 통하여 조회할수 있다. props는 객체 형태로 전달되며, 만약 name값을 조회하고 싶다면 props.name을 조회하면 된다.

 

여러개의 props,비구조화 할당

Hello컴포넌트에 또 다른 props를 전달해보자. color라는 값을 설정해보자.

 

App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello name="react" color="red"/>
  );
}

export default App;

그 다음에는 Hello컴포넌트에서 color값을 조회해서 폰트의 색상으로 설정을 해보자.

 

Hello.js

import React from 'react';

function Hello(props) {
  return <div style={{ color: props.color }}>안녕하세요 {props.name}</div>
}

export default Hello;

props내부의 값을 조회 할 때 마다 props.를 입력하고 있는데, 함수의 파라미터에서 비구조화 할당 문법을 사용하면 조금 더 코드를 간결하게 작성 할수 있다.

 

Hello.js

import React from 'react';

function Hello({ color, name }) {
  return <div style={{ color }}>안녕하세요 {name}</div>
}

export default Hello;

defaultProps 로 기본값 설정

컴포넌트에 props를 지정하지 않았을 때 기본적으로 사용 할 값을 설정하고 싶다면 컴포넌트에  deraultProps라는 값을 설정 하면된 된다.

 

Hello.js

import React from 'react';

function Hello({ color, name }) {
  return <div style={{ color }}>안녕하세요 {name}</div>
}

Hello.defaultProps = {
  name: '이름없음'
}

export default Hello;

한번 App에서 name이 없는 Hello컴포넌트를 렌더링 해보자.

 

App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <>
      <Hello name="react" color="red"/>
      <Hello color="pink"/>
    </>
  );
}

export default App;

props.children

컴포넌트 태그 사이에 넣은 값을 조회하고 싶을땐,

props.children을 조회하면 된다.

이번에 props.children을 사용하는 새로운 컴포넌트를 만들어 보자.

Wrapper.js를 src디렉터리에 만들어 보자.

 

Wrapper.js

import React from 'react';

function Wrapper() {
  const style = {
    border: '2px solid black',
    padding: '16px',
  };
  return (
    <div style={style}>

    </div>
  )
}

export default Wrapper;

이 컴포넌트를 App에서 사용해 보자.

 

App.js

import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';

function App() {
  return (
    <Wrapper>
      <Hello name="react" color="red"/>
      <Hello color="pink"/>
    </Wrapper>
  );
}

export default App;

이렇게 Wrapper태그 내부에 Hello태그 내부에 Hello컴포넌트 두개를 넣었는데, 브라우저를 확인하면 다음과 같이 Hello컴포넌트들은 보여지지 않을 것이다.

내부의 내용이 보여지게 하기 위해서는 Wrapper에서 props.children을 렌더링해주어야 한다.

 

Wrapper.js

import React from 'react';

function Wrapper({ children }) {
  const style = {
    border: '2px solid black',
    padding: '16px',
  };
  return (
    <div style={style}>
      {children}
    </div>
  )
}

export default Wrapper;

 

'공부내용정리 > React' 카테고리의 다른 글

JSX의 기본규칙  (0) 2021.05.03
나의 첫번째 리액트 컴포넌트  (0) 2021.04.29

JSX는 리액트에서 생김새를 정의할때 사용하는 문법이다.

얼핏보기에는 html같이 생격지만 실제로는 JavaScript이다

return <div>안녕하세요</div>;

리액트 컴포넌트 파일에서 XML형태로 코드를 작성하면 bable이 JSX를 JavaScript로 변환을 해준다.

어떻게 변환되는지 한번 예시를 보자

Babel은 자바스크립트의 문법을 확장해주는 도구이다.

아직 지원되지 않는 최신 문법이나, 편의상 사용하거나 실험적인 자바스크립트 문법들을 정식 자바스크립트 형태로 변환해 줌으로서 구형 브라우저 같은 환경에서도 제대로 실행할수 있게 해주는 역할을 한다.

 

꼭 닫혀야 하는 태그

태그는 꼭 닫혀있어야 한다.

다음과 같은 코드는 오류가 발생하게 된다.

 

App.js

 

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
      <Hello />
      <Hello />
      <div>
    </div>
  );
}

export default App;

태그를 열었으면 꼭, <div></div>이렇게 닫아줘야 된다.

 

HTML에서는 input또는 br태그를 사용 할 때 닫지 않고 사용하기도 한다. 하지만 리액트에서는 그렇게 하면 안된다.

 

App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
      <Hello />
      <Hello />
      <input>
      <br>
    </div>
  );
}

export default App;

태그와 태그 사이에 내용이 들어가지 않을 때에는, Self Closing태그 라는 것을 사용해야 ㅎ나다. 현재 Hello컴포넌트를 사용 할 떄에도 Self Closing 태그를 사용해 주었는데, 열리고 바로 닫히는 태그를 의미한다.

 

App.js

 

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
      <Hello />
      <Hello />
      <input />
      <br />
    </div>
  );
}

export default App;

 

꼭 감싸져야 하는 태그

 

두개 이상의 태그는 무조건 하나의 태그로 감싸져 있어야 한다. 한번 다음 코드를 작성해보자.

 

App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello />
    <div>안녕히계세요.</div>
  );
}

export default App;

이런 코드는 오류가 발생하게 된다.

그 대신에 하나의 태그로 감싸주어야 한다.

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
      <div>안녕히계세요</div>
    </div>
  );
}

export default App;

하지만 이렇게 단순히 감싸기 위해 불필요한 div로 감싸는게 별로 좋지 않은 상황도 있다. 예를 들어서 스타일 관련 설정을 하다가 복잡해지게 되는 상황도 올수 있고, table관련 태그를 작성 할 때에도 내용을 div같은걸로 감싸기엔 애매하다. 그럴 땐, 리액트의 Fragment라는 것을 사용하면 된다.

 

App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <>
      <Hello />
      <div>안녕히계세요</div>
    </>
  );
}

export default App;

태그를 작성 할 때 이름없이 작성을 하게 되면 Fragment가 만들어지는데, Fragment는 브라우저 상에서 따로 별도의 엘리먼트로 나타나지 않는다.

 

JSX안에 자바스크립트 값 사용하기

JSX내부에 자바스크립트 변수를 보여줘야 할때에는 {}으로 감싸서 보여준다.

import React from 'react';
import Hello from './Hello';

function App() {
  const name = 'react';
  return (
    <>
      <Hello />
      <div>{name}</div>
    </>
  );
}

export default App;

 

style과 className

JSX에서 태그에 style과 CSS class를 설정하는 방법은 HTML에서 설정하는 방법과 다르다.

우선, 인라인 스타일은 객체 형태로 작성을 해야하며, background-color처럼 -로 구분되어 있는 이름들은backgroundColor처럼 camelCase형태로 네이밍 해주어야 한다.

 

App.js

 

import React from 'react';
import Hello from './Hello';

function App() {
  const name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24, // 기본 단위 px
    padding: '1rem' // 다른 단위 사용 시 문자열로 설정
  }

  return (
    <>
      <Hello />
      <div style={style}>{name}</div>
    </>
  );
}

export default App;

그리고 CSS class를 설정 할때에는 class=가 아닌 className=으로 설정을 해주어야 한다. 한번 App.css파일을 열어서 전체 내용을 지운뒤 다음과 같이 수정해보자.

 

App.css

.gray-box {
  background: gray;
  width: 64px;
  height: 64px;
}

그 다음 App.js를 다음과 같이 수정해보자.

 

App.js

 

import React from 'react';
import Hello from './Hello';
import './App.css';


function App() {
  const name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24, // 기본 단위 px
    padding: '1rem' // 다른 단위 사용 시 문자열로 설정
  }

  return (
    <>
      <Hello />
      <div style={style}>{name}</div>
      <div className="gray-box"></div>
    </>
  );
}

export default App;

주석

이제, JSX에서 주석은 어떻게 작성하는지 알아보자.

JSX내부의 주석은 {/* 이런형태로 */} 작성한다.

한번 사용해보자.

import React from 'react';
import Hello from './Hello';
import './App.css';


function App() {
  const name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24, // 기본 단위 px
    padding: '1rem' // 다른 단위 사용 시 문자열로 설정
  }

  return (
    <>
      {/* 주석은 화면에 보이지 않습니다 */}
      /* 중괄호로 감싸지 않으면 화면에 보입니다 */
      <Hello 
      />
      <div style={style}>{name}</div>
      <div className="gray-box"></div>
    </>
  );
}

export default App;

추가적으로, 열리는 태그 내무에서는 // 이런 형태로도 주석 작성이 가능하다.

import React from 'react';
import Hello from './Hello';
import './App.css';


function App() {
  const name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24, // 기본 단위 px
    padding: '1rem' // 다른 단위 사용 시 문자열로 설정
  }

  return (
    <>
      {/* 주석은 화면에 보이지 않습니다 */}
      /* 중괄호로 감싸지 않으면 화면에 보입니다 */
      <Hello 
        // 열리는 태그 내부에서는 이렇게 주석을 작성 할 수 있습니다.
      />
      <div style={style}>{name}</div>
      <div className="gray-box"></div>
    </>
  );
}

export default App;

첫번째 리액트 컴포넌트를 만들어 보자.

src디렉터리에 Hello.js라는 파일을 다음과 같이 작성해보자.

 

Hello.js

import React from 'react';

function Hello() {
  return <div>안녕하세요</div>
}

export default Hello;

리액트 컴포넌트를 만들 땐

import React from 'react';

를 통하여 리액트를 불러와 줘야 된다.

리액트 컴포넌트는 함수형태로 작성 할수도 있고 클래스 형태로도 작성할수 있다. 지금은 함수로 작성하는 방법만 해보자.

 

리액트 컴포넌트에서는 XML 형식의 값을 반환해줄 수 있는데 이를 JSX 라고 부른다.

 

코드의 최하단

export default Hello;

이 코드는 Hello라는 컴포넌트를 내보내겠다는 의미이다.

이렇게 해주면 다른 컴포넌트에서 불러와서 사용할수 있다.

 

이 컴포넌트를 한번 App.js에서 불러와서 사용해 보겠다

 

App.js

 

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
    </div>
  );
}

export default App;

상단에 있던

import logo from './logo.svg';
import './App.css';

는 SVG파일을 불러오고 CSS를 적용하는 코드인데 이는 현재 불필요 하므로 제거해 주었다.

컴포넌트는 일종의 UI조각이다. 그리고 쉽게 재사용 할수 있다.

import React from 'react';
import Hello from './Hello';


function App() {
  return (
    <div>
      <Hello />
      <Hello />
      <Hello />
    </div>
  );
}

export default App;

이제 index.js를 열어보자.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

여기서 ReactDOM.render 의 역할은 브라우저에 있는 실제 DOM 내부에 리액트 컴포넌트를 렌더링하겠다는 것을 의미한다.

id  root 인 DOM 을 선택하고 있는데, 이 DOM 이 어디있는지 찾아보자

 

public/index.html을 열어보면 내부에

<div id="root"></div>

을 볼수 있다.

결국, 리액트 컴포넌트가 렌더링 될떄에는 렌더링된 결과물이 위 div내부에 렌더링 되는것이다.

'공부내용정리 > React' 카테고리의 다른 글

props를 통해 컴포넌트에게 값 전달하기  (0) 2021.05.03
JSX의 기본규칙  (0) 2021.05.03

UI 만들기

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <h2 id="number">0</h2>
    <div>
      <button id="increase">+1</button>
      <button id="decrease">-1</button>
    </div>

    <script src="src/index.js"></script>
  </body>
</html>

결과물

위와 같은 결과물이 잘 나왔다. h2와 button태그에 id값을 설정해 주었는데, 이렇게 id값을 설정해주면 JavaScript 에서 쉽게 해당 DOM을 선택 할 수 있다. 여기서 DOM이란, 각 태그에 대한 정보를 지니고 있은 JavaScript객체입니다.

 

DOM 선택하기

우선 DOM을 선택해 보자. index.js를 다음과 같이 수정해보자.

const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");

console.log(number);
console.log(increase);
console.log(decrease);

결과

각 DOM에 내장 되어 있는 기능들은 정말 다양하지만 그중 중요한것 몇가지만 사용해 보자.

const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");

console.log(number.innerText); // 내용
console.log(increase.offsetTop); // top 위치
console.log(decrease.id); // id

 

이벤트 설정하기

이제 DOM이벤트를 설정해 보자. 버튼들이 클릭 됐을 때 콘솔에 텍스트를 출력하는 이벤트를 설정해보자.

const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");

increase.onclick = () => {
  console.log("increase 가 클릭됨");
};

decrease.onclick = () => {
  console.log("decrease 가 클릭됨");
};

버튼들을 클릭했을 때 콘솔에 우리가 설정한 텍스트들이 출력되는지 확인해 보자.

DOM에 이벤트를 설정 할떄는 on이벤트이름 값에 함수르 설정해주면 됩니다. DOM 이벤트의 종류는 정말 다양하다.

 

이제 버튼들이 클릭될 때 숫자값을 올리거나 내려보자.

const number = document.getElementById("number");
const increase = document.getElementById("increase");
const decrease = document.getElementById("decrease");

increase.onclick = () => {
  const current = parseInt(number.innerText, 10);
  number.innerText = current + 1;
};

decrease.onclick = () => {
  const current = parseInt(number.innerText, 10);
  number.innerText = current - 1;
};

parseInt 는 문자열을 숫자로 변환해주는 함수이다.

두번째 10을 넣어준 것은, 10진수로 숫자를 받아오겠다는 의미이다.

이번에 자바 스크립트의 Scope에 대해서 알아보자. Scope란 우리가 변수 혹은 함수를 선언하게 될 떄 해당 변수 또는 함수가 유효한 범위를 의미한다. Scope는 총 3가지 종류가 있다.

 

1. Global(전역) Scope: 코드의 모든 범위에서 사용이 가능

2. Function(함수) Scope: 함수 안에서만 사용이 가능하다.

3. Block(블록) Scope : if, for, switch등 특정 블록 내부에서만 사용이 가능하다.

 

예시를 통한 Scope이해

한번 예시 코드를 보고 Scope를 이해해 보자

const value = 'hello!';

function myFunction() {
  console.log('myFunction: ');
  console.log(value);
}

function otherFunction() {
  console.log('otherFunction: ');
  const value = 'bye!';
  console.log(value);
}

myFunction();
otherFunction();

console.log('global scope: ');
console.log(value);

위 코드의 결과는 다음과 같다.

코드의 맨 윗줄에서 선언된 value값은 Global Scope로 선언된 값이다. Global Scope로 선언된 값은 어디서든지 사용이 가능하다. myFunction 에서 바로 사용을 할 수 있었다.

otherFunction에서는 함수 내부에서 value값을 'bye!'로 새로 선언을 해주었다. 이렇게 되면, value라는 값은 Function Scope로 지정이 되서 해당 값은 otherFunction 내부에서만 유효한 값이 된다. 이렇게 값을 설정한다고 해서 기존에 Global Scope로 선언된 value값이 바뀌지 않는다.

 

또 다른 예시를 확인해 보자.

const value = 'hello!';

function myFunction() {
  const value = 'bye!';
  const anotherValue = 'world';
  function functionInside() {
    console.log('functionInside: ');
    console.log(value);
    console.log(anotherValue);
  }
  functionInside();
}


myFunction()
console.log('global scope: ');
console.log(value);
console.log(anotherValue);

myFunction 내부에 anotherValue라는 새로운 값을 선언했고, functionInside라는 함수도 선언을 했다.

functionInside 함수에서는 myFunction에서 선언한 value값과 anotherValue 값을 조회 할수 있다.

반면, myFunction밖에서는 anotherValue를 조회 할 수 없다.

이제 또다른 예시를 알아보자.

const value = 'hello!';

function myFunction() {
  const value = 'bye!';
  if (true) {
    const value = 'world';
    console.log('block scope: ');
    console.log(value);
  }
  console.log('function scope: ');
  console.log(value);
}

myFunction();
console.log('global scope: ');
console.log(value);

const로 선언한 값은 Block Scope로 선언이 된다. 따라서 if 문 같은 블록 내에서 새로운 변수/상수를 선언하게 된다면, 해당 블록내부에서만 사용이 가능하고 블록밖의 범위에서 똑같은 이름을 가진 값이 있다고 해도 영향을 주지 않는다.

let또한 마찬가지 이다.

하지만 var는 어떨까?

var value = 'hello!';

function myFunction() {
  var value = 'bye!';
  if (true) {
    var value = 'world';
    console.log('block scope: ');
    console.log(value);
  }
  console.log('function scope: ');
  console.log(value);
}

myFunction();
console.log('global scope: ');
console.log(value);

var는 Function Scope로 선언이 되므로, if 문 블록 내부에서 선언한 value값이 블록 밖의 value에도 영향을 미치게 된다.

 

Hoisting 이해하기

Hoisting이란 자바스크립트에서 아직 선언되지 않은 함수/변수를 "끌어올려서" 사용 할수 있는 자바스크립트의 작동 방식을 의미한다.

다음코드를 확인해 보자.

myFunction();

function myFunction() {
  console.log('hello world!');
}

위 코드에서는 myFunction함수를 선언하기 전에,

myFunction()을 호출해 주었다. 함수가 아직 선언되지않았음에도 불구하고 코드는 정상적으로 작동하게 된다.

이게 잘 작동하는 이유는, 자바스크립트 엔진이 위 코드를 해석하는 과정에서, 다음과 같이 받아 들이게 되기 때문이다

function myFunction() {
  console.log('hello world!');
}

myFunction();

이러한 현상을, Hoisting이라고 부른다.

변수 또한 Hoisting 된다.

예를 들어서, 다음과 같은 코드를 실행한다면,

console.log(number);

이런 오류가 발생한다.

그렇지만, 다음과 같은 코드는

console.log(number);
var number = 2;

undefined가 출력된다.

 

자바스크립트 엔진이 위 코드를 해석 할 때는 다음과 같이 받아들이게 된다.

var number;
console.log(number);
number = 2;

반면 const와 let은 hoisting이 발생하지 않고, 에러가 발생하게 된다. Codesandbox에서는 자바스크립트가 Bable이라는 도구에 의하여 const와 let이 var로 변환되기 때문에 오류가 발생하지 않는다. Chrome 개발자 도구의 콘솔에서 다음 코드를 실행해 보자.

function fn() {
    console.log(a);
    let a = 2;
}
fn();

Hoisting은 자바스크립트 엔진이 갖고 있는 성질이며, Hoisting을 일부러 할 필요는 없지만, 방지하는 것이 좋다. 왜냐하면 Hoisting이 발생하는 코드는 이해하기 어렵기 때문에 유지보수도 힘들어지고 의도치 않는 결과물이 나타나기 쉽기 때문이다.

 

Hoisting을 방지하기 위해서, 함수의 경우 꼭 선언후에 호출을 하도록 주의를 하고, var대신 const,let을 위주로 사용하자. 추가적으로 나중에 자바스크립트 개발을 본격적으로 하게 될 때에는 EsLint 라는것을 사용하여 Hoisting이 발생하는 코드는 에디터상에서 쉽게 발견해 낼수 있다.

'공부내용정리 > JavaScript' 카테고리의 다른 글

카운터  (0) 2021.04.28
spread와 rest  (0) 2021.04.26
비구조화 할당 (구조분해) 문법  (0) 2021.04.21
조건문 더 스마트 하게 쓰기  (0) 2021.04.20
단축 평가(short-circuit evaluation)논리 계산법  (0) 2021.04.20

이번에는 ES6에서 도입된 spread와 rest문법에 대해서 알아보자. 서로 완전히 다른 문법인데 은근히 좀 비슷하다.

 

spread

일단 spread 문법부터 알아봅시다. spread 라는 단어가 가지고 있는 의미는 펼치다. 퍼뜨리다 입니다. 이 문법을 사용하면, 객체 혹은 배열을 펼칠수 있다.

예를 들어서 다음과 같은 객체들이 있다고 가정해보자.

const slime = {
  name: '슬라임'
};

const cuteSlime = {
  name: '슬라임',
  attribute: 'cute'
};

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

이 코드에서는 먼저 slime이라는 객체를 선언했다. 그리고 cuteSlime이 가지고 있는 값을 그대로 사용하였다.

기졵에 선언한 slime을 건들이지 않고 객체를 만들었는데요, 기존에 선언한 slime을 건들이지 않고 새로운 객체를 만들어서 slime이 가지고 있는 값을 그대로 사용하였다.

 

그 다음에는 purpleCuteSlime이라는 객체를 만들었는데요, 이 객체는 cuteSlime이 가지고 있는 속성을 그대로 사용하면서 추가적으로 color가 추가 되었다.

 

위 코드에서의 핵심은, 기존의 것을 건들이지 안ㅎ고, 새로운 객체를 만든다는 것인데 이러한 상황에 사용 할수 있는 유용한 문법이 spread이다.

 

아까 코드는 spread문법을 사용하면 다음과 같이 작성 할수 있다.

const slime = {
  name: '슬라임'
};

const cuteSlime = {
  ...slime,
  attribute: 'cute'
};

const purpleCuteSlime = {
  ...cuteSlime,
  color: 'purple'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

여기서 사용한 ... 문자가 바로 spread연산자이다.

spread연산자는배열에서도 사용 할 수 있다.

const animals = ['개', '고양이', '참새'];
const anotherAnimals = [...animals, '비둘기'];
console.log(animals);
console.log(anotherAnimals);

기존의 animals는 건드리지 않으면서, 새로운 anotherAnimals 배열에 animals가 가지고 있는 내용을 모두 집어넣고,'비둘기' 라는 항목을 추가적으로 넣었다.

배열에 spread연산자를 여러번 사용 할 수도 있다.

const numbers = [1, 2, 3, 4, 5];

const spreadNumbers = [...numbers, 1000, ...numbers];
console.log(spreadNumbers); // [1, 2, 3, 4, 5, 1000, 1, 2, 3, 4, 5]

rest

rest는 생김새는 spread랑 비슷한데, 역할이 매우 다르다.

rest는 객체, 배열, 그리고 함수의 파라미터에서 사용이 가능하다.

객체에서의 rest

우선 객체에서의 예시를 알아보자.

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...rest } = purpleCuteSlime;
console.log(color);
console.log(rest);

rest 안에 name값을 제외한 값이 들어있다.

rest는 객체와 배열에서 사용 할때는 이렇게 비구조화 할당 문법과 함께 사용 된다. 주로 사용 할때는 위와 같이 rest라는 키워드를 사용하게 된다. 추출한 값의 이름이 꼭 rest일 필요는 없다.

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...cuteSlime } = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);

이렇게 해도 무방하다.

이어서 attribute까지 없앤 새로운 객체를 만들고 싶다면 이렇게 해주면 된다.

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...cuteSlime } = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);

const { attribute, ...slime } = cuteSlime;
console.log(attribute);
console.log(slime);

배열에서의 rest

다음 배열에서의 사용 예시를 알아보자.

const numbers = [0, 1, 2, 3, 4, 5, 6];

const [one, ...rest] = numbers;

console.log(one);
console.log(rest);

배열 비구조화 할당을 통하여 원하는 값을 밖으로 꺼내고, 나머지 값을 rest안에 넣었다.

이렇게 할수는 없다

const numbers = [0, 1, 2, 3, 4, 5, 6];

const [..rest, last] = numbers;

함수 파라미터에서의 rest

rest를 함수 파라미터에서 사용 할 수도 있다. 예를 들어서 우리가 파라미터로 넣어준 모든 값들을 합해주는 함수를 만들어 주고 싶다고 가정해보자.

function sum(a, b, c, d, e, f, g) {
  let sum = 0;
  if (a) sum += a;
  if (b) sum += b;
  if (c) sum += c;
  if (d) sum += d;
  if (e) sum += e;
  if (f) sum += f;
  if (g) sum += g;
  return sum;
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result);

위에서의 sum함수는 7개의 파라미터를 받아오는데, 아래에서 사용 할때에는 6개만 넣어줬다.그러면, g 값이 undefined 가 되기 때문에 sum 에 더하는 과정에서 += undefined 를 하게 되면 결과는 NaN 이 되버린다.그렇기 때문에 함수에서 하나하나 유효한 값인지 확인을 해줬다.

함수의 파라미터가 몇개가 될 지 모르는 상황에서 rest파라미터를 사용하면 매우 유용하다. 코드를 다음과 같이 수정해보자.

function sum(...rest) {
  return rest;
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result);

result가 가르키고 있는 것은 함수에서 받아온 파라미터들로 이루어진 배열이다. 우리가 이제 파라미터들이 들어가 있는 배열을 받았으니 그냥 모두 더해주면 된다.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result); // 21

 

함수 인자와 spread

이번에는 다시 아까 배웠던 spread로 돌아와서 한가지를 더 배워보자. 함수의 인자와 spread인데, 만약 프로그래밍을 처음 배운다면 파라미터와 인자가 헷갈릴수 있다. 이에 대해서 간단하게 알아보자.

const myFunction(a) { // 여기서 a 는 파라미터
  console.log(a); // 여기서 a 는 인자
}

myFunction('hello world'); // 여기서 'hello world' 는 인자

함수에서 값을 읽을떄, 그 값들을 파라미터 라고 부른다. 그리고 함수에서 값을 넣어줄 때, 그값들을 인자라고 부른다.

인자가 무엇인지 이해를 했다면 이제 함수인자와 spread문법을 사용하는 것에 대하여 알아보자.

 

인자가 무엇인지 이해를 했다면 이제 함수인자와 spread문법을 사용하는것에 대해 알아보자. 우리가 방금 함수 파라미터와 rest를 사용한 것과 비슷한데, 반대의 역할이다. 우리가 배열안에 있는 원소들을 모두 파라미터로 넣어주고 싶다고 가정해보자.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const numbers = [1, 2, 3, 4, 5, 6];
const result = sum(
  numbers[0],
  numbers[1],
  numbers[2],
  numbers[3],
  numbers[4],
  numbers[5]
);
console.log(result);

굉장히 불편하다. 만약에 sum함수를 사용 할때 인자 부분에서 spread를 사용하면다음과 같이 표현이 가능하다.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const numbers = [1, 2, 3, 4, 5, 6];
const result = sum(...numbers);
console.log(result);

이렇게 spread와 rest를 잘 사용하면 앞으로 보기 깔끔한 코드를 작성하는 것에 큰 도움을 준다.

이번에는 1장 섹션 6 에서도 배웠던 비구조화 할당 문법을 잘 활용하는 방법에 대해서 알아보자

 

이전에 배웠던 것을 복습해보면, 비구조화 할당 문법을 사용하면 다음과 같이 객체 안에 있는 값을 추출해서 변수 혹은 상수로 바로 선언해 줄수 있었다.

const object = { a: 1, b: 2 };

const { a, b } = object;

console.log(a); // 1
console.log(b); // 2

그리고, 함수의 파라미터에서도 비구조화 할당을 할 수 있는 것도 배웠다.

const object = { a: 1, b: 2 };

function print({ a, b }) {
  console.log(a);
  console.log(b);
}

print(object);

그런데 여기서 만약 b값이 주어지지 않았다고 가정해 보자.

const object = { a: 1 };

function print({ a, b }) {
  console.log(a);
  console.log(b);
}

print(object);
// 1
// undefined

두번째 출력에서 undefined가 나타날 것이다.

 

비구조화 할당시 기본값 설정

이러한 상황에 b값에 기본 값을 주고 싶다면 이렇게 해줄수 있다.

const object = { a: 1 };

function print({ a, b = 2 }) {
  console.log(a);
  console.log(b);
}

print(object);
// 1
// 2

이는 꼭 함수의 파라미터에서만 할 수 있는 것은 아니다.

const object = { a: 1 };

const { a, b = 2 } = object;

console.log(a); // 1
console.log(b); // 2

 

비구조화 할당시 이름 바꾸기

이번에는 비구조화 할당을 하는 과정에서 선언 할 값의 이름을 바꾸는 방법을 알아보자.

예를 들어서 다음과 같은 코드가 있다고 가정해보자.

const animal = {
  name: '멍멍이',
  type: '개'
};

const nickname = animal.name;

console.log(nickname); // 멍멍이

위 코드에서는 animal.name값을 nickname값에 담고 있는데, 이름이 같다면 그냥 우리가 이전에 배웠던 대로 비구조화 할당을 쓰면 되는데 지금은 이름이 서로 다르다.

이러한 상황에서는 : 문자를 사용해서 이름을 바꿔줄수 있다.

 

const animal = {
  name: '멍멍이',
  type: '개'
};

const { name: nickname } = animal
console.log(nickname);

 

 

배열 비구조화 할당

비구조화 할당은 객체에만 할 수 있는 것이 아니다. 배열에서 할수 있다.

예시코드를 보자

const array = [1, 2];
const [one, two] = array;

console.log(one);
console.log(two);

이 문법은 배열 안에 있는 원소를 다른 이름으로 새로 선언해주고 싶을때 사용하면 매우 유용하다.

객체 비구조화 할당과 마찬가지로, 기본값 지정이 가능하다.

const array = [1];
const [one, two = 2] = array;

console.log(one);
console.log(two);

 

깊은 값 비구조화 할당

객체의 깊숙한 곳에 들어있는 값을 꺼내는 방법을 알아보자.

예를 들어서 다음과 같은 객체가 있다고 가정해보자.

const deepObject = {
  state: {
    information: {
      name: 'velopert',
      languages: ['korean', 'english', 'chinese']
    }
  },
  value: 5
};

여기서 name, languages, value 값들을 밖으로 꺼내주고 싶다면 어떻게 해야 할까? 이럴땐 두가지 해결 방법이 있다. 첫번쨰는 비구조화 할당 문법을 두번 사용하는 것이다.

const deepObject = {
  state: {
    information: {
      name: 'velopert',
      languages: ['korean', 'english', 'chinese']
    }
  },
  value: 5
};

const { name, languages } = deepObject.state.information;
const { value } = deepObject;

const extracted = {
  name,
  languages,
  value
};

console.log(extracted); // {name: "velopert", languages: Array[3], value: 5}
const extracted = {
  name,
  languages,
  value
}

이 코드는 다음과 같다

const extracted = {
  name: name,
  languages: languages,
  value: value
}

만약에 key이름으로 선언된 값이 존재한다면, 바로 매칭시켜주는 문법이다. 이문법은 es6의 object-shorthand 문법이라고 부른다.

이번엔 두번째 방법, 한번에 모두 추출하는 방법을 알아 보겠다.

const deepObject = {
  state: {
    information: {
      name: 'velopert',
      languages: ['korean', 'english', 'chinese']
    }
  },
  value: 5
};

const {
  state: {
    information: { name, languages }
  },
  value
} = deepObject;

const extracted = {
  name,
  languages,
  value
};

console.log(extracted);

이렇게 하면 깊숙히 안에 들어있는 값도 객체에서 바로 추출 할 수 있답니다.

위 이미지에서 주황색으로 나타난 값들이 추출 된 것이다.

반면, 빨간색으로 나타난 값들은 따로 추출되지 않으니 참고!

이번에는 조건문을 조금 더 스만트하게 쓰는 방법에 대해서 알아보겠다.

 

특정 값이 여러 값중 하나인지 확인해야 할때

만약, 여러분이 특정 값이 여러 값중 하나인지 확인을 해야하는 상황이 생겼다고 해보자.

그러면 이렇게 할수 있을것이다.

function isAnimal(text) {
  return (
    text === '고양이' || text === '개' || text === '거북이' || text === '너구리'
  );
}

console.log(isAnimal('개')); // true
console.log(isAnimal('노트북')); // false

비교해야 할 값이 많아질 수록 코드는 길어진다.

 

이러한 코드를 간단하게 해결 할수 있는 방법은, 배열을 만들고  배열의 includes 함수를 사용하는 것 이다.

이러한 코드를 간단하게 해결 할 수 있는 방법은, 배열을 만들고 배열의 includes 함수를 사용하는 것이다.

function isAnimal(name) {
  const animals = ['고양이', '개', '거북이', '너구리'];
  return animals.includes(name);
}

console.log(isAnimal('개')); // true
console.log(isAnimal('노트북')); // false

원한다면 animals 배열을 선언하는 것도 생략하고, 화살표 함수로 작성할 수도 있다.

const isAnimal = name => ['고양이', '개', '거북이', '너구리'].includes(name);

console.log(isAnimal('개')); // true
console.log(isAnimal('노트북')); // false

물론, 코드가 짧다고 해서 무조건 좋은것은 아니다. 단 코드가 짧으면서도 읽었을 때 어떤 역할을 하는지 잘 이해가 될수 없어야 비로소 좋은 코드이다.

 

값에 따라 다른 결과물을 반환 해야 할 때

이번에는 주어진 값에 따라 다른 결과물을 반환해야 할 때 사용 할 수 있는 유용한 팁을 알아보자.

예를 들어서, 동물 이름을 받아오면, 동물의 소리를 반환하는 함수를 만들고 싶다고 가정해보자.

function getSound(animal) {
  if (animal === '개') return '멍멍!';
  if (animal === '고양이') return '야옹~';
  if (animal === '참새') return '짹짹';
  if (animal === '비둘기') return '구구 구 구';
  return '...?';
}

console.log(getSound('개')); // 멍멍!
console.log(getSound('비둘기')); // 구구 구 구

if문의 코드 블록이 한줄짜리라면 {}를 생략 할 수도 있다.

 

만약 여기서 우리가 배운 switch case문을 사용하여 다음과 같이 구현 할 수도 있다.

function getSound(animal) {
  switch (animal) {
    case '개':
      return '멍멍!';
    case '고양이':
      return '야옹~';
    case '참새':
      return '짹짹';
    case '비둘기':
      return '구구 구 구';
    default:
      return '...?';
  }
}

console.log(getSound('개')); // 멍멍!
console.log(getSound('비둘기')); // 구구 구 구

참고로 switch 문에서 return 을 할떄는 break를 생략해도 된다.

 

우리가 방금 구현한 코드는 큰 문제는 없지만, 이걸 깔끔하게 해결할 방법을 알고 나면 좀 맘에 들지 않는 코드의 형태이다.

 

이 코드를 더욱 깔끔하게 작성하는 방법을 알아보자

function getSound(animal) {
  const sounds = {
    개: '멍멍!',
    고양이: '야옹~',
    참새: '짹짹',
    비둘기: '구구 구 구'
  };
  return sounds[animal] || '...?';
}

console.log(getSound('개')); // 멍멍!
console.log(getSound('비둘기')); // 구구 구 구

훨씬 더 간략하고 가독성도 좋다.

이렇게 특정 값에 따라 반환 해야 하는 값이 다른 조건이 여러가지 있을 때는 객체를 활용하면 좋다.

 

반면, 값에 따라 실행해야 하는 코드 구문이 다를때는 어떻게 해야 할까?

 

그럴때는 객체에 함수를 넣으면 된다.

function makeSound(animal) {
  const tasks = {
    개() {
      console.log('멍멍');
    },
    고양이() {
      console.log('고양이');
    },
    비둘기() {
      console.log('구구 구 구');
    }
  };
  if (!tasks[animal]) {
    console.log('...?');
    return;
  }
  tasks[animal]();
}

getSound('개');
getSound('비둘기');

 

'공부내용정리 > JavaScript' 카테고리의 다른 글

spread와 rest  (0) 2021.04.26
비구조화 할당 (구조분해) 문법  (0) 2021.04.21
단축 평가(short-circuit evaluation)논리 계산법  (0) 2021.04.20
Truthy and Falsy  (0) 2021.04.19
삼항 연산자  (0) 2021.04.19

+ Recent posts