[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

[JavaScript] ES6 chap.3

 

 

 

Destructuring

* Array

// Array
var array = [2,3,4];
var a = array[0]; 
var b = array[1];
var c = array[2];

// ==
var [a,b,c] = [2,3,4];

// default 값
var [a,b,c = 5] = [2,3];

 

 

* Object

var { name : a, age : b } = { name : 'Kim', age : 30 }; // { a: 'Kim', b: 30 }

// key 생략
var { name, age } = { name : 'Kim', age : 30 }; // { name: 'Kim', age: 30 }

 

- 변수를 Object에 넣기

var name = 'Kim';
var age = 30;

var obj = { name : name, age : age } // { name: 'Kim', age: 30 }
// == //
var obj = { name, age } // { name: 'Kim', age: 30 }

 

 

* 함수

- Object

function 함수(name, age){
  console.log(name);
  console.log(age);
}

var obj = { name : 'Kim', age : 20 }
함수(obj.name, obj.age);


// destructuring
function 함수( { name, age }){
  console.log(name);
  console.log(age);
}

var obj = { name : 'Kim', age : 20 };
함수(obj);

 

 

- Array

function 함수( name, age ){
  console.log(name);
  console.log(age);
}

var array = [ 'Kim', 30 ];
함수(array[0], array[1]);


// destructuring
function 함수( [name, age] ){
  console.log(name);
  console.log(age);
}

var array = [ 'Kim', 30 ];
함수( ['Kim', 30] );

 

 

 

import & export

* default export

// import할 곳
<script type="module">
  import a from 'library.js';
  console.log(a);
</script>


// export할 곳
var a = 10;
export default a;

- export default는 한번만 사용이 가능하다.

- import 시에 변수명을 새롭게 작명이 가능하다.

 

 

* export

// import할 곳
<script type="module">
  import {a,b} from 'library.js';
  console.log(a);
</script>

// export할 곳
var a = 10;
var b = 20;
export {a, b};

- export는 {변수명1, 변수명2} 이렇게 사용해야하고 import 할때도 정확한 변수명을 써줘야한다.

 

 

* default export & export 동시사용

// import할 곳
<script type="module">
  import c, {a,b} from 'library.js'; // 순서는 default가 먼저 온다.
  console.log(c);
</script>

// export할 곳
var a = 10;
var b = 20;
var c = 30;
export {a, b};
export default c;

** default export로 설정한 변수가 export보다 먼저 와야한다.

 

 

* 알리아스(as)

// import할 곳
<script type="module">
  import c as 폭풍, {a as 간지, b as 폭발} from 'library.js'; // 순서는 default가 먼저 온다.
  console.log(폭풍); // 30
  console.log(간지); // 10
  console.log(폭발); // 20
</script>

// export할 곳
var a = 10;
var b = 20;
var c = 30;
export {a, b};
export default c;

as라는 키워드를 통해 새로운 변수명을 지정할 수 있다.

 

 

* 아스테리스크(*)

// import할 곳
<script type="module">
  import c, {* as 변수모음} from 'library.js'; // 순서는 default가 먼저 온다.
  console.log(a); // 10
  console.log(c); // 30
</script>

// export할 곳
var a = 10;
var b = 20;
var c = 30;
export {a, b};
export default c;

export 했던 모든 변수들을 지정할 수 있다.

** 그냥쓰면 안되고 꼭 as를 통해 변수명을 새로 지정해주어야 한다.

 

 

 

Stack & Queue

* Stack과 Queue의 동작

브라우저는 C++ 기반으로 짜여져 자바스크립트 코드를 발견하면 stack에 넣어 돌린다. 동기식 처리로 맨 윗줄부터 하나하나 실행시키는 공간이다. 하지만 ajax 요청이나 이벤트리스너, setTimeout 등의 코드를 만나게되면 처리하기까지의 시간이 오래 걸리기 때문에 Stack에서 제외하여 잠시 보류시킨다. 보류시키는 동안에 Stack에 있는 다른 처리들을 먼저 처리하고 보류되어있던 코드들은 실행 시점이 다 되었을 때 Queue에 집어 넣고 Queue에 있는 코드를 Stack에 옮겨서 처리하는데 Stack이 비어있을 때만 차례로 집어넣어 처리한다.

 

때문에 자바스크립트의 스택에 너무 무겁거나 많은 데이터가 쌓여있으면 Queue를 통해서 오는 ajax 요청이나 이벤트리스너 setTimeout 등의 코드를 실행 할 수 없다. (Stack이 10초간 실행중이면 해당 코드들은 실행 시점이 와도 실행이 되지 않음)

 

프로그램을 무겁게 돌려야 할 시

1. setTimeout을 통해 분할해서 실행한다.

2. Web worker를 이용한다.

 

 

 

 

 

Synchronous / Asynchronous

* Synchronous

- 동기식 처리: 한번에 코드 한줄씩 차례차례 실행

<script>
  console.log(1); 
  console.log(2); 
  console.log(3);
  // 1 2 3
</script>

 

 

- 비동기식 처리: 먼저 시작된 코드와 상관없이 새로운 코드를 실행

// python
print(1)
print(2)
time.sleep(1)
print(3)
// 1 2 1초쉬고 3

<script>

  console.log(1);
  setTimeout(function(){console.log(2);}, 1000);
  console.log(3);
  // 1 3 1초쉬고 2

</script>

 

 

브라우저는 비동기처리를 하는 코드들을 제쳐두고 원래 코드부터 실행한다. (ex. ajax, setTimeout, addEventListener)

 

코드를 실행하다가 ex에 해당하는 코드를 보게되면 Web API 대기실로 옮겨서 대기 시키다가 실행시점이 도달했을 때 코드를 꺼내서 실행시킨다. 때문에 시간이 오래 걸리는 코드들을 비동기식으로 처리할 수 있다.

 

 

* 콜백함수

- 함수 안에 들어가는 함수. 비동기 상황 등에서 순차적으로 실행하고 싶을 때 사용한다. 어떤 이벤트가 발생했거나 특정시점에 도달했을 때 시스템에서 호출.

function 첫째함수(){
  console.log(1)
}

function 둘째함수(){
  console.log(2)
}

function 셋째함수(){
  console.log(3);
}

첫째함수(); // 비동기 시 실행순서 보장 못함
둘째함수(); 


// 콜백함수
function 첫째함수(콜백){
  console.log(1);  
  콜백();
}

function 둘째함수(콜백){
  console.log(2);
  콜백();
}

function 셋째함수(){
  console.log(3);
}

첫째함수(function(){
  둘째함수(function(){
    셋째함수(function(){
      ...
    });
  });
}); // 1 2 3

다른 프로그래밍 언어라면 순차적으로 출력되겠지만 자바스크립트의 경우는 비동기식 처리 함수가 있을 시 Web API 대기실로 보내져서 나중에 실행된다.

 

 

- callback hell

첫째함수(function(){
  둘째함수(function(){
    셋째함수(function(){
      어쩌구..
    });
  });
}):

 

 

 

Promise

- 콜백함수의 한 디자인 패턴 (성공&실패 판정)

var 프로미스 = new Promise(function(성공, 실패){
  var 연산 = 1 + 1;
  성공(연산);
});

프로미스.then(function(결과){
  // Promise 성공 시 실행할 코드
  // 성공 파라미터를 통해 결과 값을 받아올 수 있음
}).catch(function(){
  // Promise 실패 시 실행할 코드
}).finally(function(){
  // Promise 결과와 상관없이 실행할 코드
});

성공하면 then(), 실패하면 catch()를 실행하는 코드를 짤 수 있다.

 

: 장점

 - 콜백함수 사용시 코드가 옆으로 길어지지 않아 보기 직관적이다.

 - 성공뿐만 아니라 실패 또는 결과와 상관없이 실행할 코드를 지정할 수 있다. (catch, finally)

 

 

* Promise 특징

1. Promise를 선언한 변수를 출력하면 대기<pending>, 성공<resolved>, 실패<rejected>의 3단계로 나뉜다. (한번 정해진 상태를 되돌릴 수는 없다.)

 

2. 동기를 비동기로 만드는 것이 아니라 콜백 함수를 지정하는 하나의 디자인 패턴이다. (Promise 안에 어려운 연산을 시키면 브라우저가 멈춤)

 

 

 

async / await

- Promise와 then을 쉽게 쓸수 있게 만들어주는 ES8 문법

 

* async

async function 연산 (){ // 이 함수 자체가 Promise
  return 1 + 1;
}

연산().then(function(결과){ // then을 사용할 수 있음
  console.log(결과); // 2
})

Promise를 알아서 생성해주기 때문에 함수를 실행할 때 then을 붙일 수 있다. 또한 async 함수 안에서 나온 결과를 then 안에서 파라미터로 받아서 사용할 수 있다.

 

 

* await

async function 더하기(){
  var 어려운연산 = new Promise((성공, 실패)=>{
    var 결과 = 1 + 1;
    성공();
  });
  어려운연산.then(function(result){
    console.log(result);
  });
}
더하기();

/////////// 같은 결과 /////////////

async function 더하기(){
  var 어려운연산 = new Promise((성공, 실패)=>{
    var 결과 = 1 + 1;
    성공();
  });
  var 결과 = await 어려운연산;
  console.log(결과);
}
더하기();

////////// async만 사용 했을 때 //////////

async function 더하기(){
  async function 어려운연산(){                
    return 1 + 1;
  }
  var result = await 어려운연산();
  console.log(result);
}
더하기();

단순히 then 대신에 await을 사용했다. await을 사용하면 문법이 훨씬 더 간단하다. 어려운연산 Promise를 기다린 다음에 완료되면 결과를 변수에 담는다. ( ** 비동기식 처리되는 코드를 담는다면 await을 기다리는 동안 브라우저가 잠깐 멈출수 있다.)

 

 

async function 더하기(){
  var 어려운연산 = new Promise((성공, 실패)=>{
    실패();
  });
  try {  
    var 결과 = await 어려운연산 // 성공했을 시 실행할 코드
  }
  catch { 
    // 어려운연산 Promise가 실패할 경우 실행할 코드 
  }
}

await은 Promise가 실패하면 에러가 나고 코드가 멈추기때문에 하단의 코드들은 더 이상 실행되지 않지만 그것을 방지하기 위해 try{} catch{}를 실행하면 된다. try 문에 성공했을 시 수행할 코드, catch 문엔 실패했을 시 수행할 코드를 넣으면 된다.

 

 

 

반복문
  • for 반복문 (공통)
  • forEach() 반복문 (Array 전용)
  • for in 반복문 (Object 전용)
  • for of 반복문 (iterable 전용)

 

* for in 반복문

- Object 자료형에 저장된 자료들을 꺼내고 싶을 때 사용

var 오브젝트 = { name : 'Kim', age : 30 };

for (var key in 오브젝트) { // 오브젝트의 자료 2개 = 2번 반복
  console.log(오브젝트[key]); // key는 오브젝트의 key
}

: 특징

 1. enumerable한 것만 출력한다.

var 오브젝트 = { name : 'Kim', age : 30 };

console.log( Object.getOwnPropertyDescriptor(오브젝트, 'name') ); // 오브젝트 속성
// {value: "Kim", writable: true, enumerable: true, configurable: true}
// enumberable은 셀수 있는지의 여부인데 object는 생성 시 true로 되어있음.

enumerable이 true로 체크 되어있어야 for in 문에서 거르지 않는다.

 

 

2. 부모의 prototype에 저장된 것도 출력한다.

class 부모 {

}
부모.prototype.name = 'Park';

var 오브젝트 = new 부모();

for (var key in 오브젝트) {
  console.log(오브젝트[key]); // Park
}

부모가 가지고 있는 prototype도 출력한다.

 

class 부모 {
 
}
부모.prototype.name = 'Park';

var 오브젝트 = new 부모();

for (var key in 오브젝트) {
  if (오브젝트.hasOwnProperty(key)) {
    console.log(오브젝트[key]);
  }
}

해당 오브젝트에 hasOwnProperty() 함수를 사용하면 오브젝트가 직접 가지고 있는지 true or false로 체크 하여 사용할 수 있다.

 

 

* for of 반복문

- 여러가지 자료형에 사용할 수 있는 반복문 (Array, 문자, arguments, NodeList, Map, Set 등)

var 어레이 = [2,3,4,5];
for (var 자료 of 어레이) {
  console.log(자료);
}

: 특징

1. iterable한 자료형들에만 사용 가능하다.

var 어레이 = [2,3,4,5];
console.log( 어레이[Symbol.iterator]() ); // ~~~ iterator {} 속성이 있음
// 위의 방법으로 콘솔 출력시 iterator속성이 있으면 iterable하다고 한다.

 

 

 

 

 

Symbol
var 심볼 = Symbol('설명아무거나적기');

- Object 자료형에 비밀스러운 key값을 부여하고싶을 때 사용한다.

 

 

var person = { name : 'Kim' };
person.weight = 100;

var weight = Symbol('내 진짜 몸무게');
person[weight] = 200;

console.log(person);

: 특징

- for문에 등장하지 않는다.

- 특이한 이름을 가진 자료를 Object안에 만들고 싶을 때 사용한다.

 

// 직접 입력
var height = Symbol('내 키임');
var person = { name : 'Kim', [height] : 160 };


// 심볼은 값은 같아도 서로 다른 Symbol
var a = Symbol('설명1');
var b = Symbol('설명1');
console.log(a === b); // false


// 전역 심볼
var a = Symbol.for('설명1');
var b = Symbol.for('설명1');
console.log(a === b); // true


// 기본 내장 Symbol
ar array = [2,3,4];
console.log(array[Symbol.iterator]); // Array iterator {}...

 

 

 

 

Map & Set

* Map

- 자료의 연관성을 위해 사용한다.

var person = new Map();
person.set('name', 'Kim');
person.set([1,2,3], 'Kim'); // key 값에 어떤 자료도 가능하다
person.set('age', 20);
// Map {"name" => "Kim", "age" => 20}

 

 

- 사용법

var person = new Map();
person.set('age', 20);

person.get('age'); //자료 꺼내는 법
person.delete('age'); //자료 삭제하는 법
person.size; //자료 몇갠지 알려줌

//Map자료 반복문 돌리기
for (var key of person.keys() ){
  console.log(key)
}

//자료를 직접 집어넣고 싶으면

var person = new Map([
  ['age', 20],
  ['name', 'Kim']
]);

Array 같은 자료형에 대량의 데이터가 있을시 Hash Map, Hash Table 등을 사용한다. Array 같은경우 필요한 데이터를 사용 시에 반복문을 돌려 일일이 출력해봐야 아는데, Hash Table은 미리 abc순으로 정렬되어 있어서 빠르게 찾을 수 있다. Hash Table은 자료에 key 값을 부여해놓고 정렬하는 식으로 구성되어있다. Object 자료형이랑 비슷하다. Object는 hasOwnProperty, toString 키들도 집어넣을수 있어서 너무 유연하고, key 값이 문자형태로 제한되어 들어올 수 밖에 없는 차이가 있다.

 

 

* Set

- 자료를 Array처럼 일렬로 저장할 수 있다. (***중복 제거)

var 출석부2 = new Set([ 'john' , 'tom', 'andy', 'tom' ]);

console.log(출석부2); // Set { "jhon", "tom", "andy"}

Set은 중복된 자료를 허용하지 않는다.

 

 

var 출석부2 = new Set([ 'john' , 'tom', 'andy', 'tom' ]);

출석부2.add('sally'); //자료더하기 
출석부2.has('tom'); //자료있는지 확인
출석부2.size;  //자료 몇갠지 세기

var 출석부 = [ 'john' , 'tom', 'andy', 'tom' ];

var 출석부2 = new Set(출석부); //Array를 Set으로 바꾸기

출석부 = [...출석부2]  //Set을 Array로 바꾸기

 

 

 

Web Components

- 여러개의 태그들을 하나의 단어로 축약해서 사용할 수 있다

<custom-input name="이름"></custom-input>
<custom-input name="비번"></custom-input>

<script>
  class 클래스 extends HTMLElement {

      connectedCallback() { // html 태그 사용 할 부분
        let name = this.getAttribute('name'); // attribute 추가 해서 사용 가능
        this.innerHTML = '<label>${name}을 입력하쇼</label><input>'
      }
      
      static get observedAttributes() {
        return ['name'] // 여러개면 [ 속성, 속성...] 이런식으로 사용
      }
      
      attributeChangedCallback() {
        // attribute 변경시 실행할 코드
      }
  }

  customElements.define("custom-input", 클래스); // 컴포넌트 등록
</script>

<custom-input> 같은 커스텀 태그를 컴포넌트라고 한다. 해당 기능은 React나 Vue에서 제공하는 자동 html 재렌더링 기능처럼 구현한 것이다. 

 

 

* Shadow DOM과 template 모듈화

- Shadow DOM

<div class="mordor"></div>
<script>
  document.querySelector('mordor').attachShadow({mode : 'open'}); // shadow 공간 만들기
  document.querySelector('mordor').shadowRoot.innerHTML = '<p>심연에서왔도다</p>' // html 사용
</script>

해당 방법으로 shadow DOM을 만들 수 있고 shadow DOM은 web component와 사용시 유용하다.

 

 

: web component 문제점

<custom-input></custom-input>
<label>왜 나까지 빨개짐?</label>

<script>

  class 클래스 extends HTMLElement {
    connectedCallback() {
      this.innerHTML = `<label>이름을 입력하쇼</label><input>
        <style> label { color : red } </style>`
    }
  }

  customElements.define("custom-input", 클래스);
  
</script>

컴포넌트화할 때 스타일까지 포함하는 경우가 많은데 해당 컴포넌트를 제외한 다른 요소들까지 같이 적용될 수가 있다. 이럴때 스타일을 shadow DOM을 열어서 집어넣게 되면 shadow DOM안에 있는 스타일은 밖에까지 영향을 끼치지 않기때문에 html의 모듈화 개발이 가능하다.

 

 

- template 태그

해당 태그에 적힌 html은 렌더링 되지 않는다.

 <custom-input></custom-input>

  <template id="template1">
    <label>이메일을 입력하쇼</label><input>
    <style>label { color : red }</style>
  </template>

  <script>
    class 클래스 extends HTMLElement {
      connectedCallback() {
        this.attachShadow({mode : 'open'});
        this.shadowRoot.append(template1.content.cloneNode(true));
        let el = this.shadowRoot.querySelector('label');
        el.addEventListener('click', function(){ // 이벤트리스너 사용
          console.log('클릭함')
        })
      }
    }
    customElements.define("custom-input", 클래스);
  </script>

컴포넌트를 만들 때 html이 너무 길어지면 가독성이 떨어지니 template태그에 내용을 보관해두고 shodowRoot를 통해 집어 넣을 수 있다.

 

 

 

[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

[JavaScript] ES6 chap.1

 

 

 

this

1. 아무데서 쓰거나 일반 함수에서의 this는 window

<script>

    console.log(this); // Window
    
    function 함수(){
    	console.log(this); 
    }
    
    함수(); // Window
    
</script>

 

** use strict **

<script>
    'use strict';

    console.log(this); // Window
    
    function 함수(){
    	console.log(this); 
    }
    
    함수(); // undefined
    
</script>

 

 

2. object 자료형 안의 함수에서 this값은 오브젝트 그 자체

<script>
    
    var 오브젝트 = {
        data: "kim",
        함수: function(){
            console.log(this);
        }
    }
    
    오브젝트.함수(); // { data : 'Kim', 함수 : f }
    
</script>

this값: 오브젝트 객체

 

<script>
    
    var 오브젝트2 = {
        data: {
          함수: function(){
              console.log(this);
          }
        }
    }
    
    오브젝트2.data.함수(); // { 함수 : f }
    
</script>

this값: data 객체

 

 

* window 객체

<script>

  (1)
  function 함수(){
    console.log(this)
  }

  (2)
  window.함수 = function(){
      console.log(this);
  }; <!-- window라는 오브젝트에 함수 자료를 추가 -->
  
  <!-- (2)와 같은 의미
  var window = {
    함수: function(){
      console.log(this);
    }
  }
  실질적으로 window로 객체 변수를 선언하면 에러 남-->
  
</script>

- 2번의 뜻은 1번의 뜻과 상통한다. script라는 태그 자체안에 window라는 큰 객체(object)가 있는것이다.

 

 

3. constructor(생성자) 안에서 쓰면 constructor로 새로 생성되는 오브젝트

<script>
       
    function 생성자(){
        console.log(this);
    }        

    new 생성자(); // 생성자 {}
        
</script>

this 값: 생성자 객체

 

 

<script>

    function 생성자or함수(){
        this.테스트 = "test";
        console.log(this);
    }        

    // 1번의 경우
    new 생성자or함수(); // 생성자or함수 {테스트: kim}
    
    // 3번의 경우
    생성자or함수(); // Window
    
</script>

- 함수로 사용 했을시엔 window 객체를 가리키지만 new를 통해 생성자(constructor)로 만들게 되면 해당 function의 이름으로 새로운 object 객체를 만든다.

 

 

4. eventListener 안에서 쓰는 this는 e.currentTarget

<script>

	document.getElementById('ID').addEventListener('click', function(e){
            // == e.currentTarget
            console.log(this); // document.getElementById('ID')            
	});
    
</script>

- 이벤트리스너 안에서의 this는 지금 이벤트가 동작하는 곳을 의미하며, e.currentTarget과 document.getElementById('ID')와 같은 의미이다.

 

 

** 가장 가까이 있는 함수에 따라 바뀌는 this

<script>

    document.getElementById('버튼').addEventListener('click', function(e){
        console.log(this); // document.getElementById('버튼') (4)
        var 어레이 = [1,2,3];
        어레이.forEach(function(){
            console.log(this); // window, window, window (1)
        });
    });

    var 오브젝트 = {
        이름들 : ['김', '이', '박'],
        함수 : function(){
            console.log(this); // 오브젝트 { 이름들: ['김', '이', '박'] } (2)
            오브젝트.이름들.forEach(function(){
                console.log(this); // window, window, window (1)
            });
        }
    }
    
    console.log(오브젝트.함수());
</script>

 

 

** function()과 arrow함수의 차이

<script>

    var 오브젝트 = {
        이름들 : ['김', '이', '박'],
        함수 : function(){
            console.log(this); // 오브젝트 { 이름들: ['김', '이', '박'] } (2)
            오브젝트.이름들.forEach(function(){
                console.log(this); // window, window, window (1)
            });
        }
    }

    console.log(오브젝트.함수());
    
    var 오브젝트2 = {
        이름들 : ['김', '이', '박'],
        함수 : function(){
            console.log(this); // 오브젝트 { 이름들: ['김', '이', '박'] } (2)
            오브젝트2.이름들.forEach( () => {
                console.log(this); // 오브젝트 { 이름들: ['김', '이', '박'] } (2)
            });
        }
    }
    
    console.log(오브젝트2.함수());

</script>

ES6에선 function(){} 대신 () => {} 라는 arrow function 문법이 있는데, 둘의 차이는 함수 내부의 this 값을 새로 바꿔주지 않기 때문에(=바깥에 있던 this값을 내부에서 그대로 사용) this를 사용하기 유용하다.

 

 

 

Arrow function
<script>

    var x = function(){} // 기존 함수
    
    var y = () => {} // arrow 함수

</script>

 

 

* 사용법

<script>

    var 두배만들기 = (x) => { return x * 2 }
    console.log( 두배만들기(4) );
    
    
    var 두배만들기 = x => x * 2 ;
    console.log( 두배만들기(8) );

</script>

- 파라미터가 하나면 중괄호 생략이 가능하고 return 값도 한 줄이면 중괄호와 return도 생략 가능하다.

 

 

* arrow function에서의 this

<script>

    var 오브젝트1 = {
        함수 : function(){ 
            console.log(this)
        }
    }

    오브젝트1.함수(); // { 오브젝트1: 함수f }
    
    
    var 오브젝트1 = {
        함수 : () => { console.log(this) }
    }

    오브젝트1.함수(); // window

</script>

arrow function은 외부에 있던 this를 그대로 내부로 가져와서 사용한다.

 

 

 

 

 

var, let, const

* var

  • 재선언 (o)
  • 재할당 (o)
  • 범위: function
var 이름 = 'kim';

이름 = 'lee' // (o)
var 이름 = 'kim'; // (o)

function(){
    var 테스트 = 'test';
    테스트 // (o)
}

테스트 // (x)

 

 

* let

  • 재선언 (x)
  • 재할당 (o)
  • 범위: {}
let 이름 = 'kim';

이름 = 'lee' // (o)
let 이름 = 'kim'; // (x)

if(1 == 1){
    let 테스트 = 'test';
    테스트 // (o)
}

테스트 // (x)

 

 

* const

  • 재선언 (x)
  • 재할당 (x)
  • 범위: {}
const 이름 = 'kim';

이름 = 'lee' // (x)
const 이름 = 'kim'; // (x)

if(1 == 1){
    const 테스트 = 'test';
    테스트 // (o)
}

테스트 // (x)

 

const 오브젝트 = { 이름 : 'Kim' }
오브젝트.이름 = 'Park'; //가능

const 변수를 쓴다고 하더라도 const로 선언된 변수의 자료 형이 object 형이라면 안에 있는 값을 변경 할 수 있다. 변경 불가능한 값을 만드려면 Object.freeze()라는 기본 함수를 사용하면 된다.

 

 

 

호이스팅, 클로저

- 호이스팅

<script>

    // var 이름;

    console.log(이름); // undefined

    var 이름 = 'Kim'; // 이름 = 'kim;
    
    console.log(이름); // kim
    
</script>

var 변수를 사용하게되면 (var 변수) 선언 부분은 맨 위로 올리고 (변수 = 값)만 그 자리에 남게되는데 이런것을 호이스팅이라고 한다. (함수 또한 호이스팅 가능하다.)

 

 

- 클로저

var 나이 = 20;

function 함수(){
  console.log(나이)
}

함수();

클로저는 바깥에 있는 변수는 안쪽에서 자유롭게 사용할 수 있다는 것을 의미한다. 이것을 참조가능하다라고도 한다. 함수 안쪽에 나이라는 변수가 있다면 그것을 사용하겠지만 없으면 바깥에 있는 변수를 사용한다.

 

 

 

Template literals

따옴표 대신 backquote, backtick 이라는 '`' 기호를 사용하여 문자를 만드는 법이다.

: 장점

  • 문자 중간 엔터키 입력가능
  • 문자 중간 변수를 집어넣을 때 편리
var 문자 = `안녕

하세요`;
var 이름 = '손흥민';
var 문자 = `안녕하세요 ${이름} 입니다`;

 

 

* Tagged Literals

 - 문자 해체분석

var 변수 = '손흥민';

function 해체분석기(문자들, 변수들){
  console.log(문자들);
  console.log(변수들);
}

해체분석기`안녕하세요 ${변수} 입니다`; // () 대신에 이런식으로 사용 가능하다.
// 문자열 값: [안녕하세요, 입니다]
// 변수 값: 손흥민

 

 

 

spread operator

- 괄호를 제거해주는 연산자 (함수/소괄호, 오브젝트/중괄호, 어레이/대괄호에서 사용)

var 어레이 = ['hello', 'world'];
console.log(어레이); // ['hello', 'world']
console.log(...어레이); // hello world

 

- 문자의 경우

var 문자 = 'hello';
console.log(문자[0]); // h
console.log(문자[1]); // e
console.log(문자); // hello
console.log(...문자); // h e l l o

 

 

* 합치기 / 복사

// Array
var a = [1,2,3];
var b = [4,5];
var c = [...a, ...b]; // [1, 2, 3, 4, 5]

// Object
var o1 = { a : 1, b : 2 };
var o2 = { c : 3, ...o1 }; // { a: 1, b: 2, c: 3}

: 합치기

 

var a = [1,2,3];
var b = a;

console.log(a);
console.log(b);

var object1 = {a: 1, b: 2};
var object2 = object1;

console.log(object1);
console.log(object2);

: 복사

등호(=)를 이용하여 쉽게 Array와 Object의 값을 복사 할 수는 있지만 참조 값 타입의 변수를 등호(=) 방식으로 복사 하게되면 값 공유가 일어난다. 때문에 복사되어진 값과 복사한 값의 값 변경이 같이 일어나기 때문에 올바른 복사 방식은 아니다.

 

var a = [1,2,3];
var b = [...a];

console.log(a);
console.log(b);

var object1 = {a: 1, b: 2};
var object2 = {...object1};

console.log(object1);
console.log(object2);

: spread를 통한 복사 방식

값 변경이 일어나도 서로의 값에 영향을 주지 않는다.

 

 

* 만약 spread를 통한 복사를 했을 때, 중복되는 값이 있다면 ??

var o1 = { a : 1, b : 2};
var o2 = { a : 3, ...o1 };
console.log(o2); // {a: 1, b: 2}

중복된 값이 있다면 기존의 값에 새롭게 들어온 값으로 저장된다.

 

 

 

apply, call

array를 파라미터 형태로 집어넣고 싶을 때 사용한다.

function 더하기(a,b,c){
   console.log(a + b + c)
}

더하기(1,2,3); // 6

var 어레이 = [10, 20, 30];

더하기(어레이[0], 어레이[1], 어레이[2]); // 60 주먹구구
더하기.apply(undefined, 어레이); // 60 옛날방식
더하기(...어레이); // 60 요즘방식

 

var person = {
    인사 : function(){
      console.log(this.name + '안녕')
    }
}
  
var person2 = {
    name : '손흥민'
}

person.인사.apply(person2);
person.인사.call(person2);

어떤 함수(person)를 실행하는데 다른 오브젝트(person2)에다가 적용해서 실행할 때 사용한다.

 

person.인사.apply(person2, [1,2,3]); // array 형태
person.인사.call(person2, 1,2,3); // 일반 형태

apply와 call의 사용법과 결과는 똑같지만 함수에 파라미터를 넣어서 실행할 때, apply는 array[] 형태로, call은 일반 함수처럼 파라미터를 전달한다.

 

 

 

 

 

'JavaScript' 카테고리의 다른 글

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

+ Recent posts