IT world

[JavaScript] 24.02.02 JavaScript에 대해서 본문

모두의 연구소(오름캠프)/AI 모델 활용 백엔드 개발 과정

[JavaScript] 24.02.02 JavaScript에 대해서

엄킹 2024. 2. 2. 12:49

JavaScript

자바스크립트는 ‘웹페이지에 생동감을 불어넣기 위해’ 만들어진 프로그래밍 언어로 해당 언어를 사용하여 정적이던 웹을 동적인 웹으로 만들 수 있게 되었다. 즉 HTML 페이지를 동적으로 만들어 주는 것이다.

 

왜 자바스크립트인가?

자바스크립트의 원래 명칭은 ‘모카’(Mocha)에서 ‘라이브 스크립트’(LiveScript)로 변경되었다가 최종적으로 ‘자바스크립트’(JavaScript)가 되었습니다. 라이브스크립트가 출시 될때 쯤, 당시에 인기있던 언어중에 ‘자바’ 가 있었는데 이 인기를 이용하고자 이름만 빌려와 자바스크립트가 되었습니다.

  • HTML : 웹페이지의 구조를 만들어준다. (마크업 언어)
  • CSS : 웹페이지에 디자인을 입혀준다. (스타일 규칙 언어)
  • JavaScript : 웹페이지가 동적으로 움직이도록 만들어준다. (스크립트 언어)

자바스크립트는 웹을 위한 인터프리터 언어이자 객체기반의 스크립트 프로그래밍 언어이다. HTML의 특정 요소들을 선택하여 다양한 이벤트에 따라 어떤 동작을 하도록 기능을 넣을 수 있고 발생하는 이벤트에 따라 HTML, CSS를 조작할 수 있다. 

 

장점

  • 컴파일과정이 필요없다 > 빠른 시간 안에 스크립트 코드를 작성할 수 있다.
  • 다른언어들에 비해 단순한 구조와 원칙을 갖고 있어 배우기 쉽다.
  • 웹에 특화된 기술이기 때문에 운영체제나 플랫폼에 상관없이 잘 작동되고 확장성이 높다.

단점

  • OS에 직접 접근할 수 없다.
  • 하드디스크를 읽거나 쓸 수 없다.
  • 다른 프로그램을 호출할 수 없다.
  • 자바스크립트는 도메인이 동일한 두 탭/윈도우를 제외하고 탭/윈도우 간에 통신을 수행할 수 없다.
  • 자바스크립트는 웹 브라우저에서 실행되기 때문에 일부 보안상의 제약이 있으며, 브라우저에서 웹 페이지를 열 때 안전하고 위험에 처하지 않도록 보장해야 한다.
  • 일반적으로 자바스크립트는 자체 도메인에 대해서만 제한없이 네트워크 요청을 보낼 수 있다.

변수

변수란? 변할 수 있는 수, 변할 수 있는 정보라는 뜻으로 프로그램을 만들때는 필요한 숫자나 문자와 같은 데이터를 보관할 공간을 의미한다. 변수는 선언하고, 할당하고, 사용할 수 있으며 변수는 '변할 수 있는 수'이므로 const를 제외하고 지정된 값을 계속 바꿀 수 있다.

[변수 값 할당]

 

변수명을 정할 때

  • 변수이름은 $, _ 를 제외한 공백, 특수문자, 구두점(글의 여러 가지 경계를 구분하기 위해 사용되는 반점(,), 온점(.), 물음표(?) 등등…)을 사용할 수 없다.
  • 첫 글자는 숫자가 될 수 없다.
  • 대소문자를 구별한다.
  • 예약어가 쓰일 수 없다. (예: let, const, function ..)
  • 유니코드 문자도 사용할 수 있다. 그러나 실무에는 보통 영어를 사용.

변수의 특징

var, let 두 가지 키워드는 변수를, const 키워드는 변경할 수 없는 수 즉, 상수를 의미

let과 const는 블록-레벨 선언으로 불리며, 선언된 코드 블록 밖에서 접근할 수 없다.

특히 const의 경우에는 재정의가 불가능한 특징을 가지고 있다. const 의 경우에는 반드시 초기화가 필요하다.

[예시] (let은 초기화 안해도 되고 const는 초기화를 해줘야함)

let helle → 가능, 그 후 재할당 가능

const hello → 불가능 / 반드시 초기화 필요 : const hello = "hello" 그 후 hello = "hello2" 로 재할당 불가능

const에는 변하면 안되는 값을 사용해야할 때 많이 사용한다 → ex) 주민번호 ..

 

let 과 const 언제 사용할까?

