
재선언: 똑같은 이름의 변수를 다시 만드는 것
재정의: 값이 지정된 변수에 값을 바꾸려는 것
스코프(scope): 식별자(ex. 변수명, 함수명, 클래스명 등)의 유효범위
// 변수 선언
var x = 2;
// 재정의
x = 4;
// 재선언
var x = 4;
var의 문제점
1. 변수 선언이 유연하기 때문에 예기치 못한 값을 반환할 가능성이 있음
2. 코드가 길어진다면 어디에서 어떻게 사용될 지 파악하기 힘듦
3. 함수 레벨 스코프로 인해 함수 외부에서 선언한 변수는 모두 전역 변수
4. 변수 선언문 이전에 변수를 참조하면 언제나 undefined를 반환 (hoisting 발생)
→ 따라서, var는 잘 사용하지 않으며, let과 const 키워드를 사용하는 것을 권장
let x = 10;
if (true) {
let x = 20;
console.log(x);
}
console.log(x);
const PI = 3.14;
console.log(PI); // 3.14
PI = 3.14159; // Error: 상수에 재할당할 수 없음
const로 선언된 객체와 배열은 참조를 변경하지 못하지만, 객체나 배열 내부의 속성과 요소는 수정 가능
const person = {
name: 'John',
age: 30
};
person.age = 31;
person = {}; // Error: 상수에 재할당할 수 없음
const number = [1, 2, 3];
number.push(4);
number = []; // Error: 상수에 재할당할 수 없음
let은 변수를 선언하며, 재할당이 가능. 반면에 const는 상수를 선언하며, 재할당이 불가능
let으로 선언된 변수는 초기화되지 않은 상태로 선언할 수 있지만, const는 선언과 동시에 반드시 초기값을 할당해야 함.
let과 const는 모두 블럭 범위이기 때문에 변수는 범위 내에서만 사용 가능
// 기존 코드 방식
function myFunc1(){
return '안녕' + name + '너의 나이는' + age + '살 이다!';
}
console.log('영희', 22);
// 출력 결과 => 안녕 영희 너의 나이는 22살 이다!
// 템플릿 리터럴 방식
const myFunc = (name, age) => {
return `안녕 ${name}, 너의 나이는 ${age}살 이다!`;
};
console.log(myFunc('영희', 22));
// 출력 결과 -> 안녕 영희, 너의 나이는 22살 이다!
화살표 함수는 함수 표현식을 보다 단순하고 간결하게 작성하는 문법
// 기존 방식
const myFunc(name){
return `안녕 ${name}`;
}
console.log(myFunc('영희')); // 출력 => 안녕 영희
// 화살표 함수 방식
const myFunc = (name) => {
return `안녕 ${name}`;
}
console.log(myFunc('영희')); // 출력 => 안녕 영희
// 또는 화살표를 사용하거나 'return' 키워드를 사용하지 않아도 됨
const myFunc = (name) => `안녕 ${name}`;
console.log(myFunc('영희')); // 출력 => 안녕 영희
const myFunc2 = (a, b) => a+b;
arr.map((el) => el*2);
// ES5 방식
const myArray = ['진수', '영철', '영희', '5'];
let arr1 = myArray.map(function(item){
return item;
});
console.log(arr1);
// ES6 방식
let arr2 = myArray.map((item) => item);
console.log(arr2);
return으로 결과값을 반환해줌모듈을 내보내는 방법으로는 named export와 default export(= import)가 있음
// named export 기본 형식
export {모듈명1, 모듈명2};
import {모듈명1, 모듈명2} from 'js 파일 경로';
// default export 기본 형식
export default 모듈명;
import 모듈명 from 'js 파일 경로';
export할 때 사용 가능export한 이름과 동일한 이름으로 import해야 하며, 중괄호에 묶어서 import 해야 한다.import 하려면 as를 사용하고, 한 파일에 있는 클래스나 변수들을 한 번에 import 하려면 * as 를 사용한다.// named export는 중괄호 포함 import
import {named1, named2} from './example.js';
// named export에서 as를 사용하여 다른 이름으로 import
import {named1 as myExport, named2} from './example.js';
// 한 파일에 있는 모든 클래스나 변수를 * as를 사용하여 한 번에 import
import * as Hello from './example.js';
export 가능import 할 때 아무 이름으로나 자유롭게 import 가능하며, 중괄호에 묶지 않아도 된다.// default export는 중괄호 없이 import
import default1 from './example.js';
일반적으로 js 파일을 불러오고 하다보면, 통으로 가져오는 부분이 크다보니 성능이나 시간에 차이가 생기기 마련이지만 export를 사용하면 선택적으로 다른 JavaScript 구성 요소에 사용할 function을 내보낼 수 있음
다른 컴포넌트에 사용하기 위해 가져오기 import를 사용
class는 객체를 생성하기 위한 템플릿으로, 틀과 같은 역할을 함
class 키워드와 함께 클래스의 이름을 작성let과 const처럼 블록 스코프에 선언되며, 호이스팅(hoisting)이 일어나지 않음클래스는 반드시 정의한 뒤에 사용한다.
super 키워드를 사용할 수 있다.static 키워드를 메소드 이름 앞에 붙여주면 해당 메소드는 정적 메소드가 된다.Getter 혹은 Setter를 정의하고 싶을 때는 메소드 이름 앞에 get 또는 set을 붙여주면 된다.extends 키워드를 사용하여 클래스에서 다른 클래스로 상속하면서 클래스의 기능을 확장해 나갈 수 있다.class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
nextYearAge(){ // 메서드 생성
return Number(this.age)+1;
}
}
// 클래스 상속
class introducePerson extends Person{
constructor(name, agte, city, futureHope){
// super 키워드를 이용해서 자식 class에서 부모 메서드를 호출
super(name, age, city);
this.futureHope = futureHope;
}
introduce(){
return `저는 ${this.city}에 사는 ${this.name} 입니다.
sosusdps ${super.nextYearAge()} 살이며,
장래희망은 ${this.futureHope} 입니다.`
}
}
let kim = new introducePerson('kim', '23', 'seoul', '개발자');
console.log(kim.introduce())
new 키워드를 사용하여 class 메서드와 속성에 액세스 가능
class myClass{
constructor(name, age){
this.name = name;
this.age = age;
}
}
const user = new myClass('영희', 22);
console.log(user.name); // 영희
console.log(user.age); // 22다
다른 class에 상속하려면 extends 키워드 다음에 상속할 class의 이름을 사용
class myClass{
constructor(name, age){
this.name = name;
this.age = age;
}
sayHello(){
console.log(`안녕 ${this.name} 너의 나이는 ${this.age} 살이다.`);
}
}
class UserProfile extends myClass{
userName(){
console.log(this.name);
}
}
const profile = new UserProfile('영희', 22);
profile.sayHello(); // 안녕 영희 너의 나이는 22살이다.
profile.userName(); // 영희
클래스는 상속과 다형성과 같은 객체 지향 프로그래밍(OOP)의 개념을 구현하기 위한 기반을 제공한다. 자식 클래스를 만들고 부모 클래스의 속성과 메서드를 상속받을 수 있다.
→ 이를 통해 코드의 재사용성과 유지 보수성을 향상시킬 수 있음.
객체와 배열의 값을 쉽게 변수로 저장할 수 있음
객체에서 값을 꺼낼 때는 중괄호를 사용해서 key와 같은 이름으로 꺼내올 수 있고, key와 다른 이름으로 꺼낼 때는 변수이름: 키 값으로 꺼내올 수 있다.
const contacts = {
name: 'unknown',
age: 23
};
let myName = contacts.name;
let myAge = contacts.age;
console.log(name); // unknown
console.log(age); // 23
📌 속성 이름과 동일하지 않은 변수에 할당하면 undefined가 반환됨.
예를 들어, 속성의 이름이 name이고 username 변수에 할당하면 undefined를 반환
항상 속성의 이름과 동일하게 변수 이름을 지정해야 함. 그러나 변수의 이름을 바꾸려면 콜론을 : 대신 사용하여 가능함
const introduce = {name: 'unknown', age: 23};
// key와 같은 이름으로 변수 선언
const {name, age} = introduce;
// 다른 이름으로 변수 선언 -> 변수이름: 키 값
const {myName: name, myAge: age} = introduce;
console.log(myName); // unknown
console.log(myAge); // 23
배열에서 값을 꺼낼 때는 대괄호를 사용해서 앞에서부터 순차적으로 꺼내올 수 있다.
const fruit = ['apple', 'mango', 'grape'];
// 앞에서부터 순차적으로 변수 선언 가능
const [zero, one, two] = fruits;
console.log(zero); // apple
Rest Parameter(나머지 매개변수)는 나머지 후속 매개변수들을 묶어 하나의 배열에 저장해서 사용하는 것이다.
묶어줄 매개변수 앞에 …을 붙여서 작성하면 된다.
즉, Rest Parameter는 배열과 함수의 인자 중 나머지를 가리키며, 객체의 나머지 필드를 가리킨다.
function func1(...args){
console.log(`args: [${args}]`)
// args: [1, 2, 3, 4, 5]
}
func1(1, 2, 3, 4, 5);
function func2(arg1, arg2, ...arg3){
console.lof(`arg1: ${arg1} , arg2: ${arg2}, arg3: [${arg3}]`)
// arg1: 1, arg2: 2, arg3: [3, 4, 5]
}
func2(1, 2, 3, 4, 5);
func(인자1, 인자2, …인자들)로 넘겨주게 되면 인자1, 인자2처럼 지정된 인자는 앞에서부터 각각의 값을 넣어주고 그 뒤의 나머지 후속 인자들을 배열에 인자들로 묶어서 보내주는 것이다.
Rest Operator는 함수 정의에는 하나의 …만 존재할 수 있으며, 반드시 마지막 매개변수여야 한다.
func(...wrong, arg2, arg3)
// 틀린 예 (...wrong이 마지막으로 와야 한다.)
Spread Operator(전개 구문)는 묶인 배열 혹은 객체를 개별적인 요소로 분리한다. 즉, Rest와 반대 개념이라고 생각하면 되고, 마찬가지로 전개할 매개변수 앞에 …을 붙여서 작성하면 된다.
→ for 반복문이나 다른 메서드를 사용하는 대신 Spread Operator를 사용하여 배열의 값을 가져올 수 있다.
따라서, 배열과 함수에선 또 다른 배열과 함수의 인자로의 전개를, 객체에선 또 다른 객체로의 전개를 한다.
let arr = [1, 2, 3, 4, 5];
console.log(...arr);
// 1 2 3 4 5
var str = 'Hello';
console.log(...str);
// "H" "e" "l" "l" "o"
Spread Operator도 Rest Operator와 마찬가지로 …의 작성 순서에 주의해야 한다. 등장 순서에 따라, 덮어씌워 질 수 있기 때문이다.
var obj = {name: '짱구', species: 'human'};
obj = {...obj, age: 5};
console.log(obj);
obj = {...obj, name: '짱아', age: 1};
console.log(obj);
위 예제와 같이 …obj가 먼저 나오고 name과 age가 나중에 등장함으로써 덮어씌워져 값이 변경된 것을 확인할 수 있다.
요약하자면, Rest Operator(나머지 매개변수)는 배열로 묶는 역할을, Spread Operator(전개 구문)는 개별적인 요소로 분리하는 역할을 한다.
둘 다 …을 붙여서 사용하며, 작성 순서에 주의해야 한다.
Spread 연산자는 배열이나 객체를 분해하거나 복사하는 데 사용되는 반면, Rest 매개변수는 함수 매개변수로 가변 개수의 인자를 배열로 수집하는 데 사용
forEach()와 map()은 반복문을 돌며 배열 안의 요소들을 1대1로 짝지어 주는 역할을 한다.
forEach(): 배열 요소마다 한 번씩 주어진 함수 (콜백)실행
배열.forEach((요소, 인덱스, 배열) ⇒ {return 요소});
map(): 배열 내의 모든 요소 각각에 대하여 주어진 함수(콜백)를 호출한 결과를 모아 새로운 배열을 반환
배열.map((요소, 인덱스, 배열) ⇒ {return 요소});
하지만 forEach()와 map()은 역할은 같지만, 리턴값의 차이가 있다.
forEach()는 기존의 배열을 변경하는 반면, map()은 결과값으로 새로운 배열을 반환한다.
var arr = [1, 2, 3, 4, 5];
// forEach()
var newArr = arr.forEach(function(e, i){
return e;
})
// return -> undefined
// map()
var newArr = arr.map(function(v, i, arr){
return v + 1;
})
// return -> 2, 3, 4, 5, 6
reduce(): 배열의 각 요소를 순회하며 callback 함수의 실행 값을 누적하여 하나의 결과값을 반환
배열.reduce((누적값, 현재값, 인덱스, 요소) ⇒ {return 결과}, 초깃값);
result = sum.reduce((prev, curr, i) => {
console.log(prev, curr, i);
return prev+curr;
}, 0);
// 0 1 0
// 1 2 1
// 3 3 2
result; // 6
0번째 인덱스의 값이 된다.reduce()는 초기값을 배열로 만들고, 배열에 값들을 push하면 map과 같아진다.const myFunc = (name, age) => {
return `안녕 ${name} 너의 나이는 ${age}살 이니?`;
};
console.log(myFunc1('영희'));
// 출력 => 안녕 영희 너의 나이는 undefined살 이니?
위의 함수는 정의되지 않은 상태로 반환 → 두 번째 매개 변수 age를 지정하는 것을 잊어버렸기 때문이다.
그러나 기본 매개 변수를 사용하면 정의되지 않은 매개 변수가 반환되지 않고 매개 변수 할당을 잊어버렸을 때 해당 값이 사용된다.
const myFun = (name, age = 22) => {
return `안녕 ${name} 너의 나이는 ${age}살 이니?`;
};
console.log(myFunc1('영희'));
// 출력 => 안녕 영희 너의 나이는 22살 이니?
자바스크립트에서 비동기 처리를 기존에는 콜백 함수를 사용한, 콜백 패턴을 사용하였지만 결과적으로 콜백헬이 발생
이를 해결하기 위해 프로미스가 도입되었고, 프로미스 후속처리 메소드를 이용하여 에러 처리를 효과적으로 할 수 있게 되었다.
const myPromise = () => {
return new Promise((resolve, reject) => {
resolve('안녕하세요 Promise가 성공적으로 실행했습니다.')
});
};
console.log(myPromise());
// Promise {<resolve>: "안녕하세요 Promise가 성공적으로 실행했습니다."}
콘솔을 기록하면 Promise가 반환된다. 따라서 데이터를 가져온 후 함수를 실행하려면 Promise를 사용. Promise는 두 개의 매개 변수를 사용하며 resolve 및 reject 예상 오류를 처리할 수 있다.
📌
fetch함수는Promise자체를 반환
const url = 'https://jsonplaceholder.typicode.com/posts';
const getData = (url) => {
return fetch(url);
};
getData()
.then((result) => {
console.log(result); // 성공적인 결과 출력
})
.catch((error) => {
console.error(error); // 에러 메시지 출력
})
.finally(() => {
console.log('Cleanup'); // 항상 실행되는 코드
});
then: 작업이 성공적으로 완료되면 then 메서드를 사용하여 이행 상태에 대한 처리를 할 수 있음catch: 작업이 실패하면 catch 메서드를 사용하여 거부 상태에 대한 처리를 할 수 있음finally: 작업이 완료되었을 때 어떤 처리든 항상 실행할 수 있음Reference
https://github.com/lukehoban/es6features
https://www.freecodecamp.org/news/write-less-do-more-with-javascript-es6-5fd4a8e50ee2/