[TypeScript] chap.1

 

 

 

설치 및 세팅

1. nodejs 설치

2. 타입스크립트 설치

npm install -g typescript
tsc -w // 자바스크립트로 저장시 자동 컴파일

 

 

* React에서 Typescript 사용

- 이미 있는 프로젝트

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

 

- 새로운 프로젝트

npx create-react-app my-app --template typescript

 

 

* Vue에서 Typescript 사용

vue add typescript
<script lang="ts">
  
</script>

lang 옵션을 키고 사용할 수 있다.

 

 

* tsconfig.json

- 타입스크립트 ts 파일들을 .js 파일로 변환할 때 어떻게 변환할 것인지 세부설정하는 파일

{
 "compilerOptions": {

  "target": "es5", // 'es3', 'es5', 'es2015', 'es2016', 'es2017','es2018', 'esnext' 가능
  "module": "commonjs", //무슨 import 문법 쓸건지 'commonjs', 'amd', 'es2015', 'esnext'
  "allowJs": true, // js 파일들 ts에서 import해서 쓸 수 있는지 
  "checkJs": true, // 일반 js 파일에서도 에러체크 여부 
  "jsx": "preserve", // tsx 파일을 jsx로 어떻게 컴파일할 것인지 'preserve', 'react-native', 'react'
  "declaration": true, //컴파일시 .d.ts 파일도 자동으로 함께생성 (현재쓰는 모든 타입이 정의된 파일)
  "outFile": "./", //모든 ts파일을 js파일 하나로 컴파일해줌 (module이 none, amd, system일 때만 가능)
  "outDir": "./", //js파일 아웃풋 경로바꾸기
  "rootDir": "./", //루트경로 바꾸기 (js 파일 아웃풋 경로에 영향줌)
  "removeComments": true, //컴파일시 주석제거 

  "strict": true, //strict 관련, noimplicit 어쩌구 관련 모드 전부 켜기
  "noImplicitAny": true, //any타입 금지 여부
  "strictNullChecks": true, //null, undefined 타입에 이상한 짓 할시 에러내기 
  "strictFunctionTypes": true, //함수파라미터 타입체크 강하게 
  "strictPropertyInitialization": true, //class constructor 작성시 타입체크 강하게
  "noImplicitThis": true, //this 키워드가 any 타입일 경우 에러내기
  "alwaysStrict": true, //자바스크립트 "use strict" 모드 켜기

  "noUnusedLocals": true, //쓰지않는 지역변수 있으면 에러내기
  "noUnusedParameters": true, //쓰지않는 파라미터 있으면 에러내기
  "noImplicitReturns": true, //함수에서 return 빼먹으면 에러내기 
  "noFallthroughCasesInSwitch": true, //switch문 이상하면 에러내기 
 }
}

 

 

 

기본 타입
let 이름 :string = 'kim'; // string
let 나이 :number = 20; // number
let 결혼했니 :boolean = false; // boolean

let 회원들 :string[] = ['kim', 'park'] // array
let 내정보 : { age : number } = { age : 20 } // object

// **기본적으로 변수 생성 시 타입이 알아서 지정되기 때문에 일일이 할 필요는 없다.

 

 

 

 

union 타입
let 이름: string | number = 'kim';
let 나이: (string | number) = 100; // 같음

///////////////////////////////////////////

var 어레이: number[] = [1,'2',3]
var 오브젝트: {data : number} = { data : '123' }

var 어레이: (number | string)[] = [1,'2',3]
var 오브젝트: {data : (number | string) } = { data : '123' }

 

 

 

any, unknown 타입

* any

아무 자료나 대입할 수 있는 타입. (타입스크립트의 기능을 해제하는 타입)

let 이름: any = 'kim';
이름 = 123;
이름 = undefined;
이름 = [];

 

 

* unknown

아무 자료나 대입할 수 있는 타입. (타입은 uknown으로 지정되어 다른 타입과는 에러발생. any는 아님)

let 이름: unknown;

let 변수1: string = 이름;
let 변수2: boolean = 이름;
let 변수3: number = 이름;

///////////////////////////

let 이름: unknown;
이름[0];
이름 - 1;
이름.data;

 

타입스크립트는 언어가 엄격하기 때문에 변경하려는 변수의 타입이 확실해야만 연산을 수행해준다. -1, +1 같은 경우는 number 타입일 때만, .name 등은 object 타입 일때만 사용이 가능하다.

 

 

 

함수 & void

1. 함수로 들어오는 자료 (파라미터)

2. 함수에서 나가는 자료 (return)

function 내함수(x :number) :number { 
  return x * 2 
}

 

 

- void

function 내함수(x :number) :void { 
  return x * 2 //여기서 에러남 
}

함수에서 return을 방지할 때 사용한다.

 

 

- 파라미터가 옵션인 경우

