JavaScript 정리

정우시·2022년 6월 19일
1

1. 프론트엔드 입문

목록 보기
11/13


JavaScript 정리

시작하기 전

컴퓨터의 구성요소

  • 대표적인 컴퓨터의 구성요소에는 하드디스크, 연산(CPU), 메모리가 있다.
  • 우리 컴퓨터에서 문서 파일을 열려면 우선 하드디스크에 저장된 폴더를 선택한다. 그리고 어떤 것을 선택하고 열고 하는 계산을 CPU가 처리를 해서 하드디스크에 있는 문서 파일의 데이터를 메모리 상으로 가지고 오게 되고 마지막으로 그 파일을 열고 처리할 수 있는 어플리케이션을 모니터에 출력한다. 작업물을 수정하면 메모리에 저장되고 저장된 작업물을 종료하면 하드디스크에 다시 저장된다.

메모리

  • 메모리 셀이라고 불리는 각각의 칸 즉, 각각의 저장 장치가 연속으로 이루어진 것이 메모리이다. 각각의 메모리 셀은 1 byte 사이즈로 만들어져있다.
  • 메모리가 부족하면 사용하지 않는 어플리케이션은 하드디스크에 저장해두고 사용하는 어플리케이션의 메모리를 유동적으로 늘리고 줄인다.
  • 내가 가지고 있는 메모리 용량보다 어플리케이션이 더 많은 용량을 요구하면 에러가 발생한다.

메모리 구성

Code: 개발자가 작성한 코드
Data: 어플리케이션에서 전반적으로 필요한 변수 즉, 데이터들을 저장
Stack: 어플리케이션을 실행하는 순서를 보관하는 곳
Heap: 객체를 저장

0. 자바스크립트란?

자바스크립트가 동작하는 과정

  • 브라우저 자체에 내장되어 있는 자바스크립트 엔진(JavaScript Engine)이 필요하다.
  • 자바스크립트 엔진이 동작하는 시간(런타임)에 코드를 한 줄, 한 줄 읽어서 실행을 한다. 그리고 이렇게 하는 것을 인터프리터라고 한다.

※ 인터프리터 vs 컴파일러

컴파일러

  • 보통 다른 프로그래밍 언어(자바 등)에서는 컴파일러가 필요하다.
  • 자바 등을 통해 실행하기전 모든 코드를 컴파일링해서 컴퓨터가 읽을 수 있는 실행 파일을 만든다.
    • (코드 → 컴파일러 → 실행파일 → 출력)
  • 보통 컴파일링을 하는 프로그래밍 언어는 사전에 컴파일링 과정을 거쳐서 실행 파일을 만들기 때문에 컴파일링 과정에서 시간이 오래 걸린다는 단점이 있다.
  • 그러나 한번 실행 파일을 만들어두면 빠르게 실행 할 수 있다는 장점이 있다.
  • 변수나 메모리에 대해 공부를 할 때 컴파일링 과정을 거치면 관련 코드가 정적으로 타입이 된다.

인터프리터

  • 일단 실행을 하고 하나씩 필요할 때마다 한 줄씩 번역을 한다.
  • 인터프리터의 역할은 런타임시 코드가 동작하고 있는 그 당시에 코드를 한줄 씩 번역해서 실행을 해준다.
  • 인터프리터는 실행 전에 컴파일링을 다 하는 과정을 거치지 않고 바로 실행을 하기 때문에 초반 실행하는 속도는 빠르지만 실행하는 당시에 한 줄, 한 줄 번역을 해야 하기에 실행 속도가 느릴 수 있다는 단점이 있다.
  • 물론, 자바스크립트 엔진도 시간이 갈수록 성능이 최적화가 되어서 비교적 빠르게 인터프리터이지만 자바스크립트를 번역해서 실행 할 수 있다.

★ 정리

  • 자바스크립트 코드를 실행하기 위해서는 자바스크립트 엔진이 필요하다.
  • 수많은 브라우저가 있는데 각각의 브라우저들도 엔진을 가지고 있다.

