JavaScript

Seung min, Yoo·2021년 4월 5일
0
post-thumbnail

1.javascript란?

  1. 스크립트 언어이다.
  2. 자바와 관련이 없다.
  3. 스크립트 언어는 어플리케이션에서 코드를 해석하고 실행할 수 있는 엔진이 존재하여 스크립트로 해당 어플리케이션을 제어하기 위해서 사용된다.
  4. 인터프린터 언어다(소스코드를 한줄 씩 읽으면서 읽으면서 바로 해석하는 것)
  5. 동적으로 바꾸는 것이라고 쉽게 생각할 수 있다.

2. runtime

스크립트 언어인 자바스크립트가 사용되는 runtime환경은 여러가지가 있다.
1. 각종 웹브라우저
2. 서버로 활용되는 Node.js나 Eletron등이 있다.


3. Expression

값을 만들어내는 간단한 코드를 '표현식'이라고 한다.

1.true

ture라는 표현식은 true라는 값을 만들어 내는데 이런 것을 표현식이라고 한다.

💡
1.24라고 하면 24라는 결과값이 나온다. 이 뿐만 아니라 1000+900+90+9라고 입력했을 경우 1999라는 값이 나온다.
2. anna->anna, hellow+world->hellowworld와 같은 문자열도 표현식이라고 한다.
3. 표현식은 값을 만들어 내기 때문에 함수의 인자로 사용할 수 있다.

2. alert
💡
1. alert('1000+900+90+9'); -> 1999라는 경고창같은 것이 나온다.
2. alert('hellow' + 'world'); -> hellowworld라는 경고창 같은 것이 나온다.

4.statement

  • 하나 혹은 여러 개의 표현식이 모여 문장을 이룬다.
  • 모든 표현식은 문장이 될 수 있다.
  • (보통)문장의 끝에는 세미콜론을 붙인다.

💡여기서 문장이란?
1. 24; -> 24, true;->true
2. 1000+900+90+9; -> 1999
3. "anna"; -> anna, "hellow" + "world";

💡plus
var name = "mark";와 같은 것도 문자로 볼 수 있다.
alert('');도 마찬가지이다.

  • 한 줄에 문장이 하나인 경우에는 세미 콜론을 붙이지 않아도 문제가 없다. 하지만 관례상 붙인다.
  • 한 줄에 여러 문장을 적을 경우, 세미 콜론으로 문장을 구분해야 한다.
  • 마지막 문장은 세미 콜론을 붙이지 않아도 문제가 없다.
  • 마지막 문장의 결과가 반환된다.
    EX) true; 26; 1000+900+90+9 = 1999와 한 줄에 여러 문장을 적을 경우 마지막에 세미콜론을 붙이지 않아도 되고, 마지막 문장이 반환되는 것을 알 수 있다.
  • 조건문(if)과 반복문(for)의 경우도 문장이다. 이 경우 마지막 }뒤에 세미콜론을 붙이지 않는다.

5. keywords

  • 자바스크립트에서 특정한 목적을 위해 사용하는 단어
  • 이러한 키워드 들은 예약어로 지정되어 있다.
    EX)
var name = 'mark'; // var라는 단어는 변수를 선언할 때 사용하는 키워드이다.

6. reserved word

프로그램을 작성할 때, 변수명, 학수명 등 이름으로 사용할 수 없는 단어

EX)

var return = '변수명'; //return은 예약어라 변수명으로 사용할 수 없다.
function for() {} //for는 예약어라 함수명으로 사용할 수 없다.

7. reserved keyword

이미 특정한 목적을 위해 사용하기 때문에 사용할 수 없는 예약어

//예약어의 종류
break
case
catch
continue
default
delete
do
else
finally
for
function
if
in
instanceof
new
return
switch
this
throw
try
typeof
var
void
while
with

8. future reserved keywords

앞으로 특정한 목적을 위해 사용할 가능성이 있어서 사용할 수 없는 예약어

abstract
boolean
byte
char
class
const
debugger
double
enum
export
extends
final
float
goto
implement
import
int
interface
long
native
package
private
protected
public
short
static
super
syncronized
throws
transient
volatile

9.identifier(식별자)

코드 내의 변수,함수 혹은 속성을 식별하는 문자열

EX)

var name = 'mark';
function hellow() {}
var person = {name: 'mark', age: 37};

💡함수의 이름, 변수의 이름, person이라는 것도 name과 age라는 property가 있고 각각 식별자 이기 때문에 대소문자를 구분한다.

식별자

대소문자를 구분한다.
EX)

var myName = '';
var myname = '';

두 개는 대소문자로 구분 되어있기 때문에 에러가 나지 않는 것이다.

유니코드문자

$, _, 숫자(0~9)를 사용할 수 있지만, 숫자로 시작할 수 는 없다.
'예약어'는 사용할 수 없고, '공백문자'도 사용할 수 없다.

EX)

var name1;
var $name;
var _name;
var 1name; //숫자로 시작할 수는 없다.
var 이름; //가능하지만 영문을 사용하는 것을 추천

10.comments(주석)

  1. 한줄만 주석을 하고 싶다면 //를 붙이면 된다.
  2. 여러줄을 주석으로 하고 싶다면/**/를 이용하면 된다.

11.변수와 상수

변수는 variable, 상수는 constant라고 하며 보관소 역할을 하는 것을 변수와 상수라고 한다.

const

const는 상수를 지칭하는 이름으로 상수를 선언하는 것이다.

💡상수를 선언하면서 바로 값을 할당하는 방법

const 상수를 지칭하는 이름 =;

let
💡변수를 선언하는 방법

let 변수를 지칭하는 이름;

💡이미 선언된 변수에 다른 값을 할당하는 방법

let 변수를 지칭하는 이름 =;

💡주의할 점

선언과 동시에 값을 할당하거나 이미 선언된 변수에 값을 할당하는 것은 가능하나 선언이 안된 변수에는 값을 할당할 수 없다.


12. 변수의 유효범위

const, let의 유효범위는 블록스코프라는 범위를 갖는다. 여기서 블록이라는 말은{}를 의미한다.

EX)

//블록
{
const name ='mark';
 console.log(name);
}
//위는 블록 안에서 선언해 준것이고 블록 안에서는 문제없이 변수의 값이 할당되어 나오는 것을 확인가능

//밖에서 안으로
let age =37;
{
	age++;
  console.log(age);
}

console.log(age);
// age가 선언된 영역에서는 사용하는데 문제가 없다는 것을 알 수 있다.


//중첩
{
  {
    {
    	console.log(age);
    }
  }
}
//위의 결과 또한 바깥에 있는 let age =37;의 결과값이 나오지만 만약 중첩된 블록안에서 다른 선언이 있었다면 그 선언에 대한 값이 반환된다.

1. 값을 선언하는 방식 변수와 상수

1. 변수

let value = 1;
console.log(value);

여기서 바뀔 수 있는 값을 '변수'라고 한다.
1. 한번 선언하게 되면 똑같은 이름으로 선언할 수 없다.
2. 다른 블록 범위 내에서는 다른 이름으로 선언이 가능하다.

2. 상수

상수는 const 라는 선언을 이용하다.
1. 한번 값을 설정하고 나면 바꾸지 못한다.
2. 마찬가지로 선언을 중복해서 사용할 수 없다.

const a = 1;
a = 2; // 여기에서 오류가 뜨게 된다. 'a is readonly'

💡또다른 키워드 Var

var a = 1;
  1. var과 let은 비슷하다. var의 사용은 권장하지 않는다.
  2. var과 let의 주요 차이는 var은 여러번 사용할 수 있다.

✍️ const와 let는 Internet Explore9, 10같은 구형브라우저에서는 const,let을 사용할 수 없다.
하지만 바벨이라는 것을 통해서 우리가 작성한 최신 자바스크랩트 문법이 구형 브라우저에서도 돌아갈 수 있게 변환할 수 있다.

데이터타입

변수나 상수를 선언할 때 숫자 외에도 다른 값을 선언할 수 있다. 예로 문자열, 불리언등이 있다.
+) 문자열을 사용할 때 ''""둘다 사용해도 상관없다.

1) 문자열은 말 그대로 문자를 쓸 때 이용한다.
2) 불리언은 '참 혹은 거짓'만을 나타내는 표현하는 값이다.
3) null, undefined: 둘다 '없다'라는 뜻이지만 서로 역할이 서로 조금 다르다.

💡null과 undefined의 차이

null의 경우 값이 '없다'는 것이고, undefined는 '아직 정해지지 않았다'라는 것이다.


2. 연산자- 산술연산자, 대입연산자

1. 산술연산자

사칙연산을 실행하는 연산자

let a = 1+2;
console.log(a);

결과

3

또한 계산기에서 계산하는 것과 같은 연산도 가능하다.

++를 붙이는 연산

EX1)

let a = 1;
a++;
console.log(a);

결과

2

EX2)

let a = 1;
console.log(a++);
console.log(a);
console.log(++a);

결과

1
2
3

EX2.2) 뺄셈에 대한 예