function 내함수(x? :number) { // == x : number | undefined

}
내함수(); //가능
내함수(2); //가능

x? :number은 x :number | undefined 와 같은 의미이다.

 

 

 

 

 

Narrowing & Assertion

타입을 확정할 때 쓰는 문법.

 

* Type Narrowing

function 내함수(x :number | string){
  if (typeof x === 'number') {
    return x + 1
  } 
  else if (typeof x === 'string') {
    return x + 1
  }
  else { // 함수안에서 if쓸 때 else가 없으면 에러날 수도 있으니 쓰자
    return 0
  }
}

 

 

* Type Assertion

function 내함수(x :number | string){ 
    return (x as number) + 1 
}
console.log( 내함수(123) )

해당하는 변수를 number로 지정한다. (내가 꼭 ! number 타입이 들어올 것이라는 확신이 있을 때 사용한다.)

 

특징:

1. union 타입 중에서 하나의 정확한 타입으로 지정할 때 사용 (형 변환처럼 사용하면 에러 남)

2. 타입실드를 임시로 해제한다고 생각하면 된다. (타입을 바꿔주는건 아니다)

 

Assertion은

1. 타입에러가왜 나는지 모르겠는 상황에서 에러 해결용으로 사용

2. 어떤 타입이 들어갈지 확실히 아는데 컴파일 상에서 에러가 날 때 사용.

 

**웬만하면 Narrowing 쓰는게 더 나음.

 

 

 

type & readonly

* type

타입의 정의가 너무 길거나 복잡하게 나열된 타입을 변수에 담아 사용할 수 있다.

type Animal = string | number | undefined;
let 동물 :Animal;
type 사람 = {
  name : string,
  age : number,
}

let teacher :사람 = { name : 'john', age : 20 }

 

 

- object의 속성이 선택사항일 때

type Square = {
  color? : string,
  width : number,
}

let 네모2 :Square = { 
  width : 100 
}

함수의 파라미터와 마찬가지로 object에서도 ?를 통해 string | undefined 형태로 선택적으로 사용할 수 있다.

 

 

- type 키워드 여러개 합치기

type Name = string;
type Age = number;
type NewOne = Name | Age;

or 연산자를 이용해서 union 타입으로 만들 수 있다.

 

type PositionX = { x: number };
type PositionY = { y: number };
type XandY = PositionX & PositionY
let 좌표 :XandY = { x : 1, y : 2 }

and(&) 기호를 쓰면 object 안의 두개의 속성을 합칠 수 있다. (extend)

 

type Name = string;
type Name = number; // 불가

type 키워드는 재정의가 불가능하다.

 

 

* readonly

object 속성을 const처럼 재 할당할 시에 값이 변경하는걸 미리 감지하고 차단한다

type testType = {
  readonly name : string,
}

let 이름 :testType = {
  name : '홍길동'
}

이름.name = '고길동' //readonly라서 에러남

컴파일 시에 에러만 출력되는것이고, 자바스크립트로 변환하면 문제없이 작동한다.

 

 

 

Literal type

특정 글자나 숫자만 가질 수 있게 그것으로 타입 제한을 두는 타입

let john :'대머리';
let kim :'솔로';

let 방향: 'left' | 'right';
방향 = 'left';

function 함수(a : 'hello') : 1 | 0 | -1 {
  return 1 
}

 

- as const

1. 타입을 object의 value로 바꿔준다. (타입을 'kim'으로 바꿔준다)

2. object 안에 있는 모든 속성을 readonly로 바꾼다. (변경하면 에러)

var 자료 = {
  name : 'kim'
}
function 내함수(a : 'kim') { // 'kim' 타입

}
내함수(자료.name) // string 타입 => 에러

function의 파라미터 변수 a는 'kim'이라는 리터럴 타입이고, 자료.name으로 가져오는 'kim'은 string 타입이다.

 

var 자료 = {
  name : 'kim'
} as const;

function 내함수(a : 'kim') {

}
내함수(자료.name)

해결책:

1. object 만들 때 object의 타입을 지정한다.

2. assertion을 쓴다 (ex. as 'kim')

3. as const를 object 자료형에 붙인다.

 

 

 

function & method의 type alias

* function

type NumOut = (x : number, y : number ) => number ;

let ABC :NumOut = function(x,y){
  return x + y
} // 함수 표현식

함수에 type 지정하기 (함수 선언문 형태로는 type을 만들 수 없다. 사용할 때도 표현식으로 사용)

 

 

* method

type 회원정보타입 = {
    name: string,
    plusOne: (a: number) => number,
    changeName: () => void
};

let 회원정보 :회원정보타입 = {
    name: 'kim',
    plusOne(a: number): number{
        return a + 1;
    },
    changeName: () => {
        console.log('안녕');
    }
};
회원정보.plusOne(1);
회원정보.changeName();

 

 

 

