JavaScript 함수와 클래스

JaeHwan Kim·2021년 4월 2일

HTML, CSS, JS

목록 보기
3/4
post-thumbnail

업데이트 21.04.06

ECMA 스크립트

ES5.1 미만은 구형 브라우저에서 지원, ES6 이상을 지원하지 못한다.
ES6 이상은 신형 브라우저에서도 지원 가능하다.

ES6는 2015년을 기점으로 나왔으며, 이때부터 JS의 전성기가 시작된다.

ECMA 스크립트는 웹 표준에 근거하기 때문에 프론트엔드 개발자에게는 필수적으로 요구되는 역량이다.

JS=JavaScript=ES=ECMA 스크립트는 유사한 의미이다.

데이터형 확인

// 간단한 데이터형은 확인이 가능하나 배열-객체-null 간은 힘들다.
console.log(typeof []);

// 아래와 같은 함수를 통해 우리는 정확한 데이터형을 확인할 수 있다.
function getType(data) {
  return Object.prototype.toString.call(data).slice(8, -1)
}

import-export

main.js 외에 메소드를 담기 위해 js 파일을 생성 한다음,
export default 키워드를 통해 메소드를 내보낼 수 있다.

// getType.js
export default function getType(data) {
  return Object.prototype.toString.call(data).slice(8, -1)
}

아래와 같이 import 키워드를 통해 내보낸 메소드를 사용할 수 있다.
.js (파일 확장자)는 생략된다.

// main.js
import getType from './getType'

삼항 연산자

if else문은 아래와 같이 줄여 사용할 수 있다.
단, if else문이 복잡하다면 읽기 어려워지기 때문에 간단한 경우에만 사용하는 것이 좋다.

const a = 1 < 3
console.log(a ? '참' : '거짓')  // 참

switch 문

상황에 따라 적절하게 switch 문을 사용할 수 있어야 한다.
특히, 확실한 조건(딱 떨어지는 값)이 있을 경우4에는 switch를 사용하는 것이 적합하다.

switch (조건) {
  case 정수:
    실행할 값
    break
  case 정수:
    실행할 값
    break
  default:          // default가 곧 if else문에서의 else이다.
    실행할 값
}

반복 for문

패턴이 있는 작업들은 반복문을 사용하여 작업하는 것이 효율적이다.

// 종료 조건이 false가 되는 경우 반복문이 끝난다.
for (시작조건; 종료조건; 변화조건) {
  실행할 내용
}

변수 유효 범위(Variable Scope)

let, const는 블록 레벨의 유효 범위를 가진다.
var는 함수 레벨의 유효 범위를 가진다.

함수 레벨의 유효 범위를 사용하게 되면 생각치 못한 곳에서 변수 값이 사용될 수 있고,
계속해서 함수 레벨에서 사용되기 때문에 메모리가 누수될 확률이 높다.
이에 따라, var 사용을 권장하지 않는다.

형 변환(Type Conversion)

==(동등 연산자)를 사용하면 형 변환이 자동으로 일어난다.
이는 의도하지 않은 결과가 나올 수 있다는 뜻이기 때문에 가급적 사용하지 않는 것을 추천한다.

Truthy (참 같은 값)

true, {}, [], 1, 2, 'false', -12, '3.14'

Falsy (거짓 같은 값)

*아래 정도는 숙지하고 있어야 한다.

false, '', null, undefined, 0, -0, NaN

NaN(Not a Number) : 더해진 값이 숫자로 판단할 수 없는 특정 값인 경우
예시) 1 + undefined // 결과 : NaN

함수 호출

함수가 호출 횟수를 줄이는 것은 중요하다.

  • 함수가 여러 번 호출되어야 하는 것은 함수 결과 값을 변수에 담는 것이 좋다.
  • 함수가 단일로 호출되어야 하는 것은 변수에 담지 않고 함수를 바로 사용하는 것이 좋다.
// 여러번 호출하는 경우는 변수에 담는 것이 좋다.
const a = sum(1,2);
const b = sum(3,4);
console.log(a);
console.log(b);
console.log(a+b);

// 1번만 호출하는 경우는 바로 출력하는 것이 좋다.
console.log(sum(1,2));
console.log(sum(3,4));

함수의 arguments 객체