let a =1;
console.log(a--);
console.log(a);

결과

1
0

대입연산자
EX1)

let a = 1;
a += 1;	//a에 1을 더하겠다는 것을 의미한다.
console.log(a);

결과

2

Ex2)

let a = 1;
a += 3;
a -= 3;
a *= 3;
a /= 3;

3. 논리연산자

EX)

// NOT = !
const a = !true;
console.log(a);
//또는
const a = !false
console.log(a);


// and = &&
const a = true && true;
console.log(a);
// case 1
const a = false && true;
console.log(a);
// case 2
const a = true && false;
console.log(a);
//case 3
const a = false && false;
console.log(a);


// or = ||
const a = true || true;
console.log(a);
//case 1
const a = true || false;
console.log(a);
//case 2
const a = false || true;
console.log(a);
//case 3
const a = false || false;
console.log(a);

결과

// NOT = ! 즉, !는 특정 불리언을 반전시켜준다.
false
// 또는
true

// and = &&
true
// case1
false
//case2
false
//case 3
false				// 즉 둘 중 하나라도 false라면 결과는 false가 된다.


// or = ||
true
//case1
true
//case2
true
//case3
false			//즉 둘 중 하나라도 true라면 true가 나온다.

💡사칙연산에서 계산 순서에 따른 규칙이 있듯이, 'not, and, or'도 순서가 있다.
우선순위는 not, and, or 순으로 된다.

EX)

const value = !(true && false || true && false || !false);
console.log(value);

결과

false

💡계산되게 되는 과정

const value = !(true && false || true && false || !false);
//!(true && false || true && false || true)
//!(false || false || true)
//!(false || true)
//!(true)
// false 가 결과가 된다.

4. 비교연산자, 문자열 붙이기

비교연산자
1)

const a = 1;
const b = 1;
const equals = a === b;
console.log(equals);

이 결과는 true라고 나온다.

비교연산자를 사용할때 =====를 사용한다.
여기서 =====는 같은 결과가 나오지만 차이가 조금 있다.
==의 경우 타입을 검사하지 않기 때문에 실제로는 값이 다르지만 결과는 같다고 나온다.
그리므로 ===을 사용하는 것이 더 정확한 방법이라고 할 수 있다.

2)

const a = 'a';
const b = 'b';
const notEquals = a !== b;
console.log(notEquals);

결과

true

여기서 살펴보면 우리가 not!으로 설정한다는 것을 알기 때문에 !==는 '같지 않다'라는 비교연산자라는 것을 알 수 있다.

크고 작음을 비교하는 연산자

const a = 10;
const b = 15;
const c = 15;

//1
console.log(a < b);
//2
console.log(b > a);
//3 같거나 작다
console.log(b >= a);
//4
console.log(a <= c);
//5
console.log(b < c);

결과

//1
true
//2
true
//3
true
//4
true
//5
false

문자열 붙이기

const a = '안녕';
const b = '하세요';

console.log(a + b);

결과

안녕하세요

5. 조건문

if문(가장 기본적인 조건문)

const a = 1;
if (a + 1 === 2) {
	console.log('a + 1이 2입니다.');
} // 여기서 만약 참이라면 'a + 1이 2입니다.'라는 구문이 실행되고 거짓이라면 실행되지 않는다.

결과

a + 12입니다.

블록범위에 따른 선언이 달라지는 방식

const a = 1;
if(a + 1 === 2) {
	const a = 2;		
    console.log('if문 안의 a 값은 ' + a);
}
console.log('if문 밖의 a 값은' + a);

결과

if문 안의 a값은 2
if문 밖의 a값은 1

위에서 보다싶이 let과 const는 블록범위에 따라서 다르게 선언할 수 있다는 것의 예제가 된다.

💡그렇다면 var은?

var a = 1;
if (a + 1 === 2) {
	var a = 2;
  	console.log('if문 안의 a 값은' + a);
}
console.log('if문 밖의 값은' + a);

결과

if문 안의 a값은 2
if문 밖의 a값은 2

이와 같은 결과 때문에 var을 쓰게 되면 실수할 경우가 많이지기 때문에 조심해야 한다.

if else문

'어떤 특정 조건이 만족했을 때 이것을 하고 만족하지 않았을 경우 이것을 해라'와 같다.

EX)

const a = 10;
if (a > 15) {
	console.log('a가 15보다 큽니다.');
} else {
	console.log('a가 15보다 크지 않습니다.');
}

결과

a가 15보다 크지 않습니다.

if else if 구문

if구문을 여러번 사용하는 것과 같은데, 다른 조건에 따라 다른 조건이 나타나도록 할 수 있다.

const a = 10;

if (a === 5) {
	console.log('5입니다!');
} else if (a === 10) {
	console.log('10입니다!');
} else {
	console.log('5도 아니고 10도 아닙니다.');
}

결과

10 입니다!

여기서 else if를 여러번 써줄 수 있다.

또 다른 조건문 switch case

특정 값이 무엇이냐에 따라 다른 작업을 하고 싶을 때 사용할 수 있다.

const device = 'iphone';

switch (device) {
  case 'iphone' : 
    console.log('아이폰!');
    break;
  case 'ipad' : 
    console.log('아이패드!');
    break;
  case 'galaxy note' : 
    console.log('갤럭시노트!');
    break;
    default : 
    console.log('모르겠네요..');
}

결과

아이폰!

여기서 default는 여기서 모두 해당하지 않았을 경우의 값을 설정해주는 것이다.


6. 함수

EX)

const a = 1;
const b = 2;
const sum = a + b // 와 같은 작업을 함수로 만들어 보자
//함수
function add(a, b) {
	return a + b;
}
const sum = add(1, 2);
console.log(sum);

결과

3

EX2)

function hello(name) {
	console.log('hello,' + name + '!');
}
hello('Sim');

결과

hello, Sim!

함수 - template literal
💡여기서 잠깐 es6란?

'ECMAScript 6'를 의미하며, 자바스크립트를 의미한다.

EX) es6의 문법중 하나인 template literal의 예제

function hello (name) {
	console.log(`hellow ${name}!`);
}
hello('sim');

EX2)

function hello (name) {
	return `Hello ${name}!`;
}
const result = hello('sim');
console.log(result);

함수연습

1)getGade(이 함수는 스코어 0~100까지 가져와서 등급으로 형태로 변환하는 함수)

function getGrade (score) {
	if (score === 100) {
    	return 'A+';
    }else if(score >= 90) {
    	return 'A';
    }else if(score === 89) {
    	return 'B+';
    }else if (score >= 80) {
    	return 'B';
    }else if (score === 79) {
    	return 'C+'; 
    }else if (score >= 70) {
    	return 'C';
    }else if (score === 69) {
    	return 'D+';
    }else if (score >= 60) {
    	return 'D';
    }else {
    	return 'F';
    }
}

const grade = getGrade(100);
console.log(grade);
//const grade = getGrade(~~); 여기서 '~~'에 따라서 등급이 달라진다.

2) 화살표 함수
EX1)

const add = (a, b)/*parameter*/=> {
	return a + b;
}
const sum = add(1, 2);
console.log(sum);
//결과는 아까 봤듯이 '3'이 나온다.

EX1.1) EX1을 더 간단히 작성하는 방법도 있다.

const add = (a, b) => a + b;
const sum = add(1, 2);
console.log(sum);
// 이 결과 또한 '3'이 나온다.

EX2)

const hello = (name) => {
	console.log(`Hello, ${name}!`);
}

hello('Sim');

7. 객체

EX1)

const ironMan = {
	name: '토니 스타크',
	actor: '로버트 다우니 주니어',
  	alias: '아이언맨',
};
const captinAmerica = {
	name : '스티븐로저스',
  	actor : '크리스 에반스',
  	alias : '캡틴아메리카'
};

console.log(ironMan);
console.log(captinAmerica);

EX2) 함수의 파라미터에서 객체를 받아오는 방법

const ironMan = {
	name: '토니 스타크',
	actor: '로버트 다우니 주니어',
  	alias: '아이언맨',
};
const captinAmerica = {
	name : '스티븐로저스',
  	actor : '크리스 에반스',
  	alias : '캡틴아메리카'
};

function print(hero) {
	const text = `${hero.alias}(${hero.name})역할을 맡은 배우는 ${hero.actor}입니다.`;
  	console.log(text);
}
print(ironMan);
print(captinAmerica);

결과

아이언맨(토니스타크) 역할을 맡은 배우는 로버트 다우니 주니어 입니다.
캡틴 아메리카(스티븐로저스) 역할을 맡은 배우는 크리스 에반스 입니다.

객체- 비구조화 할당

'객체 구조분해'라고 불리기도 한다. 객체에서 특정 값을 추출해 내는 것이다.

const ironMan = {
	name: '토니 스타크',
	actor: '로버트 다우니 주니어',
  	alias: '아이언맨',
};
const captinAmerica = {
	name : '스티븐로저스',
  	actor : '크리스 에반스',
  	alias : '캡틴아메리카'
};