HTML

- 세팅

{
    "compilerOptions": {
        "target": "ES5",
        "module": "commonjs",
        "strictNullChecks": true // true로 설정 (false는 타입스크립트 쓰는 의미가..)
    }
}

null 체크 옵션인데 html 조작할 때 셀렉터로 찾으면 null이 발생하는 일이 많다.

 

 

- HTML 변경

  • narrowing
  • instanceof
  • assertion
  • optional chaining
  • strict false
let 제목 = document.querySelector('#title');
if(제목 != null){
    제목.innerHTML = '반가우요';
}
if(제목 instanceof Element){
    제목.innerHTML = '반가우요';
}
제목.innerHTML = '반가우요'; //as Element => assertion
if(제목?.innerHTML != undefined){
    제목.innerHTML = '반가우요';
}

 

 

- instanceof & optional chaining

let 링크 = document.querySelector('.link');

// instanceof
if(링크 instanceof HTMLAnchorElement){
    링크.href = 'https://kakao.com'
}

// optional chaining
let 버튼 = document.querySelector('#button');
버튼?.addEventListener('click', function(){
    
})

ex:

<a> =  HTMLAnchorElement

<img> = HTMLImageElement

<h4> = HTMLHeadingElement

 

 

 

 

 

class

- 필드값 타입지정

class Person {
  data = 0;
}

let john = new Person();
let kim = new Person();

console.log(john.data);
console.log(kim.data);

 

 

- constructor 타입지정

class Person {
  name;
  age;
  constructor ( a :string ){
    this.name = a;
    this.age = 20;
  }
}

constructor에도 default parameter나 rest parameter를 사용 할 수 있다.

 

 

- method 타입지정

class Person {
  
  add(숫자){ // Person의 prototype에 저장 됌
    console.log(숫자 + 1)
  }
}

add라는 함수를 prototype으로 사용할 수 있다.

 

 

 

interface

object 자료형의 타입을 편리하게 저장할 수 있다.

interface Square { 
  color :string, 
  width :number, 
} 

let 네모 :Square = { color : 'red', width : 100 }

 

 

- extends

interface Student {
  name :string,
}
interface Teacher {
  name :string,
  age :number,
}

///////////////////////////////////////

interface Student {
  name :string,
}
interface Teacher extends Student {
  age :number
}

let 학생: Student = {name: 'kim'}
let 선생: Teacher = {name: 'kim', age: 20 }

interface의 extends를 사용하면 extends 되는 object 안에 있는 것들을 복사해서 넣어준다.

 

 

* interface와 type의 차이점

- interface

interface Animal { 
  name :string 
} 
interface Cat extends Animal { 
  legs :number 
}

extends하기

 

interface Student {
  name :string,
}
interface Teacher {
  age :number
}

let 변수 :Student & Teacher = { name : 'kim', age : 90 }

intersection(&) 기호를 통한 extends와 유사하게 사용하기

 

// 에러 안남 (타입 명 중복 허용)
interface Animal { 
  name :string 
} 
interface Animal { 
  legs :number 
}

////////////////////////////

// 에러 남
interface Animal { 
  name :string 
} 
interface Dog extends Animal { 
  name :number 
}

타입이름 중복 선언시 extends한 것이랑 동일하게 동작하며 interface 안에 개별적 속성을 한꺼번에 가질 수 있다. type 선언을 자주하는 외부 라이브러리 이용시 type 선언을 덮어쓰기(override) 하기 편하다.

 

 

- type

type Animal = { 
  name :string 
} 
type Cat = Animal & { legs: number }

extends 대신에 intersection(&) 기호를 통해서 object 두개를 합칠 수 있다. (하지만 interface도 이렇게 사용할 수 있다.)

 

// 에러 남
type Animal = { 
  name :string 
} 
type Animal = { 
  legs :number 
}

///////////////////

type Animal = {name: string}
type Cat = {name: number} & Animal

let 야옹이 :Cat = {name: 'kim'}

타입이름 중복 선언시 에러난다. 타입을 intersaction(&) 했을 때, 타입 안에 개별적 속성이 겹치는 경우, 사용할 때 에러가 난다.

 

 

결론: object형태의 자료형은 interface로 만들고 다른형태(string, number, boolean ... 등 primitive 타입)의 자료형은 type 키워드로 만들어 사용하자.

 

 

 

'TypeScript' 카테고리의 다른 글

[TypeScript] chap.2  (0) 2021.12.17

[React] chap.1

 

 

 

React 설치 및 개발환경 세팅

1. node.js 설치

2. 작업하려는 폴더에서 npx create-react-app 작업폴더명

3. npm start로 웹 미리보기 (작업폴더로 경로변경 후 시작)

 

 

 