자바스크립트 정의

  • 자바스크립트는 프로그래밍 언어이다.
    • 프로그래밍 언어: 개발자가 정해진 문법으로 특정한 로직을 수행하도록 하는 프로그래밍을 작성할 수 있게 해주는 것으로 어떤 환경에 어떤 일을 수행하냐에 따라서 적절한 프로그래밍 언어를 선택해야 한다.
  • 자바스크립트는 가벼운 스크립트 언어(scripting language)이다.
  • 인터프리터를 이용해서 런타임시 코드를 한 줄, 한 줄 번역해서 바로 실행하는 프로그래밍 언어이다.
  • 일급 함수를 가지고 있는 프로그래밍 언어이다.
  • 웹 페이지를 만드는 거(브라우저 환경) 뿐만 아니라, 브라우저 외부 환경 Node.js 등 자바스크립트 엔진이 있는 모든 곳에 실행할 수 있다.
  • 프로토타입을 베이스로 해서 다양한 스타일의 프로그래밍을 작성할 수 있다.
  • 싱글 스레드에 동적으로 타입이 결정되는 dynamic language라고 한다.

APIs

  • 자바스크립트는 단순 문법이다. 만약 네트워크 통신 또는 무엇인가를 출력하고 싶으면 외부환경(라이브러리)를 사용해야 한다.
  • 또한 Node.js 환경을 이용하고 싶다면 자바스크립트 문법과 더불어 해당 API도 잘 알아야 한다.
  • 자바스크립트 문법 뿐만 아니라 브라우저에서 제공해주는 Web APIs들도 잘 알아야 한다.
    • DOM APIs
    • Network APIs
    • Audio/Video APIs
    • Storage APIs
    • console.log
    • setTimeout
    • fetch

1. 변수 (Variables)

변수는 무엇인가?

  • 값을 저장하는 공간
  • 자료를 저장할 수 있는 이름이 주어진 기억장소

- 변수는 프로그래밍 언어에서 우리가 처리를 해야하는 데이터를 담을 수 있도록 해준다. 따라서 변수를 통해 데이터에 접근하고 업데이트를 할 수 있다.

  • 변수를 만들 때는 let 등의 키워드를 이용한다.
let number = 2;
  • 변수의 이름은 원하는 대로 지정할 수 있다.
let number = 2;
let num = '2';

- 가장 작은 단위의 데이터들을 primitive data type이라고 한다.

// number, string, boolean, null, undefined
  • 변수의 이름을 만들 때는 의미있는 이름을 정하는 것이 좋다. 그래야 정보에 대한 의미를 유추하기 쉽다.
let number = 2; (x) -> let age = 2; (o)
  • 변수를 선언하면 메모리에 해당되는 공간이 생긴다.
let number = 2;
let number2 = number;
console.log(number);
console.log(number2);

---

2
2
  • 기존에 있는 변수 값을 수정할 수 있다. (number에 있는 값이 number2에 복사가 되었기 때문에 number2를 수정해도 number에는 영향을 주지 않는다.)
let number = 2;
let number2 = number;
console.log(number);
console.log(number2);

number2 = 3;

console.log(number);
console.log(number2);

---

2
3

- primitive data type (number, string, boolean, null, undefined) 이외의 것은 object이다.

  • object는 다양한 데이터를 한 군데에 묶어놓은 것이다. (배열, 리스트, 함수 등등)
let obj = {
	name: 'ellie',
    age: 5,
};
  • object를 생성하면 주솟값이 생성된다.
let obj = {
	name: 'ellie',
    age: 5,
};

console.log(obj.name);
  • object도 primitive type처럼 똑같은 변수를 할당할 경우 복사되어서 들어온다. 하지만 primitive type의 경우 그 데이터 자체가 변수에 담겨 있어서 데이터 자체가 복사 되어서 들어오지만 object는 object의 주솟값만 들어온다.