자바스크립트는 함수 선언 시 매개 변수를 만들지 않아도, arguments 객체에 매개 변수 값이 저장된다.
그러나, 매개 변수의 이름을 직관적으로 명시하는 것을 권장한다.
단, 매개 변수의 개수가 너무 많을 때 사용하기 적합하다. (가급적 사용하지 않도록 한다.)

function sum() {
  return arguments[0] + arguments[1]
}
console.log(sum(1,3));  // 4

화살표 함수(Arrow Function)

간단한 함수들을 축약하여 작성할 수 있게 도와주는 함수이다.
아래의 예시를 통해 확인하는 것을 추천한다.

// 1) 일반 함수
const double = fucntion (x,y) {
  return x * y 2
}

// 2) 매개 변수가 2개인 화살표 함수
const doubleArrow = (x, y) => x * y * 2

// 3) 매개 변수가 1개인 화살표 함수
const doubleArrow = x => x * 2

// 4) 화살표 함수의 반환 값이 객체일 때는
// () 소괄호를 감싸줘야 한다.
const doubleArrow = x => ({name: "baobab"})

즉시 실행 함수(Immediately-Invoked Function Expression, IIFE)

함수 선언과 동시에 바로 실행할 수 있는 함수이다.

(function(){
  console.log(2);     
}());     // 2

호이스팅(Hoisting)

함수 선언부가 호출 유효 범위 최상단으로 올라오는 현상이다.

test();         // 함수 선언보다 호출이 먼저 되었는데도 7이 출력됨
function test() {
  console.log(7);
}

타이머 함수 (Timer Function)

setTimeout(함수, 시간) : 일정 시간 후 함수 실행
setInterval(함수, 시간) :시간 간격마다 함수 실행
clearTimeout() : 설정된 Timeout 함수 종료
clearInterval() : 설정된 Interval 함수 종료

*주의 : setTimeout() 함수를 사용했다고 프로세스가 멈춘 것은 아니다.
따라서, 바로 다음 행에 있는 코드 내용을 실행한다.

// 1초 마다 타이머 함수 실행 -> test 콘솔 출력
const timer = setInterval(() => {
  console.log('test');
}, 1000);
// h1 태그 클릭 -> 타이머 종료
const h1El = document.querySelector('h1');
h1El.addEventListener('click', () => {
  clearInterval(timer);
});

콜백 함수 (Callback Function)

콜백 함수 : 함수의 인수로 사용되는 함수이다.

예시) setTimeout(함수2, 시간) // setTimeout 안의 함수2가 콜백함수이다.
위에서 언급하였듯이 타이머 함수는 프로세스가 멈추지 않고 다음 행을 실행한다.
이때, 콜백 함수를 사용하면 타이머 함수 안의 인수로 함수를 사용함으로써 개발자의 의도대로 뒤늦게 사용할 수 있게 된다.

즉, 콜백 함수를 이용하여 특정한 실행 위치를 보장해줄 수 있다.

function timeout(cb) {
  setTimeout(() => {
    console.log('Test!');
    cb();
  }, 3000);
};

timeout(() => {
  console.log('callback function!');
});

리터럴이란?

리터럴은 어떠한 값을 명칭하는 것이 아니라 변수, 상수에 저장되는 '값 자체'를 의미한다.
살을 조금 덧붙이자면, 코드 상에서 데이터를 표현하는 방식이라고 할 수 있다.

/// 아래와 같이 객체를 생성할 때 {}를 사용한다. 이를 리터럴 표기법이라 한다.
const User {
  firstname: "bao";
}

// 만일 리터럴을 사용하지 않고 생성자를 사용한다면 아래와 같다.
const User = new Object();
User.firstName = "bao";

// 리터럴을 사용하지 않고 생성자를 사용하여 객체를 생성할 경우
// 코드가 더 길어질 뿐만 아니라 유효범위 판별 작업을 매번해야 한다.
/// => 동일한 이름의 함수가 정의되어 있지는 않은지 유효범위 체인을 따지며 확인해야 한다.

JS 클래스, 생성자 함수

원래 JS에서는 객체를 생성하기 위해서 복잡한 과정을 거쳐야 한다.

함수를 정의하고, 매개 변수로 정보를 받고, 이를 this를 이용하여 일일이 값을 넣어주고,
정의한 함수를 new 키워드로 호출하여 새로운 변수에 저장해야 객체가 생성된다.