JSX
function App(){
  return (
    <div className="App">
      <div>개발 blog</div>      
    </div>
  )
}
.black-nav {
  background : black;
  width : 100%;
  display : flex;
  color : white;
  padding : 20px;
  font-weight : 600;
  font-size : 20px;
}

 

 

- 여러가지 문법

function App() {

  let posts = {color: 'blue', fontSize: '30px'};
  function 함수(){
    return 100
  }

  return (
    <div className="App">
      <div className="black-nav">
        <div style={ {posts} }>개발 Blog</div>
      </div>
      <img src={ logo }/>
      <h4>{ 함수() }</h4>
    </div>
  );
}

class = className (class 예약어 때문에)

css style = object 형태로 카멜케이스(fontColor)

데이터 바인딩 = {} (함수도 가능)

 

 

 

State

변수 말고도 데이터바인딩과 관련된 중요한 데이터를 저장할 때 쓰는 것.

function App(){
 
  let posts = '강남 고기 맛집';
  return (
    <div className="App">
      <div className="black-nav">
        <div>개발 blog</div>
      </div>
      <div className="list">
        <h3>{ posts }</h3>
        <p>2월 17일 발행</p>
        <hr/>
      </div>
    </div>
  )
}
.list {
  margin-top : 30px;
  text-align : left;
  padding-left : 20px;
  padding-right : 20px;
}

 

 

- state 사용

import React, { useState } from 'react';
import './App.css'

function App(){
 
  // destructuring 문법
  let [글제목, 글제목변경] = useState('남자 코트 추천'); // [a, b] => [남자 코트 추천, 함수]
  // let [글제목2, 글제목변경2] = useState(['남자 코트 추천2', '강남 우동 맛집']);
  let posts = '강남 고기 맛집';
  
  return (
    <div className="App">
      <div className="black-nav">
        <div>개발 blog</div>
      </div>
      <div className="list">
        <h3>{ 글제목 }</h3> <!-- 남자 코트 추천 -->
        <p>2월 17일 발행</p>
        <hr/>
      </div>
    </div>
  )
}

기존의 변수말고도 state로 데이터 바인딩이 가능하다. Array, Object 등 아무 자료형의 데이터도 넣을 수 있다.

 

 

* State를 쓰는 이유

변수가 변경될 때 자동으로 관련된 HTML을 재렌더링되게 만들려면 state에 저장해서 데이터 바인딩한다. 글 제목을 수정하거나 할때 새로고침 없이 웹페이지를 스무스하게 반영하고 싶으면 state를 사용한다. 리액트는 state가 수정되면 state가 포함된 HTML을 자동으로 재렌더링 해준다.

 

 

- JSX 기능 개발

<!-- HTML -->
<div onclick="실행할 자바스크립트">

<!-- JSX --> 
<div onClick={실행할 함수}>
<!-- ex) --> 
<div onClick={ showModal }>  (showModal은 어디 다른데 만들어둔 함수 이름)
<div onClick={ function(){ 실행할 코드 } }>
<div onClick={ () => { 실행할 코드 } }>

1. onClick (C가 대문자)

2. {} 중괄호를 사용한다.

3. 코드가 아니라 함수가 필요하다 (callback 함수 처럼 사용)

 

 

- state 변경 함수

let [ 따봉, 따봉변경 ] = useState(0); // 변수와 변수변경 함수

function App(){
  
  let [ 따봉, 따봉변경 ] = useState(0);
  return (
    <HTML 많은 곳>
      <!-- 콜백함수로 변경함수 사용 -->
      <h3> { 글제목[0] } <span onClick={ ()=>{ 따봉변경(따봉 + 1) } } >👍</span> { 따봉 }</h3>
    </HTML 많은 곳>
  )
}

1. JSX에서는 이벤트로 함수를 넣을 때 콜백 함수처럼 넣는다.

2. state는 값을 변경할 때 지정된 변경함수를 써야한다.

3. 변경함수는 데이터를 완전히 대체한다. ( 따봉 = 따봉 + 1 이런거 안됌)

 

 

function App() {
  let [글제목, 글제목변경] = useState(['남자 코트 추천', '강남 우동 맛집', '파이썬독학']);

  function 제목바꾸기(){
    // 글제목[0] = '여자코트추천' => 이런거 안됌
    var newArray = [...글제목];
    newArray[0] = '여자 코트 추천';
    글제목변경(newArray);
  }

  return (
    <div className="App">
      <button onClick={ 제목바꾸기 }>버튼</button>
      <div className="list">
        <h3>{ 글제목[0] } <span onClick={ () => {따봉변경(따봉 + 1)} }>👍</span>{ 따봉 }</h3>
        <p>2월 17일 발행</p>
        <hr/>
      </div>
    </div>
  );
}

1. onClick에는 함수만 들어갈 수 있으며 정의된 함수를 파라미터로 넣을땐 소괄호 {}는 넣지 않는다.