function print(hero) {
  	const { alias, name, actor } = hero;
	const text = `${alias}(${name})역할을 맡은 배우는 ${actor}입니다.`;
  	console.log(text);
}
print(ironMan);
print(captinAmerica);
//결과는 위와 똑같다.

EX2) 파라미터에서 비구조화 할당을 하는 방법

const ironMan = {
	name: '토니 스타크',
	actor: '로버트 다우니 주니어',
  	alias: '아이언맨',
};
const captinAmerica = {
	name : '스티븐로저스',
  	actor : '크리스 에반스',
  	alias : '캡틴아메리카'
};

function print({alias, name, actor}) {
	const text = `${alias}(${name})역할을 맡은 배우는 ${actor}입니다.`;
  	console.log(text);
}
print(ironMan);
print(captinAmerica);

비구조화 할당은 꼭 함수 내부에 쓸 필요는 없다.아래와 같이 선언해 줄 수도 있다.

const {name} = ironMan;
console.log(name);

객체- 객체 안에 함수 넣기

const dog = {
	name : '멍멍이',
  	sound : '멍멍',
  	say: function say () {
  		console.log(this.sound); //여기서 this는 함수가 위치한 객체 '자기자신'을 의미한다.
    },
  
};

EX2)화살표 함수에서의 this가 안되는 이유에 대한 예시

const dog = {
	name: '멍멍이',
  	sound '멍멍',
  	say: function() {
    	console.log(this.sound);
    }
};

const cat = {
	name: '야옹이',
  	sound: '야옹',
};

cat.say = dog.say;
dog.say();
cat.say();

const catSay = cat.say;
catSay();

결과

멍멍
야옹
undefined error

함수에 있는 this는 자기가 속해 있는 곳을 가르키게 되고, 화살표함수를 이용하게 되면 화살표 함수내부에서는 this가 뭔지 모른다. 그리고 위의 'say: function' 함수를 바깥으로 꺼내게 되면 this와의 관계가 사라지게 된다.

객체 - getter와 setter함수

EX1)

const numbers = {
	a: 1,
    b: 2
};

numbers.a = 5;
console.log(numbers.a); // 이 결과 5가 나온다.
console.log(numbers); // object{a:5, b:2}가 나온다.

EX2) getter 함수 만들기 예제

const numbers = {
	a: 1,
  	b: 2,
  	get sum () {
  		console.log('sum함수가 실행됩니다.');
    	return this.a + this.b;
    }
};

console.log(numbers.sum); // 조회만 했을 뿐인데 결과로 'sum함수를 실행합니다! 3'이라고 나온다.
number.b = 5;
console.log(numbers.sum); // 결과'sum함수가 실행됩니다! 6'

getter함수는 특정 값을 조회하려고 할 때 특정 코드를 실행시키고 연산된 값을 받아서 사용하는 것을 의미하게 된다.

EX2)setter함수

const dog = {
	_name: '멍멍이',
  	set name(value) {
      	console.log('이름이 바뀝니다...' + value)
    	this._name = value;
    }
};

console.log(dog._name); // 결과 '멍멍이'가 나온다.
dog.name = '뭉뭉이';
console.log(dog._name);// 결과 '이름이 바뀝니다.. 뭉뭉이 뭉뭉이'가 나온다

EX3) getter와 setter을 이용한 또다른 예시

const numbers = {
	_a: 1,
  	_b: 2,
  sum: 3,
  calculate() {
  	console.log('calculate');
    this.sum = this._a + this._b;
  },
  get a() {
  	return this._a;
  },
  get b() {
  	return this._b;
  },
  set a(value) {
  	this._a =value;
    this.calculate();
  },
  set b(value) {
  	this._b = value;
    this._calculate();
  }
};

console.log(nubers.sum); // 결과 '3'이 된다.
numbers.a = 5; // 결과 'calculate'가 나온다.
numbers.b = 7; // 결과 'calculate'가 나온다.
numbers.a = 9; // 결과 'calculate'가 나온다.

8. 배열

객체는 한 변수나 상수에 여러가지 정보를 담기 위함이라면 여러개의 항목이 들어있는 리스트라고 보면 된다.

EX1)

const array = [1, 2, 3, 4]; //배열을 이용할 때는 대괄호를 사용한다. 그 안에 넣고 싶은 원소를 넣는다.
console.log(array);

결과

[1, 2, 3, 4]

여기서 원소로 다 넣을 수 있는데, 숫자나 문자열 또는 객체열 등등을 넣을 수 있다.

EX2)

const array = [1, 'blabla', {}, 4];
console.log(array[n]); // 여기에서 n의 값에 숫자를 넣음으로써 그 값이 달라진다. 그 시작은 '0'부터 시작이다.

결과

//1) n=0
1
//2) n=1
blabla
//3) n=2
object {}
//4) n=3
4
//5) n=4
//n=4번째는 위에 보면 원소의 갯수에 맞게 세어보면 없기 때문에 결과값이 안나온다.
undefined

EX3)

const object = [
  {name: 'Mike'}, //배열안의 원소끼리 구분을 할 때에는 ','를 사용한다.
  {name: 'Susan'}
];
console.log(objects);
console.log(objects[0]);
console.log(objects[1]);

결과

[object, object]
object{name: 'Mike'}
object{name: 'Susan'}

💡배열 내장함수 push(배열에 새로운 항목을 추가 하고 싶다면)를 사용해라

const objects [
  {name: 'Mike'},
  {name: 'Susan'}
];

objects.push({
	name: 'Simon'
});

console.log(objects);

결과

[object, object, object]// 이 이후에 클릭으로 어떤 항목이 있는지 볼 수 있는데 2: object에 Simon 이라고 추가된 것을 볼 수 있다.

✍️배열의 크기를 알아내는 방법 (크기란 배열안에 객체가 몇 개 있는지 알아보는 것이다)으로 length를 사용한다.

const objects [
  {name: 'Mike'},
  {name: 'Susan'}
];
console.log(objects.length); // 첫번째

objects.push({
	name: 'Simon'
});
console.log(objects.length); // 두번째

결과

2
3

여기서 눈여겨 볼 것은 위와 같이 첫번째에서 찍게 되면 2개라고 나오고, 만약에 push를 한 후에 length를 보면 3개가 나오기 때문에 결과가 저렇게 나온다는 것을 알고 있어야 한다.

💡정리
1. 배열안에 배열 등등 여러가지 넣을 수 있다.
2. push로 새로운 원소를 밖에서 넣을 수 있다.
3. length를 가지고 객체의 크기를 알 수 있다.
4.console.log(객체이름[n])을 통해서 몇번째의 배열의 값을 지정알아볼 수 있다.


9.반복문

1. for구문
EX1)

for (let i = 0; i <= 10; i++) {
	console.log(i);
}

결과

0
1
2
3
4
5
6
7
8
9

'10'까지 가게 되면 조건에 의해서 false가 됨으로 반복을 멈추게 된다.

EX2) 숫자가 올라가는 것 말고 내려가는 것으로 만드는 방법

for (let i = 10; i > 0; i--){
 console.log(i);
}

EX3) 만약 짝수로 내려오는 방법을 하고 싶다면?

for (let i = 10; i > 0; i-=2) {
	console.log(i);
}

EX4) for문과 배열을 함께 사용하는 방법

const names = ['Mike', 'Susan', 'Simon'];

for(let i = 0; i < names.length; i++) {
	console.log(names[1]);
}

결과

Mike
Susan
Simon

2. 또다른 반복구문 while
Ex1) while문에서는 잘 안쓰지만 for구문과 같이 만드는 기본적인 예시

//while문의 경우 내부에서 값을 선언해주지만 while은 밖에서 선언해준다
let i = 0;
while (i < 10;)	{			//조건을 바로 넣어준다.
  	console.log(i);
	i++			//i의 변화에 대한 조건을 여기서 설정해준다
}	

결과

0
1
2
3
4
5
6
7
8
9

Ex2)while문은 숫자의 비교가 아니라 조금 더 까다로운 조건을 다룰 때 주로 사용한다.

let i = 0;
let isFun = false;

while (isFun === false) { 	//여기서 isFun이 false인 것이 조건이기 때문에(!isFun)이라고 작성해도 같은 결과값이 나온다.
  	console.log(i);
	i++
  	if (i === 30) {
    	isFun = true;
    }
  	
}

결과

0
1
2
3
...
29

3. 또 다른 반복문 for of, for in

주로 배열을 다룰 때 이용하게 된다.

for of

Ex1) 기본적인 예시

const numbers = [10, 20, 30, 40, 50];
for(let numers of numbers) {
	console.log(numbers);
}

결과

10
20
30
40
50

Ex2) 객체의 정보를 변형적으로 받아올 수 있는 방법들

const doggy = {
	name: '멍멍이',
  	sound: '멍멍'
  	age: 2
};
//1.만약 여기서 배열의 key값들을 받아오고 싶다면(key값이란 name, sound, age를 가르킨다.)
console.log(Object.keys(doggy));
//2.key값으로 우리가 정해준 '멍멍이, 멍멍, 2'라는 값을 가지고 오고 싶다면 아래와 같이 하면 된다.
console.log(Object.values(doggy));
//3. key랑 value값을 같이 보고 싶다면
console.log(Object.entries(doggy));