1. 객체를 이용한 생성자 함수
/// 아래는 baobab의 firstName, lastName, getFullName 메소드를 가진 객체이다.
const baobab = {
  firstName: "Bao",
  lastName: "Bab",
  getFullName: function() {
    return `${this.firstName} ${this.lastName}`
  }
}
console.log (baobab.getFullName());
/// 위와 같이 객체를 생성하면 동작이 같은 메소드를 실행하는 데도 메모리가 사용된다.
/// 위에는 매번 객체를 새로 생성해줘야 되지만, 
/// 아래는 함수를 호출해서 생성하기 때문에 값만 잘 넣어주면 된다.
/// 이를 방지하기 위해 다음과 같이 생성자 함수를 만들어 객체를 사용할 수 있다.

2. 생성자 함수와 프로토타입 속성
/// 생성자 함수에서 사용할 변수들을 선언한다.
/// 생성자 함수에 한해 camelCase가 아니라 PascalCase로 작성한다.
function User(first, last) {
  this.firstName = first;
  this.lastName = last;
}
/// user 생성자의 메소드를 만들어 주기 위해서 prototype 속성을 사용한다.
/// 아래와 같이 생성자함수.속성.메소드이름 = function() {}; 형태로 사용한다.
User.prototype.getFullName = function() { 
  return `${this.firstName} ${this.lastName}`
}
/// 'new' 키워드를 사용하면 
const baobab = new User("Bao", "Bab");
console.log(baobab.getFullName());

3. 객체 지향 언어를 따라한 클래스 키워드
class User {
  constructor(first, last) {
    this.firstName = first
    this.lastName = last
  }
  getFullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

const baobab = new User('bao','bab');
const jhkim = new User('kim','jh');

console.log(baobab);
console.log(jhkim.getFullName());

Class 상속

class Vehicle {
  constructor(name, wheel) {
    this.name = name
    this.wheel = wheel
  }
}

// extends 뒤에 오는 클래스로부터 상속을 받아온다.
// super가 곧 Vehicle의 역할을 한다.
class Bicycle extends Vehicle {
  constructor(name, wheel) {
    super(name, wheel)
  }
}

// 기본적으로 확장을 사용할거면 아래와 같이 새로운 기능(변수)가 추가되어야 한다.
// 이제, 클래스 Car의 객체는 name, wheel, license 정보를 보유하고 있다.
class Car extends Vehicle {
  constructor(name, wheel, license) {
    super(name, wheel)
    this.license = license
  }
}

const myVehicle = new Vehicle('운송수단', 2)  // 객체 정보 : '운송수단', 2
const myCar = new Car('버스', 4, true); // 객체 정보 : '버스', 4, true

this 함수

일반 함수는 호출 위치에 따라 this가 정의 되고,
화살표 함수는 자신이 선언된 함수 범위에 한해서 this가 정의 된다.
이를 이용해 상황에 따라 적절하게 사용해야 한다.

아래는 일반 함수를 적절하게 사용한 예이다.

const user = {
  name: 'baobab',
  normal: function() {
    console.log(this.name);
  }
  // 일반 함수(메소드)는 normal() {} 로 축약하여 사용할 수 있다.
  arrow: () => {
    // 아래와 같은 경우에는 this 가 전역 객체로 정의 된다. 
    // 현재 this가 가리키고 있는 것은 'window'이다.
    // 만약, 굳이 this를 이용하여 name을 출력하고 싶다면 전역 변수(this.name)로 할당해 주면 된다.
    console.log(this.name); 
  }
}
user.normal();    // baobab 
user.arrow();     // undefined 

아래는 화살표 함수를 적절하게 사용한 예이다.

const timer = {
  name: 'baobab',
  timeout: function() {
    setTimeout(() => {      
      console.log(this.name); 
      // 일반 함수는 호출 위치에 따라 setTimeout의 name 속성을 찾는다.
      // setTimeout 함수의 name 속성은 당연히 없으니 undefined가 출력된다.
      // 화살표 함수는 함수 '호출' 위치가 아니라 함수 '선언' 범위를 기준으로 정의 된다.
    }, 2000); 
  }
}
timer.timeout();  // baobab
profile
바오밥 나무가 될테야

0개의 댓글