2. 제목 바꾸기라는 함수를 만들고 해당 로직을 입력하는데 state는 개별 조작할 수 없다.

3. 데이터를 바꾸기위해선 전체 state를 바꿔야하며 바꿀땐 state 변경함수를 쓴다.

4. 참조 타입의 자료형을 복사할 땐 꼭 원본은 놔두고 새로운 변수에 저장하며 [...xxx]식으로 딥 카피한다.

 

 

 

 

React Component

하나의 태그 그룹들을 하나의 태그로 만들고 싶을 때 사용한다.

<div className="modal">
  <h2>제목</h2>
  <p>날짜</p>
  <p>상세내용</p>
</div>
.modal{
  margin-top : 20px;
  padding : 20px;
  background : #eee;
}

 

위의 모달창을 하나의 태그로 관리 할 수 있다.

 

function App (){
  return (
    <div>
      HTML 잔뜩있는 곳
      ...
      <Modal></Modal>
    </div>
  )
}

function Modal(){ // 대문자로 사용해야 함
  return (
    <div className="modal">
      <h2>제목</h2>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

**return안에 태그를 2개 사용할 수 없다. (하나의 태그로 감싸서 사용)

 

 

:특징

1. 이름을 지을땐 영어 대문자로 시작한다.

2. return안에 태그가 평행하게 여러개 들어갈 수 없다. (<> </>를 사용하면 되긴 함)

3. function App과 동일한 위치에 생성한다.

4. 컴포넌트 안에 다른 컴포넌트를 주입할 수도 있다.

function Modal(){
  return (
    <div className="modal">
      <h2>제목</h2>
      <p>날짜</p>
      <p>상세내용</p>
      <다른컴포넌트></다른컴포넌트>
    </div>
  )
}
function 다른컴포넌트(){
  return ( <div> 안녕 </div> )
}

 

 

- Component 생성 관습

  • 반복해서 출현하는 HTML 덩어리
  • 내용이 자주 변경되는 HTML 부분
  • 다른페이지에 들어갈 내용
  • 협업할 때 ? 컴포넌트 단위

 

 

:단점

  • 많으면 관리가 힘들다
  • 다른 component 안에 있는 state를 사용할 때 바로 쓸 수 없다. (props 문법 사용해야함)

 

 

 

React에서 반복문 쓰기

* map

JSX에서는 중간중간에 중괄호 {} 안에 변수명을 넣을 수는 있으나, if나 for을 사용할 수 없다.

  let [글제목, 글제목변경] = useState(['남자 코트 추천', '강남 우동 맛집', '파이썬독학']);
  let [따봉, 따봉변경] = useState(0);

function App (){
  return (
    <div>
      HTML 잔뜩있는 곳
      ...
      { 글제목.map(function(글, i){
          return <div className="list" key={i}>
                    <h3 onClick={ ()=>{ 따봉변경(따봉+1) } }>{ 글 }</h3>
                    <p>2월 17일 발행</p>
                    <hr/>
                  </div>; <!-- ''가 없어도 알아서 리액트는 렌더링해줌 -->
      }) }
    </div>
  )
}

** 반복문 사용시 key를 정해줘야한다. key는 1,2,3,4.... 등의 순차적으로 올라가는 인덱스 같은것을 지정한다.

 

 

- 일반 for 반복문

function App (){

  function 반복된UI(){
    var 어레이 = [];
    for (var i = 0; i < 3; i++) {
      어레이.push(<div>안녕</div>) // ''없어도 리액트가 알아서 잘 렌더링 해줌
    }
    return 어레이
  }
  return (
    <div>
      HTML 잔뜩있는 곳
      
      { 반복된UI() }
    </div>
  )
}

1. 일반함수를 만들고 HTML을 담을 array 자료를 생성한다.

2. 함수 안에서 for반복문을 이용해 array에 HTML을 추가하고 완성된 array를 return 한다.

3. 원하는 곳에 { 함수() }식으로 데이터바인딩 한다.

 

 

 

props

자식 컴포넌트(Modal)가 부모 컴포넌트(App)의 state를 갖다 쓰고 싶을 때 사용한다.

function App (){
  let [글제목, 글제목변경] = useState(['남자코트 추천', '강남 우동맛집', '파이썬독학']);
  return (
    <div>
      ...
      <Modal 글제목={글제목}></Modal> <!-- 자식컴포넌트 전송할이름={state명} -->
    </div>
  )
}

function Modal(props){ // 전달받을 state를 받는 파라미터
  return (
    <div className="modal">
      <h2>제목 { props.글제목[0] }</h2>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

1. props는 <Modal 이런거={이런거}  저런거={저런거}> 방식으로 여러개 전달 가능

2. props를 전송할때 형식은 여러개이다. <Modal 글제목={변수명}> 변수 전달은 중괄호 {}, <Modal 글제목="강남우동맛집"> 텍스트 전달은 따옴표도 가능하다.

 

 

 

 

input
function App (){

  let [입력값, 입력값변경] = useState('');

  return (
    <div>
      HTML 잔뜩있는 곳...
      <input onChange={ (e) => { 입력값변경(e.target.value) } }/>
      {입력값}
    </div>
  )
}

input에 입력한 데이터는 중요한 데이터이기 때문에 state에 저장하여 사용하는게 일반적이다. 리액트에서는 자바스크립트와 다르게 input 이벤트리스너의 onChange와 onInput이 같게 작용한다. (input처럼) 때문에 둘중 하나를 사용하면되고, 이벤트리스너처럼 함수의 e.target등을 사용할 수 있다.

 

 

 

class
function App(){
  return (
    <div>
      HTML 잔뜩있는 곳
      <Profile />
    </div>
  )
}


class Profile extends React.Component { // 리액트 내장 클래스 상속
  constructor(){
    super(); // 상속 받은것 사용하기 위함
    this.state = { name: 'Kim', age: 30}
  }

  changeName = function() { // this 속성에따라 arrow나 function 사용
    this.setState( {name: 'Park'} )
  }

  render(){
    return (
      <div>
        <h3>프로필입니다</h3>
        <p>저는 { this.state.name }입니다.</p>
        <button onClick={ this.changeName.bind(this) }>버튼</button> <!-- this에 따라 바뀜 -->
      </div>
    )
  }
}

state를 변경할 때, this.setState()라는 내장함수를 꼭 사용해야 한다. 신 문법에서 쓰는 useState와 다른점은 useState는 변경 시 아예 state 자체를 바꾸는건데 예전 문법의 setState()는 필요한 부분만 수정한다.

 

onClick에 들어가는 로직이 길어져서 따로 함수로 빼서 쓰면 에러가 난다.

this.setState()라는 코드의 this가 함수(function)안에서 쓰면 값이 새롭게 재정의 되기때문에 arrow function()을 사용하거나 this.changeName.bind(this) 이런 식으로 사용해야 한다.

 

 

 

'React' 카테고리의 다른 글

[React] chap.3  (0) 2021.12.14
[React] chap.2  (0) 2021.12.07

[JavaScript] ES6 chap.2

 

 

 

default parameter & arguments

- default parameter

function 더하기 (a, b = 10){ // b에 default 값을 부여한다. 연산이나 함수 사용 가능
  console.log(a + b)
}

더하기(1); // 11
더하기(1, 3); // 4

 

- arguments

function 함수(a,b,c){
  console.log(arguments);
}

함수(2,3,4); // [2, 3, 4]....arguments
function 함수(a,b,c){
  for(var i=0; i<arguments.length; i++){
  	console.log(arguments[i]); // 반복문으로 함수의 파라미터 조회
  }
}

함수(2,3,4);

 

 

 

Rest Parameter

ES6에 추가된 arguments랑 비슷한 용도의 파라미터 (나머지 파라미터)

function 함수2(...파라미터들){
  console.log(파라미터들)
}

함수2(1,2,3,4,5,6,7); // [1, 2, 3, 4, 5, 6, 7]

arguments와의 차이점은 arguments는 함수를 사용할 때의 파라미터의 갯수가 변경되면 기존 함수의 파라미터 갯수도 변경 해야하지만 rest parameter는 유동적으로 변경 가능하다.

 

function 함수2(a, b, ...파라미터들){
  console.log(파라미터들)
}

함수2(1,2,3,4,5,6,7); // [3, 4, 5, 6, 7]



// 주의
function 함수2(a, ...파라미터들, b){
  console.log(파라미터들)
} // ...파라미터 뒤에 또 다른 파라미터가 오면 에러 발생

function 함수2(a, ...파라미터들, ...파라미터들2){
  console.log(파라미터들)
} // rest 파라미터를 중복으로 써도 에러 발생

 

 

 

Primitive data type / Reference data type

* primitive data type

- 자료 자체가 변수에 저장되는 자료 (문자, 숫자, 문자열 등)

var 이름1 = '김';
var 이름2 = 이름1;
이름1 = '박';
console.log(이름1); // 박
console.log(이름2); // 김

 

 

* reference data type

- 자료가 변수가 아닌 컴퓨터 메모리에 저장되고 참조하여 사용하는 자료 (Array, Object 등)

var 이름1 = { name: '김'};
var 이름2 = 이름1;
이름1.name = '박';
console.log(이름1.name); // 박
console.log(이름2.name); // 박

primitive 타입과 달리 reference 타입은 데이터가 저장된 것이 아니라 참조한다는 값을 가리키는 값이 저장된 것이기 때문에 참조되는 데이터를 변경하게 되면 두 변수가 가리키는 값은 같다.

 

 

- cf

var 이름1 = { name : '김' };
var 이름2 = { name : '김' };

console.log(이름1 == 이름2); // false
console.log(이름1 === 이름2); // false
console.log(이름1.name == 이름2.name); // true

위 처럼 새로운 {}를 할당할 때, 새로운 object가 생성되기 때문에 {} 안에 있는 오브젝트 데이터는 같지만 서로 다른 object이며 다른 object를 각각 가리키고 있는 것이다.

 

var 이름1 = { name : '김' };

function 변경(obj){
  obj = { name : 'park' }; // obj라는 변수에 새로운 {} object 재할당
  obj.name = 'park' // 파라미터로 들어온 object의 name의 value 변경
}

변경(이름1);

 

 

 

constructor

기존의 object 생성 방식

var 학생1 = { name : 'Kim', age : 15 };
var 학생2 = { name : 'Park', age : 15 };
...

여러번 선언하고 정의하거나 복사를 해야하는데 복사하는데 있어서 데이터가 같은 값을 참조 할 수 있기 때문에 constructor 방식으로 object를 생성할 수 있다.

 

 

* constructor

function 기계(이름){ // 기계: constructor
  this.name = 이름; // instance
  this.age = 15; // instance
  this.sayHi = function(){ // instance
    console.log('안녕하세요' + this.name + ' 입니다');
  }
}
var 학생1 = new 기계('Park');
var 학생2 = new 기계('Kim');

function이라는 함수를 정의하고 해당 함수를 new 함수() 형태로 사용한다. 어떤 변수에 기계라는 함수를 new 기계()로 할당하게되면 기계는 constructor가 되며 기계() 안에 있는 this는 instance가 되어 여러가지의 object를 생성할 수 있다.

 

 

 

prototype

prototype = 유전자의 역할

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
var 학생1 = new 기계(); // 상속의 개념 => 기계의 name과 age를 사용할 수 있음

console.log(기계.prototype); // 내부에 prototype이라는 항목이 생성

학생1이 기계의 constructor가 가진 name과 age의 instance를 사용할 수 있게되는 것을 상속(inheritance)했다고 한다. 하지만 constructor말고도 상속기능을 구현할 수 있는데 Java와 같은 다른 언어의 상속(extend)의 개념과 달리 Javascript는 prototype의 개념을 사용한다.

 

new 기계()를 생성하게되면 표면적으로 보이지 않는 내부의 공간에 prototype이라는 공간이 생성되는데 이것은 부모의 유전자 역할을 한다.

 

 

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}

기계.prototype.gender = '남';
var 학생1 = new 기계();
var 학생2 = new 기계();

console.log(학생1.gender); // 남
console.log(학생2.gender); // 남

기계라는 부모의 prototype(유전자)에 {gender: '남'} 이라는 속성을 추가하게되면 기계를 상속한 학생1, 학생2 자식은 {gender: '남'}이라는 속성을 사용할 수 있다.

 

 

* 작동원리

- 자바스크립트는 오브젝트에서 값을 출력할 때

  • 학생1에 gender라는 값이 있는가 ?
  • 기계라는 부모 유전자에 gender라는 값이 있는가 ?
  • 그럼 그 부모의 유전자에 gender라는 값이 있는가 ?
  • ...

 

// Array 생성 시
var arr = [1,2,3];
// == var arr = new Array(1,2,3);

// Object 생성 시
var obj = {name: 'kim'}
// == var obj = new Object({name: 'kim'});

Array나 Object 등의 생성 방식의 차이일 뿐 결국엔 내부에선 constructor 방식으로 생성되기 때문에 해당 object에 prototype으로 저장 되어있는 내장 함수 또한 사용할 수 있다.

 

 

** prototype과 constructor의 차이

  • constructor: 자식들이 직접 값을 소유하게 하기
  • prototype: 부모만 가지고 있고 그걸 참조해서 쓰게 하기

 

 

 

* 특징

1. prototype은 constructor 함수에만 몰래 생성된다.

 - 일반 object, array엔 prototype 없음 (constructor 함수, Object.create(), class 써야 함)

 

 

2. 부모 유전자 찾기

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
var 학생1 = new 기계();
console.log(학생1.__proto__); // 기계
console.log(기계.prototype);

 - 부모의 의해 생성된 자식엔 __proto__라는 속성이 있는데 해당 속성은 자식의 부모 object를 찾아준다.

 

 

3. __proto__를 직접 등록하면 object끼리 상속기능 구현가능

var 부모 = { name : 'Kim' };
var 자식 = {};

자식.__proto__ = 부모;
console.log(자식.name); // Kim

 

 

4. 자바스크립트는 모든게 다 Object이다.

- __proto__로 계속 올라가다보면 모든 부모는 Object라는 constructor로 통한다.

 

 

 

상속

* ES5

- Object.create()

var 부모 = { name : 'Kim', age : 50 };
var 자식 = Object.create(부모);
자식.age  = 20;

var 손자 = Object.create(자식);

console.log(손자.age); // 20 ==> 자식의 age

손자에서 age를 호출하면 자식의 속성에 age가 있는지 확인하고 있으면 그 것을 사용하지만 없다면 부모로 올라가서 age가 있는지 확인하는 순서이기 때문에 자식의 age 값은 20으로 되어있어 20이 출력된다.

 

 

* ES6

- class

class 부모 {
  constructor(){
    this.name = 'Kim';
    this.sayHi = function(){ console.log('hello') } // constructor안에 추가하기
  }
  sayHi = function(){ console.log('hello') } // prototype에 추가하기
  // == sayHi(){ console.log('hello') } // prototype에 추가하기
}

var 자식 = new 부모();

function말고도 constructor를 만드는 ES6의 방식. constructor 안에 있는 인스턴스를 만들어 사용할 수 있으며 그 외부에 만들면 prototype으로 사용할 수 있다.

 

 

* Object.getPrototypeOf()

함수 안에 object를 넣으면 부모 prototype을 출력할 수 있다. (__proto__랑 유사함)

 

 

 

extends & super
class 할아버지{
  constructor(name){
    this.성 = 'Kim';
    this.이름 = name;
  }
  sayHi(){
    console.log('안녕 나는 할아버지')
  }  
}

class 아버지 extends 할아버지{ // 할아버지라는 객체의 특성을 복사할 때 사용
  constructor(name){
    super(name); // 할아버지 객체의 속성들을 사용하기위해 선언
    this.나이 = 50;
  }
  sayHi2(){
    console.log('안녕 나는 아버지');
    super.sayHi();
  }
}

var a = new 아버지('만수');
a.sayHi2(); // 안녕 나는 아버지 안녕 나는 할아버지

 

 

할아버지 객체의 속성들을 아버지 객체에 복사하기 위해 extends를 사용한다. extends를 사용하게 되면 따라오는 super라는 예약어가 있는데 super는 부모 객체의 속성들에 접근하는 것이다.

 

super는 constructor 안에서 사용하면 부모(할아버지) class의 constructor이고 prototype 함수 안에서 쓰면 부모(할아버지) class의 prototype이다.

 

 

 

getter & setter

자바스크립트의 getter, setter는 오브젝트 내의 데이터의 무결성을 보존하기 위해 쓰는 키워드이다.

var 사람 = {
  name : 'Kim',
  age : 30,
  nextAge(){
    return this.age + 1  
  }
  setAge(나이){
    this.age = parseInt(나이);
  }
}

console.log(사람.nextAge()); // 31
console.log(사람.setAge(20)); // 20

: 함수로 데이터 꺼내오기

- object 안의 데이터가 복잡할수록 함수로 만들어 데이터를 꺼내기 쉽다.

- 내부에 있는 인스턴스 변수를 건드리지 않아 수정 시 실수를 방지할 수 있다.

 

: 함수로 데이터 수정하기

- 원본 데이터를 덮어쓰지 않고 카피 데이터로 관리할 수 있다.

- 내부에 있는 인스턴스 변수를 건드리지 않아 수정 시 실수를 방지할 수 있다.

 

 

* get, set 사용

var 사람 = {
  name : 'Kim',
  age : 30,
  get nextAge(){
    return this.age + 1  
  }
  set setAge(나이){
    this.age = parseInt(나이);
  }
}

console.log( 사람.nextAge );
console.log( 사람.setAge = 20 );

get, set을 이용하면 오브젝트 내의 함수들을 괄호 없이 사용할 수 있다.

 

 

* 사용하는 기준

- 데이터를 뽑거나 가져올 때는 get, 데이터를 입력하거나 수정할 때는 set을 쓰면 된다.

get: 함수에 파라미터가 있으면 안되며 함수 내에 return이 있어야 한다.

set: 함수는 입력을 받아 수정을 해줘야 하기 때문에 파라미터가 한개 이상 꼭 존재해야 한다.

 

class 사람 {
  constructor(){
    this.name = 'Kim';
    this.age = 30;
  }
  get nextAge(){
    return this.age + 1  
  }
  set setAge(나이){
    this.age = parseInt(나이);
  }
}

var 사람1 = new 사람();

console.log( 사람.nextAge );
console.log( 사람.setAge = 20 );

마찬가지로 class에서도 사용할 수 있다.

 

 

 

 

'JavaScript' 카테고리의 다른 글

[JavaScript] 함수형 프로그래밍 (일급함수, 고차함수)  (0) 2022.03.29
[JavaScript] ES6 chap.3  (0) 2021.12.02
[JavaScript] ES6 chap.1  (0) 2021.11.29
[JavaScript] Chap.2  (0) 2021.11.25
[JavaScript] Chap.1  (0) 2021.11.19

+ Recent posts