자바스크립트에서 let과 const는 모두 변수를 선언하는 키워드이지만 서로 다른 용도를 가지고 있다.

 let  은 재할당이 가능한 변수를 선언할때 사용하며 변수의 값이 언제든지 변경될 수 있다는 것을 의미한다.

 const  는 재할당이 불가능한 상수를 선언할때 사용하며 변수의 값이 한번 할당되면 변경될 수 없다는 것을 의미한다.

 

const를 사용하면 의도하지 않은 값의 변경을 방지할 수 있어 코드의 예측가능성을 높이고 버그를 줄일 수 있고, 반드시 초기화를 해야하기 때문에 어떤 데이터가 사용되는지 초기에 확인할 수 있어 가독성을 높이고 유지 보수를 향상 시킨다.

 

그러나 변수의 가리키는 값이 반드시 변경되어야 하는 경우에는 let을 사용한다. 

const values = []; // 1번

values.push(10); // 2번

 

values의 변수에 배열이란 객체를 할당했고, 그 이후에 10의 값을 추가했다. 과연 에러일까...?

정답은 에러가 아니다!

 

values는 배열의 주소를 참조하고 있다. 즉 배열의 주소를 변수에 할당했고 배열이 실제 가리키고 있는 공간에서 추가, 삭제에 대한 내용은 신경쓰지 않는다. const로 이미 할당된 배열의 주소를 변경할 수는 없지만 배열의 주소값이 변경되지 않는다면 배열에 값을 추가하고 삭제하는 것은 얼마든지 가능하다는 얘기다.


함수

반복적으로 필요한 코드를 하나의 덩어리로 묶어서 필요할 때마다 호출하여 사용하는 것이다.

함수는 아래와 같은 이유로 사용한다.

  1. 재사용성이 높아진다.
  2. 유지보수가 용이하다.
  3. 구조 파악이 용이하다.
// 함수 구조
function 함수이름(parameter1, parameter2...) { // 함수의 선언
    // 실행코드...
    return 반환값
}

함수이름(argument1, argument2...) // 함수의 호출

[함수 구조]

용어 번역 의미
Parameter 매개변수 함수와 메서드에 입력 변수 이름
Argument 인자, 인수 함수와 메서드에 실제 입력되는

 

표의 내용처럼 용어를 구분해야한다. (파선아실 → 파라미터는 선언, 아규먼트는 실제값)

파라미터는  함수에서 받는, 아규먼트는 함수로 보내는 값, 아규먼트는 인자라고도 하고 파라미터는 매개변수라고 한다.

함수 내에서는 return을 통해 반환되는 값을 전달하고, 함수 내부에서 return 구문을 만나게 되면 해당 함수는 종료된다.

 

자바스크립트는 함수에 전달되는 아규먼트 즉 인자는 매개변수보다 적거나 많아도 에러가 발생하지 않는다.

즉  함수 선언했을 때 매개변수의 개수와 함수 호출 시 인자의 개수가 달라도 매개변수의 순서대로 값을 전달한다.

function 함수1 (a, b, c){
    return a + b + c
}

// 필요 이상의 아규먼트를 넣었을 때
함수1(10, 20, 30, 40) // Error를 뿜지 않습니다. 60

// 필요 이하의 아규먼트를 넣었을 때
함수1(10, 20)

 

함수 선언문과 함수 표현식

함수는 function + 제목 + ( ) + { } 의 조합인 구문(Statement)으로 선언할 수도 있고, 제목 없이 선언하여 값으로 할당하는 표현식(Expression)으로 선언이 가능.

함수의 선언식과 표현식은 다른것! 선언식은 정해진 문법이고 표현식은 값으로 평가될 수 있는 것을 의미. 즉 위에 표현식의 함수가 값인것.

// 함수 선언문
function sum(x, y){
  return x + y;
}

// 함수 표현식 - 익명함수
let sumXY = function(x, y){
  return x + y;
};
console.log(sum(10, 20));
console.log(sumXY(10, 20));

 

※ 호이스팅(Hoisting)

호이스팅이란 사전적 정의로 끌어올린다는 의미로 변수 및 함수 선언을 각 유효 범위의 최상단으로 끌어 올려주는 JS의 독특한 특징이다.