결과

//1.
["name", "sound", "age"]
//2.
["멍멍이", "멍멍", 2]
//3.
[array[2], array[2], array[2]]// 이와 같이 나오게 되고 클릭으로 key와 value값을 같이 볼 수 있다.

for in
Ex1)

const doggy = {
	name: '멍멍이',
  	sound: '멍멍'
  	age: 2
};

for (let key in doggy) {
	console.log(`${key}: ${doggy[key]}`);
}

결과

name : 멍멍이
sound : 멍멍
age: 2

✍️ 템플릿 리터럴

문자열을 조합하기 위해 더 쉬운 문법이 존재한다.
기본 함수는 단순히 해당 부분을 단일 문자열로 연결시켜주는 것이다.
1. 사용법

console.log(`hello ${매개변수의 값}!`); //매개변수의 값에는 변수, 숫자, true같은 것들

break, continue

break, continue는 반복문에서 사용하며, 반복문을 벗어나거나 다음 조건문을 반복하는데 사용한다.
if문 뿐만 아니라 while, for of, for in에서도 사용할 수 있다.

for (let 1 = 0; i < 10; 1++) {
  	if (i === 2) continue;	//continue은 특정 조건을 만족하면, 그 다음 루프를 이어가라는 것이다.
	console.log(i);
  	if( i === 5) break; //if 문 내부에서 실행할 함수가 하나라면 `{}`생략하고 쓸 수 있다.
}	// break라고 하면 조건을 만족할 경우 조건문을 끝내고 바깥으로 나온다고 보면 된다. 

결과

0
1
3
4
5

10. 배열 내장함수

foreach

배열 안에 있는 원소를 가지고 어떤 작업을 일괄적으로 하고 싶다면 foreach문을 사용하면 된다.

const superheros = [
'Mike',
'Susan'
'Simon'
];

function print(hero) {
	console.log(hero);
}

names.forEach(print);
//더 깔끔하게 작성하는 방법
const superheros = [
'Mike',
'Susan'
'Simon'
];

superheros.forEach(function(hero) {
	console.log(hero);
});

//위의 함수를 화살표 함수로 쓰는 방법
superheros.forEach(hero => {
	console.log(hero);
});

map

배열안의 원소를 변환하고 싶을 때 사용한다.

Ex1) 모든 원소에 제곱해서 나타내는 함수.

const array = [1,2,3,4,5,6,7,8];

const squared = [];
for(let i = 0; i < array.length; i++) {
	squared.push(array[i] * array[i]);
}

console.log(squared);

결과

[1, 4, 9, 25, 36, 49, 64]

💡for문 대신에 foreach문을 사용하는 경우

const array = [1,2,3,4,5,6,7,8,];

const squared = [];
array.forEach(n => {
	squared.push(n * n);
});

console.log(squared);

EX2) 더 깔끔하게

const array = [1,2,3,4,5,6,7,8];

const square = n => n * n;
const squared = array.map(square);

console.log(squared);

EX3) 위를 또 더 깔끔하게

const array = [1,2,3,4,5,6,7,8];

const squared = array.map(n => n * n;);

console.log(squared);

위 모든 예시의 결과값은 다 똑같다.

Ex4) 응용한 다른 예시 (객체배열들을 텍스트로만 이루어진 텍스트 배열로 바꾸는 응용)

const items = [
  {
  	id: 1,
    text: 'hellow'
  },
  {
  	id: 2,
    text: 'bye' 
  }
];

const text = items.map(item => item.text);
console.log(texts);

결과

["hellwo","bye"]

배열들 중에서 원하는 항목이 어디있는지 알려주는 함수
1) index of

const superheroes = ['Mike', 'Susan', 'Simon'];
const index = superheros.indexOf('Simon');
console.log(index);

결과

2

2) index of 와 비슷한 함수인 find index 함수

만약에 안에 들어있는 값들이 객체이거나 특정조건으로 찾는다면 index of로는 할 수 없다.

const todos = [
  {
  id: 1,
  text: '자바스크립트 입문',
  done: true,
  },
  {
  id: 2,
  text: '함수배우기',
  done: true,
  },
    {
  id: 3,
  text: '객체와 배열 배우기',
  done:true,
  },
    {
  id: 4,
  text: '배열 내장함수 배우기',
  done:false,
  },
];

const index = todos.findIndex(todo => todo.id === 3)
console.log(index);

결과

2

Findof와 비슷한 find함수

find index처럼 찾은 값 자체를 반환하는 함수.

const todos = [
  {
  id: 1,
  text: '자바스크립트 입문',
  done: true,
  },
  {
  id: 2,
  text: '함수배우기',
  done: true,
  },
    {
  id: 3,
  text: '객체와 배열 배우기',
  done:true,
  },
    {
  id: 4,
  text: '배열 내장함수 배우기',
  done:false,
  },
];

const todo = todos.find(todo => todo.done === false)
console.log(todo);

결과

Object {id : 4, text: '배열 내장함수 배우기', done: false}

filter함수

특정 조건을 만족하는 원소들을 찾아서 원소들을 가지고 새로운 배열을 만드는것

const todos = [
  {
  id: 1,
  text: '자바스크립트 입문',
  done: true,
  },
  {
  id: 2,
  text: '함수배우기',
  done: true,
  },
    {
  id: 3,
  text: '객체와 배열 배우기',
  done:true,
  },
    {
  id: 4,
  text: '배열 내장함수 배우기',
  done:false,
  },
];

const tasksNotDone = todos.filter(todo => todo.done === false);
console.log(tasksNotDone);

결과

[Object] //마우스로 그 안의 객체도 찾아볼 수 있다.

splice 와 slice

1)splice

splice는 배열에서 특정 항목을 제거할 때 사용하며, 제거하는 과정에서 해당 원소가 몇 번인지 명시해야 한다.

const number = [10, 20, 30, 40];
const index = numbers.indexOf(30);
numbers.splice(index, n); // n에서 들어가는 숫자에 따라서 'index부터 몇개를 지우겠다'라고 하는 것이다.
console.log(numbers);

결과

//n=1
10, 20, 40
//n=2
10, 20

💡여기서 splice된 요소를 보고 싶다면?

const number = [10, 20, 30, 40];
const index = numbers.indexOf(30);
const spliced = numbers.splice(index, 2);
console.log(spliced);
console.log(numbers);

결과

[30, 40]
[10, 20]

2) slice

slice는 배열을 잘라낼 때 쓰는데 splice와 차이점은 기존의 배열을 건드리지 않는다는 것과 파라미터에 넣는 것도 달라진다

const numbers = [10, 20, 30, 40];

const sliced = numbers.slice(0, 2);// (n, m)은 n은 자르기 시작하는 곳이고 m은 어디까지 자르는지에 대한 것이다.
console.log(sliced);
console.log(numbers);

결과

[10, 20]
[10, 20, 30, 40]

shift, pop, unshift, push

1) shift

shift는 첫 번째 배열에서 원소를 추출해준다.
shift는 기존의 배열을 수정하게 된다.

const number = [10, 20, 30, 40];

const value = numbers.shift();
console.log(value);
console.log(numbers);

결과

10
[20, 30, 40]

2) pop

shift랑 은근히 비슷하다. shift가 왼쪽 끝에서부터 원소를 빼면 pop은 오른쪽 끝에서부터 원소를 뺀다.

const number = [10, 20, 30, 40];
const value = numbers.pop();
console.log(value);
console.log(numbers);

결과

40
[10, 20, 30]

3) unshift

unshift는 배열에 원소를 추가하는 것이다.

const number = [10, 20, 30, 40];
number.unshift(5);
console.log(numbers);

결과

[5, 10, 20, 30, 40]

4) push

unshift와 비슷하지만 다른 점은 unshift는 맨 왼쪽에 추가하고 push는 맨 오른쪽에 추가하는 것이다.

const number = [10, 20, 30, 40];
numbers.push(50);
const 
console.log(numbers);

결과

[10, 20, 30, 40, 50]

💡추가로

여기서 알아야 할 것은 위의 네 가지 함수들은 배열 자체을 바꿔버리게 된다는 것을 알아야 한다.

concat

concat은 여러개의 배열을 하나로 합쳐주는 작업을 한다.
concat은 기존의 배열을 바꾸지 않는다.

const arr1 = [1,2,3];
const arr2 = [4,5,6];

const concated = arr1.concat(arr2);
console.log(concated);
//또 다른 표현법
const arr1 = [1,2,3];
const arr2 = [4,5,6];

const concated = [...arr1, ...arr2];
console.log(concated);

결과

[1,2,3,4,5,6]

✍️스프레드 연산자라는 것도 있지만 이 이후에 배워보자.

join

join은 밑의 결과와 같이 쉼표 사이사이에 배열의 원소를 넣어서 하나의 문자열을 만들어 준다.