let obj = {
	name: 'ellie',
    age: 5,
};

console.log(obj.name);

let obj2 = obj;
console.log(obj2.name);

---

ellie
ellie
  • 따라서 object는 object안의 데이터를 변경하게 되면 주솟값만 할당된 변수도 데이터가 변경된다.
let obj = {
	name: 'ellie',
    age: 5,
};

console.log(obj.name);

let obj2 = obj;
console.log(obj2.name);

obj.name = 'james';

console.log('obj.name');
console.log('obj2.name');
---

ellie
ellie
james
james

- let은 선언 후에 변경이 가능하지만 const는 변경이 안된다.

  • 다만 object는 const로 만들더라도 주솟값이 잠겨있는 것이기에 값의 수정이 가능하다.
let obj = {
	name: 'ellie',
    age: 5,
};
obj.name = 'James';

console.log('obj.name');

---

james

변수 규칙!

  • 추천: camelCase (likeThis)

null과 undefined 타입

  • null: 비어있다. (타입이 object로 나온다.)
  • undefined: 정해지지 않은 상태 (타입이 undefined로 나온다.)

값과 참조의 차이

  • 원시타입은 값이 복사되어 전달됨
  • 객체타입은 참조값(메모리주소, 레퍼런스)가 복사되어 전달됨

2. 함수

- 함수 정의

  • 반복적으로 계산되는 것을 함수로 만든다. 또한 함수는 재사용이 가능하다.

- 코드 블럭

  • 해당 부분을 코드 블럭이라고 한다.
  • 코드 블럭 자체가 따로 메모리에 저장되어 있다.
  • 함수 이름은 코드 블럭의 주솟값으로 오브젝트처럼 생각하면 된다.
                 {
	return num1 + num2; 
}

- 함수 정의

  • 해당 코드 블럭에 add라는 이름을 붙이고 function이라는 키워드를 통해 함수로 지정한다.
  • 함수 이름은 간결하면서 의미가 있는 이름을 쓴다.
  • 해당 함수는 a와 b라는 것을 받아온다.
  • 타입스크립트의 경우 해당 파라미터에 타입을 지정해서 파라미터의 값을 정확하게 알 수 있지만 자바스크립트 타입이 없기 때문에 유추를 할 수 밖에 없다.
  • 해당 함수 자체에서는 num1과 num2에 어떤 데이터가 들어올지는 모르지만 num1과 num2의 입력값을 더하겠다는 뜻이다.
fuction add(num1, num2) {
	return num1 + num2; 
}

- 함수 호출

  • 입력 변수를 할당하고 console.log를 통해 호출한다.
fuction add(num1, num2) {
	return num1 + num2; 
}

const sum = add.(3, 4);
console.log(sum);
---

7

- 함수를 다른 변수에 할당

  • 오브젝트처럼 생각하면 된다.
fuction add(num1, num2) {
	return num1 + num2; 
}

const doSomething = add;

const result = doSomething(2, 3);
console.log(result);
const result2 = add(2, 3);
console.log(result2);

---

5
5

- 아무런 인자를 받지 않는 함수

  • 아무런 인자를 받지 않는 함수는 인풋을 받지 않는다.
  • 인풋을 받고 싶다면 인자값을 설정한다.
function print() {
	console.log('print');
}

print(8, 33);

---

print

- 콜백함수

  • 현재 surprise는 operator라는 인자를 받아온다.
  • 이 함수는 받아온 operator라는 인자를 실행한다. 실행해서 결괏값을 내부 result에 할당해서 출력한다.
  • 그리고 surprise를 호출하기 위해 add라는 함수를 operator에 전달한다.
  • operator에 전달된 add는 add 함수와 코드 블럭이 같기에 add 함수를 수행한다.
  • operator에 숫자를 전달하면 결괏값이 나온다. 이것은 add를 호출한 것과 같다.
  • 결국 이름을 통해 함수를 호출할 수 있다.