자바스크립트에는 호이스팅이라는 성질이 있다. 무언가를 끌어올리는 의미로 변수나 함수의 선언 같은 것을 위로 끌어올린다. 실제로 코드가 끌어올려지는 것은 아니다! 자바스크립트는 컴파일 단계에서 코드 실행 전 전체 코드의 함수와 변수를 스캔하고 모든 함수와 변수들은 렉시컬 환경이라 불리는 자바스크립트 데이터 구조 내의 메모리에 추가된다. 즉 실행 전 자바스크립트는 우선 전체 코드를 확인하고 함수나 변수가 선언되기 전에 해당 함수/변수를 호출했더라도 해당 함수와 변수가 선언되었다는 것을 알기 때문에 에러를 출력하지 않는다. 즉 변수 선언 전에 해당 변수를 출력하는 코드가 있더라도 뒤에 선언되었단 것을 알고 있기에 에러가 출력되지 않는다. 예를 들어 console.log(helllo) 그 후 var hello = 'hello' 처럼 변수 선언하기 전에 변수 값을 출력해도 에러가 아니라는 것이고 이런 현상을 아래 있는 변수가 위로 끌려 올라오는 것처럼 보여서 호이스팅이라고 부른다. (절대로 밑에 선언된 변수가 위로 끌어올려지는 것이 아니다!)

 

선언식은 호이스팅이 적용되고 표현식은 호이스팅이 적용이 안된다. 호이스팅 때문에 선언과 실행이 꼬일 수 있고, 이러한 현상을 줄이기 위해 표현식을 사용한다. let과 const를 사용하면 호이스팅 현상이 발생하지 않고 변수 선언 전 호출 시 에러를 출력한다.

 

화살표 함수(람다식)는 function 키워드를 화살표 기호로 대체하여 표현한 방식이다.

 


조건문과 반복문

1. 조건문

조건에 따라 실행되는 코드로, 조건식이 참(Truthy)인 값이나 거짓(Falsy)인 값을 반환하는지에 따라 코드를 수행할지 말지 판단.

→ NaN, null, '', undefined: 거짓(Falsy)인 값 

 

if-else 문

조건에 따라 실행되는 조건문.

let score = 69;
let money = 1000;

if (score > 90){
  document.write('참 잘했습니다!<br>');
  money += 100000
} else if (score > 80){
  document.write('잘했습니다!<br>');
  money += 10000
} else if (score > 70){
  document.write('했습니다!<br>');
  money += 1000
} else {
  money = 0
}

document.write(money);

 

삼항 연산자

삼항연산자는 if-else 문을 간단하게 표현하는 방법.

// 조건식 ? 조건식이 참일 때 실행될 코드 : 조건식이 거짓일 때 실행될 코드

let item = true ? console.log('true') : console.log('false');
console.log(item);

 

switch 문

switch case 문은 하나의 변수를 여러 값과 비교하여 실행 코드를 결정하는 조건문.

switch (표현식) {
  case 값1:
    // 값1에 대한 실행 코드
    break;
  case 값2:
    // 값2에 대한 실행 코드
    break;
  ...
  default:
    // 모든 case에 해당하지 않을 때 실행될 코드
    break;
}

 

switch 문은 표현식의 값과 case의 값이 일치하는 경우에만 실행 코드가 실행됨을 케이스별로 명확히 구분하고 있어서 if 문에 비해 가독성이 좋다.

 

2. 반복문

단순한 작업을 여러번 반복해야 할때 사용하는것.

 

for 문

변수를 선언하는 초기화식과, 결과(true or false)에 따라 실행문의 실행 여부를 판단하는 조건식, 실행문 이후 변수의 증감을 나타내는 증감식으로 구성되어 있다.

for(초기화식; 조건식; 증감식) {
	실행문;
}

 

while 문

주어진 조건식이 참일 때 반복적으로 실행되는 반복문.

조건식은 Truthy 또는 Falsy값을 반환하는 표현식이다. 만약 조건식이 Truthy를 반환하면 중괄호 안의 코드가 반복적으로 실행되며, 조건식이 falsy 값을 반환하는 순간 반복이 종료한다.

while (조건식) {
  // 조건식이 참일 때 실행될 코드
}

타입(Type)

타입이란, 자료형을 의미한다. 변수의 타입은 다양한 데이터를 용도에 맞게 쓰기 위해 사용한다. 

 

1. 원시 타입

단순한 데이터를 저장하는 것으로, 값 자체가 변경 불가능하며 값을 변수에 저장하거나 전달할 때 값에 의한 전달을 한다는 것이다. 원시 값을 다른 변수에 할당 할때는 값의 참조가 아닌 값 자체(가리키고 있는 값을 따라가서 실제 메모리에 저장된 주소)가 복사되어 저장된다.

 