const array = [1,2,3,4,5];

console.log(array.join());
console.log(array.join(' ')); // 원소 사이에 공백을 넣어준다.
console.log(array.join(', ')); // 원소 사이에 쉼표를 넣지만 쉼표 뒤에 공백이 하나 들어간다.

결과

1,2,3,4,5

reduce

배열이 주워졌을 때 배열 안에 있는 모든 값을 사용하여 어떤 값을 연산해야 할 때 사용한다.

const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((accumulator, current) => accumulator + current, 0)
console.log(sum);
// accumulator라는 것은 누적된 값을 나타낸다,  0 은 초기값을 나타낸다, current란 배열의 원소들이 차례로 들어가는 곳이다.

결과

15

Ex2) 배열의 평균을 구할 수 있으며 그것에 대한 예시

const numbers = [1, 2, 3, 4, 5];

const avg = numbers.reduce((accumulator, current, index, array) => {
	if (index === array.length -1) {
    	return(accumulator + current) / array.length;
    }
  return accumulator + current ;
}, 0)
console.log(avg);
// index는 그 각 원소가 몇번째 아이템인지 알려준다. array는 함수를 실행하는 자기 자신을 의미한다.
3

reduce의 다른 예시

reduce는 꼭 숫자 계산이 아니더라도 사용할 수 있다

const alphabets = ['a', 'a', 'a', 'b', 'c', 'c', 'd', 'e'];
const counts = alphabets.reduce((acc, current) => {
	if (acc[current]) {
    	acc[current] += 1;
    }else {
    	acc[current] = 1;
    }
  return acc;
}, {})

console.log(counts);

결과
~~~javascript
Object {a: 3, b: 1, c:2, d:1, e:1}

11. 프로토타입과 클래스

객체 생성자라는 것에 대해서 먼저 알아보자. 객체생성자란 함수를 통해서 새로운 객체를 생성하고 그리고 그 안에 넣고 싶은 값이나 함수를 생성하게 해준다.

1. 객체생성자

// 객체 생성자를 만들때에는 대문자로 입력한다(Animal).
// this는 객체를 생성하게 되고 그 객체를 의미하게 된다.
// 객체 생성자를 이용하여 새로운 객체를 만들 때에는 'new'라는 키워드를 사용한다.
function Animal (type, name, sound) { 
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = function () {
  	console.log(this.sound);
  }
}

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '고양이', '야옹' );

dog.say();
cat.say();

결과

멍멍
야옹

2. 프로토타입

프로토타입의 역할은 객체 생성자로 무언가를 만들었을 때, 그걸로 만든 객체들 끼리 공유할 수 있는 어떠한 값이나 함수를 자바스크립트의 객체 생성자로 만든 함수에다가 프로토타입으로 설정해줄 수 있는 것이다.

Ex)

function Animal (type, name, sound) { 
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = function () {
  	console.log(this.sound);
  }
}

Animal.prototype.say = function () {
	console.log(this.sound);
}

Animal.prototype.shaedvalue = 1;

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '고양이', '야옹' );

dog.sharedvalue
cat.sharedvalue

dog.say();
cat.say();

3. 객체 생성자 상속하기

객체 생성자를 상속받는 다는 것은

EX1) Animal이라는 것을 상속받지 않는다면 어떻게 표현해야 하는지에 대한 예시

function Dog (name, sound) {
	this.type = '개';
  	this.name = name;
  	this.sound = sound;
}

function Cat (name, sound) {
	this.type = '고양이';
  	this.name = name;
  	this.sound = sound;
}

Dog.prototype.say = function () {
	console.log(this.sound);
}
Cog.prototype.say = function () {
	console.log(this.sound);
}
//이렇게 하면 두 번이나 작성해야 하기 때문에 불필요하며, 상속을 이용한다.

EX2) 상속을 이용하는 방법

function Animal (type, name, sound) {
	this.type = type;
  	this.name = name;
  	this.sound = sound;
}

Animal.prototype.say = function () {
	console.log(this.sound);
}
//여기서 최대한 animal이 가지고 있는것을 재사용하는 방법
function Dog (name. sound) {
	Animal.call(this, '개', name, sound );
}
function Cat (name. sound) {
	Animal.call(this, '고양이', name, sound );
}

Dog.prototype = Animal.prototype;
Cat.prototype = Animal.prototype;

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '고양이', '야옹' );

dog.sharedvalue
cat.sharedvalue

dog.say();
cat.say();

결과

멍멍
야옹

4. Es6 class

//constructor: 생성자라는 의미를 가지고 있다.
class Animal {
	constructor(type, name, sound) {
    	this.type = type;
      	this.name = name;
      	this.sound = sound;
    }
  say () {
  	console.log(this.sound);
  }
}

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '고양이', '야옹');

dog.say();
cat.say();

결과

멍멍
야옹

EX)상속에 대한 예시

class Animal {
	constructor(type, name, sound) {
    	this.type = type;
      	this.name = name;
      	this.sound = sound;
    }
  say () {
  	console.log(this.sound);
  }
}

class Dog extends Animal { // 여기서 'extends가 특정 클래스를 상속받는다'라는 의미를 가지고 있다.
	constructor(name, sound) {
    	super('개', name, sound); 		//여기서 super는 자신이 상속받은 class의 constructor를 호출하는 것이다.
    }
}

class Cat extends Animal {
	constructor(name, sound) {
    	super('고양이', name, sound);
    }
}

const dog = new Dog('멍멍이', '멍멍');
const cat = new Cat('고양이', '야옹');

dog.say();
cat.say();

결과

멍멍
야옹

12. 삼항연산자

작성방법
condition ? true : false
꼭 불린값이 아닌 문자열 등등 가능하다.

Ex1) if구문을 이용한 삼항연산자와 같은 예시

const array = [];
let text = '';
if (array.length === 0) {
	text = '배열이 비어있습니다.';
} else {
	text = '배열이 비어있지 않습니다';
}
console.log(text);

Ex2) 삼항연산자를 이용한 예시

const array = [1, 2];
let text = array.length === 0 
? '배열이 비어있습니다.'
: '배열이 비어있지 않습니다.';

console.log(text);

EX3) 삼항연산자의 중첩

const condition1 = false;
const condition2 = false;

const value = condition1
? '와우!'
: condition2  
 ?'blabla'
 : 'foo'

console.log(value);
//이런경우는 헷갈릴 수 있음으로 삼항연산자를 중첩하기 보다는 if문을 쓰는 것이 나을 수도 있다.

결과

foo

13. Truthy 와 Falsy

Ex1)

function print(person) {
	console.log(person.name);
}

const person = {
	name = 'Simon'
};

print(person);

결과

Simon

falsy

Falsy한 값이라는 것은 false로 나타내지는 값을 말한다.

종류

console.log(!undefined);
console.log(!null);
console.log(!0);
console.log(!'');
console.log(!NaN); 		//NaN : not a number의 준말로 숫자가 아니라는 것이다. 그 예시로 const value = 1 / 'asdf'; console.log(value);	라고 하면 NaN이 나온다.
console.log(!false);

truthy

위의 종류를 제외하고는 전부 truthy한 값이다.

종류

console.log(!3);
console.log(1'hello');
console.log(!['array']);
console.log(![]);
console.log(!{});

Ex2) '!'를 붙이지 않고 사용하는 방법

const value = {a : 1};
if (value) {
	console.log('value가 Truthy 하네요.');
} 

14. 단축 평가 논리 계산법

논리 연산자를 이용해서 코드를 더 짧게 사용하는 것을 말한다.

Ex1) 기본적인 불리언

true && true // true
true && false // false
true || false // true
false || true // true

Ex2) and연산자

console.log(true && 'hello');
console.log(false && 'hello');
console.log('hello' && 'bye');
console.log(null && 'hello');
console.log(undefined && 'hello');
console.log('' && 'hello');
console.log(0 && 'hello');
console.log(1 && 'hello');
console.log(1 && 1);

결과

hello
false
bye
null
undefined
""
0
hello
1

Ex3) or 연산자

const namelessDog = {
	name : '',
};

function getName(animal) {
	const name = animal && animal.name;
  	return name || '이름이 없는 동물입니다.';
}

const name = getName(namelessDog);
console.log(name); 

결과

이름이 없는 동물입니다.

15. 함수의 기본 파라미터

함수를 호출하게 될 때 넣어야 할 파라미터를 안넣었을 때 기본값으로 사용할 값을 지정하는 것을 말한다.

function calculateCircleArea(r) {
	return : Math.PI * r * r;
}

const area = calculateCircleArea(4);
console.log(area);
//만약에 const area에서 파라미터를 4로 넣었지만 넣어주지 않는다면 NaN이 나온다.

결과

50.xxxxxx

16. 비구조화 할당(구조분해)

객체를 배울때도 잠깐 사용했었다.

const object = { a : 1, b : 2 };
const { a, b } = object;
console.log(a);
console.log(b);
//또한 비구조화 할당은 함수의 파라미터에서도 사용할 수 있다.
const object = {a : 1, b : 2 };