function add(num1, num2) {
	return num1 + num2;
}

function surprise(operator) {
	const result = operator(2, 3);
    console.log(result);
}

surprise(add);

---

5
  • 한번에 나누기도 가능하다.
function add(num1, num2) {
	return num1 + num2;
}

function divide(num1, num2) {
	return num1 / num2;
}

function surprise(operator) {
	const result = operator(2, 3);
    console.log(result);
}

surprise(divide);

---

0.6666666666666666

3. 연산자

- String concatenation

  • 플러스 기호를 이용해서 문자열과 문자열을 합해서 새로운 문자열을 만들 수 있다.
console.log('1' + 2);
  • 문자열에 숫자를 더하게 되면 숫자가 문자열로 변환되어서 합해진다.
console.log('1' + 2);
  • 백틱 기호를 이용해서 string literals를 만들 수 있다. 달러 표시를 이용하면 변수 값을 계산해서 string을 포함해서 문자열을 만들 게 된다.
console.log(`string literals: 1 + 2 = ${1 + 2}`);
  • string literals의 좋은 점은 줄 바꿈을 하거나 중간에 특수 기호인 따옴표를 이용해도 그대로 문자열로 변환되어서 나온다.
console.log(`string literals: 

''''
1 + 2 = ${1 + 2}`);
  • 따옴표로 문자열을 만들 게 되면 중간에 따옴표나 특수기호가 인식이 되지 않는 데 그럴 경우 백슬러시를 이용한다.
console.log('ellie\'s book');
  • 개행을 할 때는 백슬러시 n을 이용하면 된다.
console.log("ellie's \nbook");
  • 백슬러시 t는 탭 키이다.
console.log("ellie's \tbook");

- Nuberic operators

  • add
console.log(1 + 1)
  • substract
console.log(1 - 1)
  • divide
console.log(1 / 1)
  • multiply
console.log(1 * 1)
  • remainder
console.log(1 % 1)
  • exponentiation
console.log(1 ** 1)

- Increment and decrement operators

  • counter라는 변수가 있으면 변수 앞에 ++ 또는 --라는 기호를 앞에 붙여주게 되면 Pre-Increment, 뒤에 ++ 또는 --라는 기호가 있으면 Post-Increment이다.

  • Pre-Increment란 counter에 1을 더해서 counter에 값을 할당하고 나서 preIncrement라는 변수에 다시 할당한다.

let counter = 2;
const preIncrement = ++counter;

// counter = counter + 1;
// preIncrement = counter;
  • Post-Increment란 counter를 postIncrement에 먼저 할당하고 그 뒤에 counter의 값을 1 증가시킨다.
let counter = 2;
const preIncrement = counter++;

// postIncrement = counter;
// counter = counter + 1;
  • 마이너스 기호(--)도 숫자만 감소하는 것으로 플러스 기호(++)랑 똑같다.

- Assignment operators

  • 기본적인 할당 방식이다.
let x = 3;
let y = 6;
  • 기본적인 할당 뿐만 아니라 아래와 같은 방식으로 많이 사용한다.
x += y; // x = x + y;
x -= y;
x *= y;
x /= y;

- Comparison operators

  • less than
console.log(10 < 6);
  • less than or equal
console.log(10 <= 6);
  • greater than
console.log(10 > 6);
  • greater than or equal
console.log(10 >= 6);

- Logical operators: || (or), && (and), ! (not)

  • or 연산자(||)는 하나만 true면 true가 나온다.
  • or 연산자는 처음으로 true가 나오면 멈춘다. 따라서 연산을 많이하는 함수를 호출하거나 expression 같은 것들을 앞에 두게 되면 안된다. 앞에는 심플한 것을 먼저 연산할 수 있게 한다.
const value1 = true;
const value2 = 4 < 2;

console.log(`or: ${value1 || value2 || check()}`);