원시타입은 값이 절대 변하지 않는 불변성의 특징을 갖고 있다. number, string, boolean, null, undefined이 해당하며 해당 값을 변수가 직접적으로 가리키는 형태로, 값이 복사될 때 독립적인 값을 가지게 된다. 재할당 시 기존 값이 변하는 것처럼 보일지 몰라도 사실 새로운 메모리에 재할당한 값이 저장되고 변수가 가리키는 메모리가 달라진 것이다.

 

자바스크립트에서 원시타입을 선언하면 스택(stack)에 저장된다. (스택은 LIFO(Last In First Out)구조를 가진 자료구조)

let a = 100
a = 50

 

예를 들어 위 코드의 경우 a란 변수에 100이란 값을 할당하고 50의 값을 재할당했다. 초기화가 진행될 때 메모리에 Number타입의 100이란 값이 생성되고 식별자 a 메모리에 생성된 100의 메모리 주소를 가리키게 된다. 그 후 재할당을 하면 메모리에 생성된 100이란 값이 50으로 수정되는 것이 아닌 새로운 Number타입의 50이란 값을 새로운 메모리에 생성하고 a가 가리키던 메모리가 바뀌는 것이다. 즉 메모리에는 100과 50의 값이 모두 존재하며 원시타입은 불변성을 갖고 있기 때문에 기존에 메모리에 생성된 값들은 그 자체가 변경될 수 없다. 변수와 연결 되어있는 메모리가 바뀌는 것!

 

let a = 100;
let b = a;
a = 50;

위의 예시는 원시 타입의 값이 복사 될때의 코드이다. 새로운 변수 b에 a를 할당하게 되면 변수 b의 공간에는 a의 값을 통째로, 값 그 자체로 복사하여 변수의 메모리에 담게 된다. 그렇기에 a가 재할당 되더라도 b는 전혀 영향을 받지 않는다.

2. 참조 타입

객체로서 저장되는 것으로, 값을 변수에 저장할 때 값 자체가 아닌 값의 위치가 저장된다. 따라서 객체 값을 다른 변수에 할당할 때는 값 자체가 복사되는 것이 아니라 값의 참조(위치)가 저장된다. 

 

참조타입은 객체(object)로 치환되며, 그렇기에 메서드(method)를 가진다. array, function, object가 대표적이며 원시타입과 큰 차이점은 변수의 크기가 동적으로 변한다는 것이다. 이러한 특징 때문에 Object의 데이터 자체는 별도의 메모리공간(heap)에 저장되며, 변수에 할당 시 데이터에 대한 주소(힙(heap) 메모리의 주소값)가 저장되기 때문에 변수가 가지고 있는 메모리 주소를 이용해서 변수의 값에 접근하게 되는 것이다.

 

만약 let myArray = []라는 배열을 생성하면 위와 같이 메모리 주소가 저장된다. 원시타입의 값들은  직접 저장되었지만 myArray(참조타입)는 Heap 메모리의 주소값이 저장된다. 즉 객체를 선언 및 할당하면 해당 객체는 힙에 저장되고 그 메모리 주소는 스택에 저장된다.

 

let myArr = [];
let copyArr = myArr;

myArr.push("hello");

위의 코드는 myArr라는 객체를 생성했고 copyArr를 선언 후 myArr를 할당했다. 그렇다면 힙에 새로운 객체가 생성될까? 

정답은 생기지 않는다. 해당 객체가 이미 힙에 존재하는 한 myArr와 copyArr는 같은 객체를 가리키게 된다.

위의 예제를 보면 참조 타입의 변수는 실제 데이터가 저장된 주소를 참조하기에 참조타입이라고 불리는 것이다. 그렇기에 변수의 복사나 수정 시 참조 여부를 잘 고려야해야한다. 만일 이러한 특성을 고려하지 않은 채 객체나 배열에 수정 및 복사를 하게 되면 예상치 못한 방향으로 변경될 수 있다.(둘은 같은 객체를 바라보고 있기에 변경된 내용이 두곳에 동일하게 표현됨)

 

배열(Array)

배열이란 데이터를 순서대로 저장하는 객체. 여러개의 데이터를 한 변수에 저장할 수 있기 때문에 데이터를 추가하거나 제거, 정렬, 검색 등 다양한 작업이 가능하다.

// 배열 생성 예시
const arr = [];
const arr1 = [1, 2, 3];
const arr2 = new Array(4, 5, 6);
const arr3 = new Array(3);

// 배열 안의 원소에 접근하기 위해서는 인덱스 번호를 이용합니다. 
const arr = [1, 2, 3];

console.log(arr[0]); // 1
console.log(arr[1]); // 2
console.log(arr[2]); // 3
console.log(arr[3]); // 접근가능..

 