function print ({ a, b}) {		//파라미터에서 만약 b를 지워버리면 undefined가 나온다.
	console.log(a);
  	console.log(b);
}
print(object);
// or 연산자를 사용하는 방법
const object = {a : 1};

function print ({ a, b}) {		//파라미터에서 만약 b를 지워버리면 undefined가 나온다.
	console.log(a);
  	console.log(b || 2);
}
//or연산자 말고 더 일반적인 방법은
const object = {a : 1};

function print ({ a, b = 2}) {		//파라미터에서 만약 b를 지워버리면 undefined가 나온다.
	console.log(a);
  	console.log(b);
}
//좀더 제대로 된 방법
const object = {a : 1};

const {a, b = 2} = object; // 비구조화할당할 때 기본값을 설정할 때 '='를 사용하면 된다.
console.log(a);
console.log(b);

결과

1
2
//
1
2
//
1
2
//
1
2
//
1
2

Ex2) 비구조화 할당을 할 때 이름을 바꾸는 방법

const animal = {
	name: '멍멍이',
  	type: '개'
};

const nickname = animal.name; // 여기서 설정해 준 것이 이제부터 animal.name을 nickname으로 부르고 싶다고 설정해 놓은 것이다.
//만약 위의 것을 비구조화 할당으로 하고 싶다면?
const { name : nickname } = animal;

console.log(nickname);
console.log(aniaml);		//이 결과에서 보면 알 수 있듯이 기존의 animal이 가지고 있던 값이 없어지는 것은 아니다. 그대로 유지되고 있다.

결과

멍멍이
object {name: "멍멍이", type: "개" } // 여기서 console.log(animal);에 대한 답을 얻을 수 있다.

Ex3) 배열 비구조화 할당이라는 것에 대한 예시

const array = [1, 2];

const one = array[0];
const two = array[1];

console.log(one);
console.log(two);
//위 같은 상황을 이렇게 할 수 있다.
const array = [1, 2];

const [one, two] = array;

console.log(one);
console.log(two);
//값은 똑같은 또다른 비구조화 할당
const array = [1];

const [one, two = 2] = array;

console.log(one);
console.log(two);

결과

1
2
//
1
2

Ex4)객체의 깊숙한 곳에 있는 값을 꺼내는 방법

const deepObject = {
	state: {
    	information: {
        	name: 'Simon',
          	languages: ['korean', 'english', 'chineese']
        }
    },
  value: 5
}

//name, languages, value값을 바깥으로 꺼내는 방법 1.비구조화 할당문법을 두 번 사용하는것
const [name, languages] = deepObject.state.information;
const [value] = deepObject;

const extracted = {
	name, 
  	languages, 
  	value
};
console.log(extracted);
//또 다른 방법으로 비구조화 할당을 한번 하면서 여러 값을 다 빼오는 것
const deepObject = {
	state: {
    	information: {
        	name: 'Simon',
          	languages: ['korean', 'english', 'chineese']
        }
    },
  value: 5
}

const {
	state : {
    	information: {
        	name, languages
        }
    },
  value
} = deepObject;

const extracted = {
	name, 
  	languages, 
  	value
};
console.log(extracted);



17. spread와 rest.

spread와 rest 이 문법은 '...'을 사용한다.

spread

이 문법을 사용하면 객체혹은 배열을 펼칠 수 있다.
Ex1)

const slime = {
	name: '슬라임'
};

const cuteSlime = {
name: '슬라임'
attribute: 'cute'
};

const purpleCuteSlime = {
name: '슬라임'
attribute: 'cute'
color: 'purple'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

결과
~~~javascript
object {name:  "슬라임"}
object {name: "슬라임", attribute: "cute"}
objcet {name: "슬라임", attribute: "cute", color: "purple"}

EX2)그렇다면 이렇게 기존에 만들었던 객체를 참고해서 새로운 객체를 만들고 싶다면? spread를 이용

const slime = {
	name: '슬라임'
};

const cuteSlime = {
	...slime,
  	attribute: 'cute'
};

const purpleCuteSlime = {
	...cuteSlime,
  	color: 'purple'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

결과

object {name:  "슬라임"}
object {name: "슬라임", attribute: "cute"}
objcet {name: "슬라임", attribute: "cute", color: "purple"}

위와 같은 결과를 보여준다. 즉, '...객체를 선언명'을 해준다면 위에 우리가 이미 선언했던 객체의 속성을 가지고 오게 되는 것이다.

Ex3) 만약에 스프래드 연산자를 이용하지 않고, 아래와 방식과 같이 하게 된다면 다른 결과가 나온다.

const slime = {
	name: '슬라임'
};

const cuteSlime = slime;
cuteSlime.attribute = 'cute';

const purpleCuteSlime = cuteSlime;
purpleCuteSlime.color = 'purple';

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

결과

objcet {name: "슬라임", attribute: "cute", color: "purple"}
objcet {name: "슬라임", attribute: "cute", color: "purple"}
objcet {name: "슬라임", attribute: "cute", color: "purple"}

그렇다면 왜 이런 결과가 나올까?
모든 슬라임이 똑같은 내용을 갖게 되는데 그 이유는 결국 다 같은 객체를 가르키게 되는 것이다.
여기서 만약에

console.log(silme === cuteSlime);

이라고 하게 되면 true가 나오게 된다. 그 이유는 cuteSlime에서 시작된 =로 인해서 결국 같은 객체를 가르키게 되는 것이다.

즉, 스프래드 연산자는 기존의 객체를 복사하고 추가적인 값을 넣어줄 때 사용하게 된다.

Ex4) 스프래드 연산자 사용이 덮어씌워지는 것에 대한 예시

const slime = {
	name: '슬라임'
};

const cuteSlime = {
	...slime,
  	attribute: 'cute'
};

const purpleCuteSlime = {
	...cuteSlime,
  	color: 'purple'
};

const greenCuteSlime = {
	...purpleCuteSlime,
  	color: 'greeen'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);
console.log(greenCuteSlime);

결과

object {name:  "슬라임"}
object {name: "슬라임", attribute: "cute"}
objcet {name: "슬라임", attribute: "cute", color: "purple"}
objcet {name: "슬라임", attribute: "cute", color: "green"}
//만약에 `greenCuteSlime`에서 스프래드 연산자와 Color: 'green'의 위치를 서로 바꾸게 되면
objcet {color: "purple", name: "슬라임", attribute: "cute"}

Ex5) 또한 스프래드 연산자는 배열에서도 사용가능하다.

const animals = ['개', '고양이', '참새'];
const anotherAnimals = [...animals, '비둘기'];
//또한 스프래드를 사용한 것이 concat을 사용한 것과 같다
const anotherAnimals = animals.concat('비둘기');

console.log(animals);
console.log(anotherAnimals);

결과

["개", "고양이", "참새"]
["개", "고양이", "참새", "비둘기"]

Ex6) 스프래드 연산자는 여러번 사용할 수 있다.

const numbers = [1, 2, 3, 4, 5];

const spread = [...numbers, 1000, ...numbers];

console.log(spreaNumbers);

결과

[1, 2, 3, 4, 5, 1000, 1, 2, 3, 4, 5]

rest

rest의 생김새는 spread와 비슷하다. 둘다 '...'을 사용하지만 역할이 조금 다르다.
rest는 객체, 배열, 함수의 파라미터에서 사용할 수 있다.

Ex1) 객체에서의 예시

const purpleCuteSlime = {
	name: '슬라임',
  	attribute: 'cute',
  	color: 'purple'
};

const{color, ...rest} = purpleCuteSlime;
console.log(color);
console.log(rest);

//여기서 우리는 ...rest를 우리가 원하는 이름으로 바꿔줄 수 있다.
const purpleCuteSlime = {
	name: '슬라임',
  	attribute: 'cute',
  	color: 'purple'
};

const{color, ...cuteSlime} = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);

결과

purple
Object{name: "슬라임", attribute: "cute"}

Ex2)만약 cuteslime에서 attribute까지 없애고 싶다면?

const purpleCuteSlime = {
	name: '슬라임',
  	attribute: 'cute',
  	color: 'purple'
};

const {color, ...cuteSlime} = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);

const {attribute, ...cuteSlime} = cuteSlime;
console.log(slime);

결과

purple
Object{name: "슬라임", attribute: "cute"}
Object{name: "슬라임"}

이렇기 때문에 rest는 spread와 는 차이가 있다. spread는 특정 객체나 배열 안에 다른 객체나 배열을 퍼트리는 역할을 한다면, rest는 퍼져있는 것을 모아오는 역할을 한다.

Ex3) 배열에서도 사용해보자

const numbers = [0, 1, 2, 3, 4, 5, 6];

const [one, two, ...rest] = numbers;
//반면에 알아둬야 할 것은 ...rest가 제일 앞에 올 수 없다. 아래예시
const [...rest, last] = numbers;

console.log(one);
console.log(two);
console.log(rest);

결과

0
1
[2, 3, 4, 5, 6]

함수 파라미터에서의 rest