function check() {
	for (let i = 0; i < 10; i++) {
      // wasting time
      console.log('^_^');
  }
  return true;
}
  • and 연산자(&&)는 모든 조건이 true면 true가 나온다. 따라서 첫 번째 조건이 false면 false가 나온다.
  • and 연산자도 무거운 조건일 경우 뒤에서 체크하는 것이 좋다.
  • 또한 and는 간편하게 null 체크 같은 것도 가능하다.
const value1 = true;
const value2 = 4 < 2;

console.log(`and: ${value1 && value2 && check()}`);

function check() {
	for (let i = 0; i < 10; i++) {
      // wasting time
      console.log('^_^');
  }
  return true;
}
  • not 연산자 (!)는 반대로 출력을 해준다.
const value1 = true;
console.log(!value1);

---

false

- Equality

  • ==의 경우 loose equality로 타입을 변경해서 비교를 한다.
const stringFive = '5';
const numberFive = 5;

console.log(stringFive == numberFive);
console.log(stringFive != numberFive);

---

true
false
  • ===의 경우 strict equality로 타입을 변경해서 비교가 안된다.
const stringFive = '5';
const numberFive = 5;

console.log(stringFive == numberFive);
console.log(stringFive != numberFive);

---

false
true

- Conditional operators: if, else if, else

  • if 연산자를 통해 조건문을 만들 수 있다.
const name = 'ellie';
if (name === 'ellie') {
	console.log('Welcome, Ellie!');
} else if (name === 'coder') {
  console.log('You are amazing coder');
} else {
  console.log('unknown');
}

- Ternary operators: ?

  • condition ? value1 : value2;
  • Ternary operator를 통해 if를 좀 더 간단하게 쓸 수 있다.
  • 해당 조건이 true면 왼쪽이 실행되고 아니면 오른쪽이 실행된다.
  • Ternary operator를 nesting 하는 경우는 코드의 가독성이 떨어지기에 많이 사용하면 안좋다.
  • 많이 써야할 경우 if나 switch를 쓰는 것이 좋다.
const name = 'df';

console.log(name === 'ellie' ? 'yes' : 'no');

- Switch statement

  • if문을 여러개를 사용한다면 switch를 사용하는 것이 좋다.
  • 나중에 타입스크립트에서 정해져 있는 타입을 검사할 때 사용한다.
  • enum 비슷한 것을 검사할 때 사용한다.
const browser = 'IE';
switch (browser) {
  case 'IE':
   console.log('go away!');
   break;
  case 'Chrome':
  case 'Firefox':
   console.log('love you!');
   break;
  default:
   console.log('same all!');
   break;
}

- Loops

  • while 같은 경우는 조건이 맞으면 실행된다. 그래서 false로 나오기 전까지 실행된다.
let i = 3;
while (i > 0) {
	console.log(`while: ${i}`);
    i--;
}

---

while: 3
while: 2
while: 1
  • do while의 경우 코드 블럭을 먼저 실행한 후 조건의 여부를 검사한다.
  • 그래서 코드 블럭을 먼저 실행하고 싶으면 do-while을 사용하고 조건문이 맞을 때만 사용하고 싶으면 while을 사용해야 한다.
let i = 3;
while (i > 0) {
	console.log(`while: ${i}`);
    i--;
}

do {
	console.log(`do while: ${i}`);
    i--;
} while (i > 0);
---

while: 3
while: 2
while: 1
do while: 0
  • for loop의 경우 시작하는 문장, condition이 중간에 오고 어떤 스텝을 밟아 가는 지 명시하게 되어 있다. for(begin; condition; step)
  • begin을 처음에 한번만 호출하고 블럭을 실행하기 전에 condition의 조건 여부를 검사한 후 블럭이 다 실행이 되면 step을 실행하게 된다.
let i = 3;
for (i = 3; i > 0; i--) {
	console.log(`for: ${i}`);
}

---

for: 3
for: 2
for: 1
  • inline variable declaration의 경우 for안에 지역 변수를 선언할 수 있다.