메소드

  • length() : 배열의 원소 개수 출력
  • push() : 배열의 끝에 요소를 추가
  • pop() : 배열의 마지막 요소를 꺼냄(꺼낸 요소는 배열에서 제외)
  • shift() : 배열에서 첫번째 요소를 꺼내고 반환
  • unshift() : 배열의 첫번째 요소로 새로운 요소를 추가
  • splice() : 배열의 요소를 추가, 제거 또는 교체 → 첫번째 인자는 삭제나 추가를 시작할 인덱스번호, 두번째 인자는 삭제할 요소의 개수, 세번째 인자는 추가할 요소를 작성한다. 추가할 요소가 없다면 생략가능(이때는 삭제만 실시)
  • slice() : 배열에서 요소들을 추출하여 새로운 배열로 반환하는 메서드 첫번째 인자는 추출을 시작할 인덱스, 두번째 인자는 추출을 끝낼 인덱스. 두번째 인자에서 바로 이전의 요소까지 추출한다. 두번째 인자는 생략 가능하며, 배열의 길이보다 큰 값을 전달하면 배열의 끝까지 추출. 
  • sort() : 배열의 요소를 정렬 → 자바스크립트에서 정렬 방식은 원소를 문자열로 전환한 후에 정렬하기 때문에 숫자형 데이터를 정렬하기 위해서는 비교함수를 사용한다.
  • forEach() : 배열의 각 요소에 대해 주어진 함수를 실행. 함수의 인자로는 배열 요소, 인덱스를 받을 수 있다. 
  • map() : 배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 새로운 배열로 반환
  • filter() : 기존 배열에서 특정 조건을 만족하는 요소들만 추출하여 새로운 배열을 만든다.
  • includes() : 요소가 포함되어 있다면 true 아니면 false를 출력
// 정렬 시 숫자형 데이터 비교함수 사용 코드
const num3 = [13, 9, 10];

num3.sort(function (a, b) {
  console.log('a: ' + a, 'b: ' + b);
  return a - b;
});

// foreach 예시
const arr = ['참외', '키위', '감귤'];
arr.forEach(function(item, index) {
  console.log(item, index);
	arr[index] = index;
});

// 결과
// 참외 0
// 키위 1
// 감귤 2

// map 예시
// foreach와 실행은 동일하지만 map은 새로운 배열을 반환한다.
const arr = [1, 2, 3];
const newArr = arr.map(function(item, index) {
  return item * index;
});

console.log(newArr);

 

객체(Object)

객체는 배열처럼 여러개의 데이터를 한 변수에 저장할 수 있는 자료형이다. 차이점은 배열은 인덱스 번호를 사용하여 값에 접근했지만, 객체는 특별한 키(key)를 통해 값(value)에 접근 할 수 있는 키-값 쌍으로 이루어져 있다.

중괄호 {} 를 사용하여 생성하고 key-value의 쌍으로 이루어져 있으며 key와 value는 콜론(:)으로 구분한다. 이러한 키 값 쌍을 합쳐서 프로퍼티(properties)라고 표현하며 만약 프로퍼티 값이 함수인 경우에는 메소드라고 부른다.

const babaYaga = {
  name: "John Wick",
  age: 53,
  from: "벨라루스",
	askingHim: function(){ // function 키워드는 생략 가능
		console.log("Yeah, I'm thinking I'm back!");
	}
};

// 객체 속성값 호출 방법
console.log(`${babaYaga.name} from ${babaYaga.from}`);
console.log(`${babaYaga['name']} from ${babaYaga['from']}`);

 

새로운 속성을 추가하기 위해서는 객체 이름 뒤에 점(.)과 새로운 속성이름을 입력하고 새로운 값을 할당

// 새로운 속성 추가
babaYaga.job = "Killer";

// 속성 삭제
delete babaYaga.job;

// 속성이 존재하는지 확인
console.log('age' in babaYaga);
console.log('mercy' in babaYaga);

 

객체의 메서드

  • hasOwnProperty() : 특정 프로퍼티를 가지고 있는지 불리언 값으로 반환
  • for..in : 객체의 반복을 통해 객체 안의 프로퍼티들에 접근하여 어떤 키와 값을 가지고 있는지 확인 in 앞의 값은 매번 반복할 때마다 다른 속성이름이 변수로 지정. for..in 문 안에서 처리되는 프로퍼티들은 반드시 순서대로 반복하지 않는다
  • key(), values() : Object.keys() 메소드는 객체의 속성 이름(key)들을, Object.values() 메소드는 객체의 속성 값(value)들을 배열로 반환. 객체에 입력한 순서대로 출력하지 않는다.

 

Comments