Ex1)파라미터로 넣어준 모든 값을 합해주는 함수를 만들어보자

function sum (a, b, c, d, e, f, g) {
	return a + b + c + d + e + f + g;
}
console.log(1,2,3,4,5,6,7);
//만약에 아래와 하나라도 작성하지 않게 된다면 'undefined'가 나오게 된다.
function sum (a, b, c, d, e, f, g) {
	return a + b + c + d + e + f + g;
}
console.log(1,2,3,4,5,6);

결과

28
//
undefined

Ex2)

function sum (a, b, c, d, e, f, g) {
	let result = 0;
  	if (a) result += a;
  	if (b) result += b;
  	if (c) result += c;
  	if (d) result += d;
  	if (e) result += e;
  	if (f) result += f;
  	if (g) result += g;
  	return result
}

console.log(sum(1,2,3,4,5,6,7));

결과

28

이 결과도 어차피 console.log(sume(1,2,3,4,5,6,7))이후에 또 다른 숫자를 넣게 되면 작동을 하지 않게 된다.
이런 상황에서는 함수의 파라미터 부분에서 rest를 사용하면 가능하게 된다.
즉, console.log(sume(1,2,3,4,5,6,7))에 넣어준 파라미터를 하나의 배열로 받아오게 된다.

Ex3) rest를 파라미터에 쓰는 경우의 예시

function sum(...rest) {
	return rest.reduce((acc, current) => acc + current, 0);
}

console.log(sum(1,2,3,4,5,6,7,8));

결과

36

함수 인자에서의 spread 함수

Ex) 인자와 파라미터의 차이에 대한 예시

function subtract (x, y) {		//여기에 들어가는 (x, y)가 파라미터이다. 파라미터는 함수에서 받아오는 것이다.
	return x - y;
}

const result = subtract(1, 2); //여기에 들어가는 (1, 2)가 인자이다. 인자는 함수를 사용할 때 넣어주는 것이다.

Ex1) 함수의 인자에서 스프래드 연산자를 사용하는 방법

function sum(...rest) {
	return rest.reduce((acc, current) => acc + current, 0);
}

const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(sum(...numbers));

18. scope의 이해하기

스코프란 우리가 변수 혹은 함수를 선언하게 될 때 해당 변수 혹은 함수가 어디서부터 어디까지 유효한지에 대한 범위를 의미하게 된다. 스코프는 크게 세 가지로 구분된다.

1. Global

전역이라는 의미를 가지고 있고, 코드의 모든 범위에서 사용할 수 있다.

2. Function

특정 함수 내부에서만 사용이 가능하다는 것을 의미한다.

3. Block

if, for, switch문을 사용할 때 우리가 중괄호로 코드를 감싸게 되는데, 그렇게 감싸진 블록 내부에서만 사용이 가능하다는 것을 의미한다.

const value = 'hello!';

function myFunction() {
	console.log('myFunction: ');
  	console.log(value);
}

function otherFunction() {
	console.log('otherFunction: ');
  	const value = 'bye!';
  	console.log(value);
}

Myfunction();
otherFunction();

console.log('global scope: ');
console.log(value);

결과

myFunction:
hello!		//글로벌 스코프인 hello가 나타났다.
otherFunction:
bye!		//(함수형 스코프)이 'bye'는 함수 내부에서만 유효한 함수이고 글로벌스코프에 영향을 안준다.
global scope:
hello!		//글로벌 스코프인 hello가 나오게 된다.

Ex2)또다른 예시

const value = 'hello!';

function myFunction() {
	const value = 'bye!';
  	const anotherValue = 'world!';
  	function functionInside() {
    	console.log('functionInside: ');
      	console.log(value);
      	console.log(anotherValue);
    }
  functionInside();
}

myFunction();
console.log('global scope: ');
console.log(value);
console.log(anotherValue);

결과

functionInside: 
bye!
world
global scope:
hello!
referenceError: anotherValue is not defined // 	anotehrValue는 함수 스코프이기 때문에 에러가 나는 것이다.

Ex3)블록스코프에 대한 예시

const value = 'hello!';

function myFunction() {
	const value = 'bye!';
  	if(true) {
    	const value = 'world';
      	console.log('block scope:' );
      	console.log(value);
    }
  console.log('function scope: ');
  console.log(value);
}

myFunction();
console.log('global scope: ');
console.log(value);

결과

block scope:
world
function scope:
bye!
global scope:
hello!

만약 var를 사용한다면?
var이 키워드로 값을 선언하게 된다면 이 값은 블록 단위가 아니라 함수 단위로 스코프가 설정되어 있기 때문에, 같은 함수에 똑같은 이름으로 값이 선언되어 있다면 다른 블록에서 선언을 해도 기존에 있는 값에 영향이 간다는 것을 알아야 한다.

그렇다면 let 이나 const로 한다면?
스코프가 블록으로 제한되어 있기 때문에 블록 바깥에 있는 선언에는 영향을 주지 않게 된다.


19. hoisting

호이스팅이란 자바스크립트에서 아직 선언되지 않은 함수나 변수를 끌어올려서 사용할 수 있는 작동 방식을 말한다.

Ex1) 이에 맞는 예시

myFunction();

function myFunction() {
	console.log('hello world');
}

예시를 보면 선언이 되기 전에 호출을 했는데 잘 작동한다.
이게 잘 작동하는 이유는 자바스크립트엔진이 코드를 해석하는 과정에서 선언을 먼저하고 호출을 한 것으로 받아들이기 때문이다.
호이스팅은 가능한 한 피해야한다. 왜냐하면 헷갈릴 수 있기 때문이다.

변수 또한 호이스팅이 일어난다.

변수 호이스팅스 var

Ex2) 변수호이스팅의 예시

console.log(number);
var number = 2;

결과

undefined

위에서 보면 referenceError가 나와야 맞는 말이지만 undefined가 나오는 것을 확인할 수 있다.
그 이유는 아래 예시와 같이 해석하기 때문이다.

var number;
console.log(number);
number = 2;

변수 호이스팅스 const, let

const나 let은 호이스팅스가 일어나지 않는다.
바벨을 설정을 이용하는 경우 const, let을 var와 같이 해석하기 때문에 호이스팅이 일어나는 경우가 있다.


20. 비동기처리의 이해

1. 비동기적 처리

비동기적 처리란 코드를 실행할 때 흐름이 멈추지 않아서 동시에 여러가지 작업을 처리할 수 있고, 기다리는 동안 여러가지 일을 실행할 수 있다.

2. 동기적 처리

동기적 처리란 하나의 작업을 끝낼 때 까지 기다리는 동안 준비상태가 되기 때문에 다른 작업을 할 수 없다.

3. 코드예시로 보는 비동기적 처리와 동기적 처리

function work() {
	const start = Date.now();
	for (let i = 0; i <1000000000; i++) {
    
    }
  const end = Date.now();
  console.log(end - start + 'ms');
}

work();
console.log('다음작업');

얼마나 걸렸는지 알려주는 함수이다.
여기서 보면 work함수가 실행된 시간이 나온 다음에 다음작업이 나온다.
즉 work함수가 실행이 되고 실행이 끝나고 난 후에 다음작업이 실행된 것이다.

💡그렇다면 여기서 work함수가 실행되는 과정에서 다음작업을 동시에 실행하고 싶다면 함수를 비동기 형태로 전환해줘야 한다. 비동기 형태로 바꾸기 위해서 setTimeout을 이용해야 한다.
Ex)

function work() {
  	setTimeout(() => {
    	const start = Date.now();
	for (let i = 0; i <1000000000; i++) {
    
    }
  const end = Date.now();
  console.log(end - start + 'ms');
    }, 0)	//여기서 들어간 '0'은 그 자리에 들어간 숫자만큼의 시간 후에 특정 작업을 하겠다는 것을 의미한다.
  
 }

work();
console.log('다음작업');

💡 우리가 설정해준 시간에 대해서

넣은 시간이 0ms 후에 실행해주겠다는 것이지만 4ms후에 시작이 된다.
그 이유는 브라우저에서 정한 최소한의 값이기 때문이다.

💡만약에 work함수를 끝난 다음에 어떤 작업을 하고 싶다면 콜백함수를 파라미터로 설정해주면 된다.

여기서 콜백함수란 함수타입의 값을 파라미터로 넘겨줘서 파라미터로 넘겨 받은 함수를 특정 작업이 끝난 다음에 호출해 주는 것을 의미한다.

function work(callback) {
  	setTimeout(() => {
    	const start = Date.now();
	for (let i = 0; i <1000000000; i++) {
    
    }
  const end = Date.now();
  console.log(end - start + 'ms');
	callback(end - start)
    }, 0)
}

work((ms) => {
	console.log('작업이 끝났어요');
  	console.log(ms +'ms 걸렸다고 해요')
});
console.log('다음작업');

21. promise