for (let i = 3; i > 0; i--) {
	console.log(`inline variable for: ${i}`);
}

---

inline variable for: 3
inline variable for: 1
  • nested loops의 경우 바깥의 i가 0일 때 안쪽 for문이 0부터 9까지 도는 씩으로 실행된다.
for (let i = 0; i < 10; i++) {
	for (let j = 0; j < 10; j++) {
    	console.log(`i: ${i}, j:${j}`);
    }
}

제어문에서 자주 쓰이는 논리연산자(Logical operator)

  • && 그리고
  • || 또는
  • ! 부정(단항연산자에서 온것)
  • !! 불리언값으로 변환 (단항연산자 응용버전)

4. 클래스, 콜백 함수

- 클래스

  • Class를 하나의 완전체로 만들기 보단, 원하는 기능을 끼워맞추어 재조립이 가능하도록 설계하라.
  • Counter라는 클래스에는 자체적으로 counter라는 변수가 있다. 이 counter는 클래스를 이용해서 오브젝트를 만드는 순간 0으로 초기화가 된다.
  • 클래스 안에는 increase라는 함수가 있는 데 클래스에서 함수를 선언할 때는 function을 작성 안해도 된다.
  • increase는 증가하는 함수로 만들었는 데 increase 함수가 증가할 때마다 counter의 함수를 1씩 증가한다.
class Counter {
	constructor() {
    	this.counter = 0;
    }
    increase() {
    	this.counter++;
        console.log(this.counter);
    }
}
  • 클래스는 다양한 오브젝트를 만들기 위한 청사진이다.
  • coolCounter라는 변수에 클래스를 이용해 오브젝트를 만든다.
  • new라는 키워드를 통해 인스턴스를 만들게 되면 constructor가 실행이 된다. this.counter를 0으로 초기화 한다.
  • coolCounter.increase();를 통해 함수를 호출한다.
class Counter {
	constructor() {
    	this.counter = 0;
    }
    increase() {
    	this.counter++;
        console.log(this.counter);
    }
}

const coolCounter = new Counter();
coolCounter.increase();

- 콜백 함수

  • 콜백 함수를 전달함으로써 원하는 기능을 수행할 수 있다. class Counter 자체는 숫자가 5배가 될 때마다 어떤 동작을 하는 지는 결정되지 않는다.
  • 해당 클래스를 사용하는 사람이 원할 때 해당 기능을 수행할 수 있게 된다.
  • 만약 숫자가 5의 배수마다 특정 키워드 출력하는 것을 원할 경우 콜백 함수를 사용한다.
  • increase가 실행될 때마다 counter가 5배가 되면 this.callback함수를 호출한다.
  • this.callback 함수를 호출할 때 함수안에 있는 (this.counter)라는 데이터를 전달한다.
  • callback은 결국은 printSomething이라는 것을 가리키고 있기에 function printSomething이 수행이 된다.
  • this.callback && this.callback(this.counter);라는 함수는 this.callback의 undefinded의 여부를 확인해준다.
class Counter {
	constructor(runEveryFiveTimes) {
    	this.counter = 0;
        this.callback = runEveryFiveTimes;
    }
    increase() {
    	this.counter++;
        console.log(this.counter);
        if (this.counter % 5 === 0) {
        	this.callback && this.callback(this.counter);
        }
    }
}

function printSomething(num) {
	console.log(`Wow! ${num}`);
}

const coolCounter = new Counter(printSomething);
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
---

1
2
3
4
5
Wow! 5

출처
드림코딩 - 자바스크립트 기초 1. 변수
드림코딩 - 자바스크립트 기초 2. 함수
드림코딩 - 자바스크립트 4. 코딩의 기본 operator, if, for loop 코드리뷰 팁
드림코딩 - 자바스크립트 기초 4. 클래스

profile
프론트엔드 공부하고 있는 정우시입니다.

0개의 댓글