'promise'는 비동기 작업을 조금 더 편하게 하기 위해서 es6에 도입된 기능이다.
이전에는 callback함수를 이용했지만, 이용해야 하는 경우가 늘어나는 경우 코드가 난잡해질 가능성이 커지기 때문이다. 원래는 라이브러리로 존재했지만 이제는 편하다보니 일반 자바스크립트 스팩에 추가되게 된 기능이다.

Ex1) promise를 만드는 방법

const myPromise = new Promise((resolve, reject) => {
	setTimeout(() => {
      resolve('result');
    }, 1000)
  
});

myPromise.then(result=> {
  console.log(result);
})

결과

result

Ex2)1초 뒤에 실패하는 예제

const myPromise = new Promise((resolve, reject) => {
	setTimeout(() => {
      reject(new Error());
    }, 1000)
  
});

myPromise.then(result=> {
  console.log(result);
}).catch(e => {			//여기서 에러를 잡아낼 때는 .catch를 써준다.
	console.error(e);
})

Ex3) promise를 만드는 함수작성

function increaseAndPrint(n){
	return new Promise ((resolve, reject)=> {
		setTimeout(() => {
        	const value = n + 1;
          	if (value === 5) {
            	const error = new error();
              	error.name = 'valueIsFiveError'; //여기서 .name으로 에러의 이름을 설정할 수 있다.
              	reject(error);
              	return;
            }
            console.log(value);
          	resolve(value);
        }, 1000);	
	});
}
increaseAndPrint(0).then(n => {
	console.log('result: ', n);
})

여기서 보면 '콜백함수를 다를 것이 없지 않느냐' 라는 생각을 할 수도 있지만 .then을 연달아서 사용할 수 있기 때문에 편리하기도 하고 코드가 깔끔할 수 있다.

function increaseAndPrint(n){
	return new Promise ((resolve, reject)=> {
		setTimeout(() => {
        	const value = n + 1;
          	if (value === 5) {
            	const error = new error();
              	error.name = 'valueIsFiveError'; //여기서 .name으로 에러의 이름을 설정할 수 있다.
              	reject(error);
              	return;
            }
            console.log(value);
          	resolve(value);
        }, 1000);	
	});
}
increaseAndPrint(0).then(n => {
	console.log('result: ', n);
}).then(n =>{
	return increaseAndPrint(n);
}).then(n =>{
	return increaseAndPrint(n);
}).then(n =>{
	return increaseAndPrint(n);
}).then(n =>{
	return increaseAndPrint(n);
}).catch(e = >{
	console.error(e);
})
//위에 .then과정을 더 깔끔하게 표현할 수 있다.
increaseAndPrint(0).then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.catch(e = >{
	console.error(e);
})
//이렇게 간단하게 작성한 코드의 결과값 역시 아래의 결과와 일치한다.

결과

1
2
3
4
valueIsFiveError

하지만 위의 경우에도 단점은 존재한다.
1.에러를 잡을 때 어떤 부분에서 에러가 발생했는지 알기 어렵다
2.특정 조건에 따른 분기를 나누는 작업도 어렵게 된다.
3.특정 값을 공유하면서 작업을 연달아서 하기가 어렵다.
위와 같은 단점으로 인해서 async, await문법을 사용한다.


22. async, await

promise를 더 쉽게 해주는 문법이다. es8에 소개된 문법이다.

Ex1)

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}

async function process () {
	console.log('안녕하세요.');
  	await sleep(1000); //1초동안 기다리게 하는 키워드
  	console.log('반갑습니다.');
}

process();

결과

안녕하세요.
반갑습니다.

위에서 보면 async와 await을 붙여주는 부분이 있는데, function앞에 async 와 promise앞에 await을 붙여주면 된다. 이렇게 되면 구태여 .then을 붙여주지 않고도 await만 붙여주면 된다.

Ex2) 만약 promise에서 에러를 발생시키고 싶다면 throw를 사용하고 에러를 잡아낼 때는 try.catch문을 사용하면 된다

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}

async function makeError () {
  	await sleep(1000); //1초동안 기다리게 하는 키워드
  	const error = new Error();
  	throw error;
}

async function process() {
	try{
    	await makeError();
       } catch (e) {	//여기에 있는 e가 위의 throw에 있는 error객체를 가르키게 된다.
       	console.error(e); 
       }
}

process();

23. promise all, promise.race

💡시작하기 앞서서 비동기처리 함수를 몇 개 더 만들어보자.

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}


const getDog = async () => { 	//만약 화살표 함수로 만들고 싶다면 ()앞에 async를 붙여주면 된다.
	await sleep(1000);
  	return '멍멍이';
}

const getRabbit = async () => {
	await sleep(500);
  	return '토끼';
}

const getTurtle = async () => {
	await sleep(3000);
  	return '거북이';
}

async function process() {
	const dog = await getDog();
  	console.log(dog);
  	const rabbit = await getRabbit();
  	console.log(rabbit);
  	const turtle = await getTurtle();
  	console.log(turtle);
}

process();

결과

멍멍이
토끼
거북이 // 한참 후에 나타난다.

promise all
💡한꺼번에 처리하는 것이 아니라 하나씩하나씩 처리하고 있는데 만약에 여러개의 프로미스를 한번에 처리하고 싶다면?

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}


const getDog = async () => { 	//만약 화살표 함수로 만들고 싶다면 ()앞에 async를 붙여주면 된다.
	await sleep(1000);
  	return '멍멍이';
}

const getRabbit = async () => {
	await sleep(500);
  	return '토끼';
}

const getTurtle = async () => {
	await sleep(3000);
  	return '거북이';
}

async function process() {
	const result = await Promise.all ([getDog(), getRabbit(), getTurtle()]);
  	console.log(result);
} // 이 부분

process();

결과

["멍멍이", "토끼", "거북이"]

위에서 이 부분이라고 표시한 부분을 보자면 이 promise는 모든 promise를 시작한 다음에 다 끝나고 난 후에 반환 값에는 각각 끝난 결과값이 들어간 배열이 반환된다.
여기서 추가적으로 모든 것이 끝난 시간은 3초이다. 그 이유는 getTurtle이 3초가 걸리기 때문이다.

💡실제로 전체가 3초가 걸렸는지 알아보기 위해서 앞에서 이용한 것을 통해서 알아볼 수 있다.

async function process() {
  	const start = Date.now();
	const result = await Promise.all ([getDog(), getRabbit(), getTurtle()]);
  	console.log(Date.now() - start);
  	console.log(result);
}

결과

3003
["멍멍이", "토끼", "거북이"]

Ex2) 만약에 promise.all에 등록한 각 프로미스 들에 대한 결과들을 각각 다른 변수로 꺼내고 싶다면?

1)가장 기본적인 방법

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}


const getDog = async () => {
	await sleep(1000);
  	return '멍멍이';
}

const getRabbit = async () => {
	await sleep(500);
  	return '토끼';
}

const getTurtle = async () => {
	await sleep(3000);
  	return '거북이';
}

async function process() {
	const result = await Promise.all ([getDog(), getRabbit(), getTurtle()]);
  	const dog = result[0];
  	const rabbit = result[1];
  	const turtle = result[2];
}

process();

이렇게 기본적인 방법으로도 가능하지만 배열비구조화 할당, 구조분해 문법을 이용하면 더 깔끔하게 가능하
다.

2) 배열비구조화 할당, 구조분해 문법을 이용한 방법

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}


const getDog = async () => {
	await sleep(1000);
  	return '멍멍이';
}

const getRabbit = async () => {
	await sleep(500);
  	return '토끼';
}

const getTurtle = async () => {
	await sleep(3000);
  	return '거북이';
}

async function process() {
	const [dog, rabbit, turtle] = await Promise.all ([getDog(), getRabbit(), getTurtle()]);
	console.log(dog);
  	console.log(rabbit);
  	console.log(turtle);
}

process();

결과

멍멍이
토끼
거북이	//모든 것들이 거북이로 인해서 3초가 걸린 후에 결과가 한번에 나온다.

promise.race

promise.race는 등록된 배열(여기서는)이나 제일 빠르게 결과값을 반환하는 값 하나만 출력된다.

function sleep(ms) {
	return new promise (resolve => setTimeout(resolve, ms));
}


const getDog = async () => {
	await sleep(1000);
  	return '멍멍이';
}

const getRabbit = async () => {
	await sleep(500);
  	return '토끼';
}

const getTurtle = async () => {
	await sleep(3000);
  	return '거북이';
}

async function process() {
	const first = await Promise.race ([getDog(), getRabbit(), getTurtle()]);
	console.log(first);
}

process();

promise.all과 promise.race의 오류에 대해서
1) promise.all

만약에 promise.all의 경우에는 셋 중에서 하나라도 오류가 걸리게 된다면 전체가 오류라고 간주하게 된다.

2)promise.race

가장 빠르게 끝난 것이 기준이 된다. 위의 코드로 예를 들자면 가장 빨리 끝난 토끼가 오류라면 오류라고 가정하게 되지만, 토끼가 오류가 아니고 터틀이 오류라고 한다면 오류라고 간주하지 않게 된다.

profile
이제 막 개발을 시작한 프로그래밍 입문자

0개의 댓글