let과 const는 es6부터 등장한 변수들이다.
그 전까지는 var를 사용했었다. let과 const는 var와 다르게 코드만으로도 의도를 알고 버그를
줄일 수 있기 때문에 변수는 let과 const를 사용하는것이 좋다.
3가지 변수 모두 호이스팅을 일으킨다.
let과 const는 블록 스코프(block - scoped)다.
즉, 코드 블록(함수, if문, while문 등)안에서 선언 된 변수는 지역변수다.
그 블록 안에서만 사용이 가능한 변수라는 뜻이다.
생성자 함수는 유사한 여러 객체를 손쉽게 만들 수 있다.
(쉽게 말해 붕어빵 틀 이라고 생각하면 쉽다.)
- 함수명의 첫글자를 대문자로 하는것이 관례이다.
- 실행할때는 반드시 new 연산자를 붙여줘야한다.
(new를 붙이지 않으면 일반적인 함수로 생각하기때문에 아무것도 반환하지 않는다.(undifined)
function Item(title,price){
this.title = title;
this.price = price;
this.showPrice = function(){
console.log(`가격은 ${price}원 입니다.`);
}
}
const item1 = new Item('인형',1000);
const item2 = new Item('가방',2000);
const item3 = new Item('신발',3000);
console.log(item1, item2, item3)
// Item {title: '인형', price: 1000, showPrice: ƒ}
// Item {title: '가방', price: 2000, showPrice: ƒ}
// Item {title: '신발', price: 3000, showPrice: ƒ}
item1.showPrice()
// 가격은 1000원 입니다.
컴퓨티드 프로피티는 이미 계산된 프로퍼티이다.
즉, 변수명을 넣으면 그 변수에 할당 된(계산 된)값이 할당 되고,
['안녕'+'하세요'] 또는 [2+3] 처럼 계산식도 넣을 수 있다.
function computedProperty(key,val){
return {
[key] : val
};
}
const name = computedProperty('이름','yong');
console.log(name);
//{이름: 'yong'}
// 이렇게 어떤게 key가 될 지 모르는 객체를 만들 때 유용하다.
- Object.assign : 객체 복사하기
const user = {
name: 'yong',
age: 27
};
const user2 = Object.assign({},user); //{}를 넣으면 새로운 객체를 만든다는 것이다.
user2.name = 'gal';
console.log(user); // {name: 'yong', age: 27}
console.log(user2); // {name: 'gal', age: 27}
객체의 key와 value만 따로 배열로 출력시킬 수 도 있다.
- Object.keys : 객체의 key만 배열로 모두 반환
- Object.values : 객체의 value만 배열로 모두 반환
- Object.entries : 객체의 key,value 각각 배열로 모두 반환
- Object.fromEntries : 배열을 객체로 변환
<Object.keys>
const user = {
name: 'yong',
age: 27
};
const key = Object.keys(user);
console.log(key); //['name', 'age']
<Object.values>
const user = {
name: 'yong',
age: 27
};
const value = Object.values(user);
console.log(value); //['yong', 27]
<Object.entries>
const user = {
name: 'yong',
age: 27
};
const entrie = Object.entries(user);
console.log(entrie); // 0 : (2) ['name', 'yong']
// 1 : (2) ['age', 27]
<Object.fromEntries>
let arr = [
['name','yong'],
['age','27']
];
const fromE = Object.fromEntries(user);
console.log(fromE); //{name: 'yong', age: '27'}
심볼은 기존의 객체의 내용을 건드리지 않고 속성을 추가할 수 있는 태그다.
남이 만든 코드에 함부로 속성을 건드리면 코드에 어떤 일이 일어날지 모르고,
또 속성을 추가한다한들 내가 지은 네이밍이 스코프 어딘가에 같은 이름으로
쓰이고 있을지 모르기 때문에!!
이럴때 심볼을 사용해주면 좋다.
const a = Symbol('name'); //Symbol <--S 대문자 명심!! ('name')은 심볼의 아이디
const b = Symbol('name');
console.log(a); //Symbol(name)
console.log(b); //Symbol(name)
//a와 b에 같은 심볼을 넣어서 콘솔에 출력해보면 동일하게 나온다. 하지만..
console.log(a==b); //false
console.log(a===b); //false
//비교해보니 둘은 완전히 각각 다른 심볼이다.
//즉, 심볼은 유일성이 보장된다.
- Symbol.for() : 전역 심볼
유일한 식별자인 Symbol과 다르게 Symbol.for()을 쓰면 전역 스코프에서
여러개로 사용할 수 있다.- Symbol.keyFor() :
해당 변수의 심볼에 정해 준 아이디(이름)를 불러와준다. () 괄호 안에 불러올 변수를 넣어주면 된다. (단, keyFor는 전역 심볼에만 사용이 가능하다.
대신 다른 방법으로는 description으로 불러올 수 있다.)
<Symbol 실제로 사용하기>
const user = {
name: "yong",
age: 27
}
const showName = Symbol("show name"); //showName을 심볼로 지정(id:show name)
user[showName] = function(){ //user에 showName을 넣는다.
console.log(this.name);
}
user[showName](); //yong
//showName을 실행해도 아래 for반복문에 영향을 주지 않는다.
for(let key in user){
console.log(`His ${key} is ${user[key]}`);
} //His name is yong
//His age is 27
통계,지표,쇼핑몰 등 연산이 필요한 동작에서 빠질 수 없는 태그들이다.
어떤것들이 있는지 쭉~쭉쭉 알아두자.
* toString() : ()에 받은 인수만큼 ()진수로 출력한다.
let num = 10;
console.log(num.toString()); //10
console.log(num.toString(2)); //1010
console.log(num.toString(16)); //a
-------------------------------------------------------
* Math.ceil() : 올림
let num1 = 5.1;
let num2 = 5.7;
console.log(Math.ceil(num1)); //6
console.log(Math.ceil(num2)); //6
-------------------------------------------------------
* Math.floor() : 내림
let num1 = 5.1;
let num2 = 5.7;
console.log(Math.floor(num1)); //5
console.log(Math.floor(num2)); //5
-------------------------------------------------------
* Math.round() : 반올림
let num1 = 5.1;
let num2 = 5.7;
console.log(Math.round(num1)); //5
console.log(Math.round(num2)); //6
-------------------------------------------------------
* Math.random() : 0~1 사이의 무작위 숫자를 생성한다.
console.log(Math.random()); //0.8344920908341382
//새로고침 할때마다 값은 매번 달라진다.
1~100 사이의 무작위 숫자를 얻고 싶다면?
Math.floor(Math.random()*100)+1; //54
//새로고침 할때마다 값은 매번 달라진다.
//마지막 +1은 1~100까지의 숫자를 원하기 때문에 1을 더해준다.
-------------------------------------------------------
* Math.max()와 Math.min() : ()안의 인수 중 최댓값/최솟값을 구할 수 있다.
console.log(Math.max(1,2,3,4,5)); //5
console.log(Math.min(1,2,3,4,5)); //1
-------------------------------------------------------
* Math.abs() : ()안의 인수의 절대값을 구해준다.(abs는 absolute의 약자)
console.log(Math.abs(-2)); //2
-------------------------------------------------------
* Math.pow(n,m) : 제곱 (pow는 power의 약자)
console.log(Math.pow(2,3)); //8
-------------------------------------------------------
* Math.sqrt() : 제곱근 (sqrt는 square root(영어로 제곱근)의 약자)
console.log(Math.sqrt(16)); //4
-------------------------------------------------------
* toFixed() : ()에 받은 인수만큼 소수점 자릿수 출력한다.
let num = 3.123;
console.log(num.toFixed()); //3
console.log(num.toFixed(0)); //3
console.log(num.toFixed(2)); //3.12
console.log(num.toFixed(5)); //3.12300
`<주의> tofixed는 반환값을 string으로 출력한다!!
따라서 Number(tofixed())처럼 Number로 다시 반환해줘야 하는 경우가 많다!!`
-------------------------------------------------------
* isNaN() : ()의 인수가 NaN인지 불린형으로 확인한다.
let x = Number('x');
let y = Number('2');
console.log(isNaN(x)); //true
console.log(isNaN(y)); //false
`isNaN 만이 유일하게 NaN인지 확인할 수 있다. 아래 사진도 같이 알아두자.`
* parseInt() : ()안의 인수의 문자열을 정수로 반환한다. Number와 다른점은 parseInt는 '34px'와 같은
숫자+문자열의 경우 숫자로 반환할 수 있는 만큼 반환한다는 점이다.
let margin = '10px'; //문자열 10px
let colorCode = 'ff5533';
console.log(parseInt(margin)); //10
console.log(Number(margin)); //NaN
console.log(parseInt(colorCode)); //때문에 문자열이 숫자로 시작하지 않는다면 NaN을 반환한다.
*또한 parseInt는 두번째 인수를 받아서 '첫번째 인수'의 진수를 지정할 수 있다.
let colorCode = 'f3';
console.log(parseInt(colorCode,16)); //243
console.log(parseInt('11',2)); //3
-------------------------------------------------------
* parseFloat() : parseInt와 다르게 소수점까지 모두 반환한다.
let a = '15.3256';
console.log(parseFloat(a)); //15.3256
문자열은 '' , "", `` 3가지로 표현할 수 있다.
'', "" 는 상황에 맞게 잘 사용하며 되고,
``백틱의 경우에는 다른 따옴표와 달리 줄바꿈을 해도 그대로 적용이 된다는 장점이 있다.
(작은.큰 따옴표들은 \n 을 써야함)
let news = `안녕하세요.
반갑습니다.
오늘의 날씨는 좋습니다.`;
console.log(news); //안녕하세요.
//반갑습니다.
//오늘의 날씨는 좋습니다.
- length :
문자열도 배열과 마찬가지로 .length를 사용해 문자열의 길이를 구할 수 있다.
(공백도 한 길이로 포함!!)
let result = "안녕하세요.";
console.log(result.length); //6
- 특정위치에 접근 : 배열처럼 변수[ ]의 [ ]안의 인수를 통해 [ ]번째 배열요소를 불러올 수 있다.
배열과 달리 문자열은 한글자 씩 고칠 수 없다.
let hi = "안녕하세요.";
console.log(hi[2]); //하
hi[0] = "아";
console.log(hi); //안녕하세요.
//배열과 달리 문자열은 '한글자씩' 고칠수 없다.
- toUpperCase() : 모두 대문자로 바꿈
- toLowerCase() : 모두 소문자로 바꿈
let result = "Hi, What are you doing this weekend?";
console.log(result.toUpperCase()); //HI, WHAT ARE YOU DOING THIS WEEKEND?
console.log(result.toLowerCase()); //hi, what are you doing this weekend?
- str.indexOf(text) : ( )안의 문자가 있는 위치를 반환
- indexOf는 ()안의 문자가 '첫번째'로 나타나는 위치 index를 리턴한다.
- 문자가 없으면 -1을 리턴합니다.
- 문자열을 찾을 때 대소문자를 구분합니다.
- if문에서 사용할 때는 > -1 을 넣어서 첫글자가 0이되어 if문이 false되는걸 막아야한다.
str.includes(text) : ( )안의 문자가 있는지 없는지 확인
특정 문자가 있는지의 여부만 확인할때는,
includes(text)를 쓰면 indexOf와 달리 > -1 를 추가해줄 필요 없다.
let result = "안녕하세요,제 이름은 용돌이 입니다.";
console.log(result.indexOf("용돌이")); //12
console.log(result.indexOf("돼지")); //-1
if(result.indexOf("안녕하세요")){
console.log("반갑습니다")
} //"안녕하세요"의 indexOf는 0이고, if문에서 0은 false이기 때문에 아무것도 반환하지 않음. 따라서,
if(result.indexOf("안녕하세요" > -1)){
console.log("반갑습니다")
} //반갑습니다.
//이렇게 -1보다 큰가? 를 논리연산자로 써서 0도 true에 포함되게 해줌.
str.slice(n, m) : n번째~m번째(m본인 미포함)까지의 문자 반환
- m이 없다면 문자열의 끝까지 반환한다.
- 음수라면 오른쪽 끝에서부터 센다.
let text = "와주셔서 감사합니다";
console.log(text.slice(2)); //셔서 감사합니다 (2부터 끝까지)
console.log(text.slice(2,4)); //셔서 (2,3)
console.log(text.slice(1,-3)); //주셔서 감 (1,2,3,4)
str.substring(n,m) : slice와 비슷하지만 n과 m이 바뀌어도 그대로 동작한다.
- 쉽게 말해 n과 m사이를 반환한다.
- 단, 음수는 허용하지 않는다.
let text = "와주셔서 감사합니다";
console.log(text.substring(0,3)); //와주셔
console.log(text.substring(3,0)); //와주셔
str.substr(n,m) : 배열의 n번째 부터 m개(n포함)를 가져온다.
let text = "와주셔서 감사합니다";
console.log(text.substr(2,3)); //셔서
console.log(text.substr(-4,2)); //사합
//음수를 쓰면 0,1,2번째가 아니라
//-1번째, -2번째 이렇게 된다.
str.trim() : 앞 뒤 공백 제거 (trim:불필요한 것을 제거하다.)
let text = " 반 갑습니다 ";
console.log(text.trim()); //반 갑습니다
//문자열의 앞,뒤 공백만 제거
str.repeat(n) : 문자열을 n번 반복한다.
let text = "hello!";
console.log(text.repeat(3)); //hello!hello!hello!
문자끼리도 엄연히 크기를 비교할 수 있다.
a보다 z가 크고, 대문자보다 소문자가 크다는것만 알고 있으면 된다. (아래 이미지 참고)
arr.splice(n,m,x) : 배열에서 지정한 배열요소를 삭제하고 삭제 된 값을 반환하며, 추가한다.
n번째부터 m개를 삭제, x는 추가하는 값
let arr = [1,2,3,4,5,'a','b'];
let arrDelete = arr.splice(1,2);
console.log(arrDelete); //[2,3] (삭제한 값을 반환할 수 있음)
console.log(arr); //[1,4,5,a,b] (삭제하고 남은 배열)
<x를 추가해 배열에 새로운 요소를 추가하기>
let arr2 = [1,2,3,4];
let arr2Delete = arr2.splice(1,0,100,2000); //(1,0)과 같이 아무것도 삭제하지 않으면
//출발한 인덱스는 1, 즉 0과 1사이에 x를 추가한다.
console.log(arr2); //[1, 100, 2000, 2, 3, 4]
arr.slice(n,m) : str.slice(n,m)과 동일하다.
- m은 미포함하고 n번째 부터 m번째 까지 반환한다.
- ( )안에 아무것도 넣지 않으면 복사된다.
let arr = [1,2,3,4];
console.log(arr.slice(1,3)); //[2,3]
console.log(arr.slice()); //[1,2,3,4]
arr.concat([arr2], [arr3],...) : concat은 배열을 병합시키고 새 배열을 만들어준다.
- (concat : 연결하다)
let arr = [1,2]
console.log(arr.concat([3,4])); //[1,2,3,4]
console.log(arr.concat([3,4], [5,6])); //[1,2,3,4,5,6] 배열과 배열 병합 가능
console.log(arr.concat([3,4],5,6)); //[1,2,3,4,5,6] 배열과 숫자 병합 가능
arr.forEach(fn) : 배열 반복
- 배열을 반복시키는 요소는 item과 index를 많이쓰고 arr는 거의 사용하지 않는다.
- 내장함수(map,filter..등 7~8개 정도 됨)에 쓰이는 ( )안의 인수는 (item, index, arr)순으로 고정으로 넣을 수 있다.
각각에 들어가는 인수 이름은 내가 정할 수 있다.
<arr.forEach(함수)를 사용해 배열 반복시키기>
let users = ['Mike', 'Tom', 'Jane'];
users.forEach((item)=>{
console.log(item)}) //Mike
//Tom
//Jane
users.forEach((item,index)=>{
console.log(item,index)}) //Mike 0
//Tom 1
//Jane 2
users.forEach((yong,dol)=>{
console.log(yong,dol)}) //Mike 0
//Tom 1
//Jane 2
//forEach(item, index, arr)<==이 3자리는 고정이다.
//이 3가지는 내가 아무 인수나 지정해줘서 쓸 수 있다.
users.forEach((item,index)=>{
console.log(`${index + 1}. ${item}`)}) //1. Mike
//2. Tom
//3. Jane
arr.indexOf() : str.indexOf()와 동일하게 ( )가 있는 위치 index를 반환한다.
- arr.indexOf(2,2)처럼 인수가 두개인 경우, 두번째 인수는 "찾기 시작하는 지점의 인덱스"가 된다.
let arr = [1,2,3,4,5,6,7,3];
console.log(arr.indexOf(3)); //2
console.log(arr.indexOf(3,2)); //2 (idx[2]부터 출발하니 3이 있는곳은 idx[2])
console.log(arr.indexOf(3,3)); //7 (idx[3]부터 출발하니 3이 있는곳은 idx[7])
arr.includes() : str.includes()와 동일. 배열에 ()의 인수가 포함되는지 확인하고 싶을때 사용.
- include : 포함하다.
let arr = [1,2,3];
console.log(arr.includes(2)); //true
console.log(arr.includes(4)); //false
arr.find(f) 와 arr.findIndex(f) : 함수를 사용해 원하는 값을 찾아낸다. (짝수를 찾거나, 성인을 찾거나.. 등등)
- 첫번째 true값만 반환하고 끝
- 없으면 undefined를 반환
arr.filter(f) : find와 동일하나 모든 true값을 반환한다는 차이가 있다.
<arr.find(f),arr.filter(f)>
: arr 배열 중 첫번째 짝수와 모든 짝수를 찾아보자.
let arr = [1,2,3,4,5];
const arrEvenNumber = arr.find((item)=>{
return item % 2 === 0; //(arr의 item 중 첫번째 짝수를 반환 후 끝)
});
const arrAllEvenNumber = arr.filter((item)=>{
return item % 2 === 0; //(arr의 item 중 첫번째 짝수를 반환 후 끝)
});
console.log(arrEvenNumber); //2
console.log(arrAllEvenNumber); //2,4
<arr.find(f)와 arr.findIndex(f)>
let userList = [
{ name: "Mike", age: 30},
{ name: "Tom", age: 25},
{ name: "Jane", age: 10}
]
const result = userList.find((user)=>{
if(user.age < 19){
return true;
}return false;
})
const resultIndex = userList.findIndex((user)=>{
if(user.age < 19){
return true;
}return false;
})
console.log(result); //{name: 'Jane', age: 10}
console.log(resultIndex); //2
arr.reverse() : 배열 요소를 역순으로 재정렬한다.
- 최근에 게시된 글이나, 최근에 가입한 유저순으로 정렬 등..이럴때에 많이 쓰인다.
let arrNum = [1,2,3,4,5];
console.log(arrNum.reverse()); //5,4,3,2,1
arr.map(f) : 함수를 받아 특정 기능을 시행하고 새로운 배열을 반환한다.
- map은 실무에서 정말 많이 쓰인다고 하니 틈틈히 연습해두자.
let userList = [
{ name: "yong", age: 20},
{ name: "gal", age: 30},
{ name: "lee", age: 40},
];
let newUserList = userList.map((user,index) => {
//map으로 기존 배열에서 값을 변경한 새 배열을 선언
return Object.assign({}, user, {id: index+1, isAdult: user.age > 19})
//Object.assign()을 넣어야 기존의 배열을 복사 후 그 배열에 요소를 추가를 시킬 수 있다.
});
console.log(newUserList);
// {name: 'yong', age: 20, id: 1, isAdult: true}
// {name: 'gal', age: 30, id: 2, isAdult: true}
// {name: 'lee', age: 40, id: 3, isAdult: true}
arr.join( ) : 배열을 합쳐서 하나의 문자열로 만든다.
- 괄호 안에 받는 인수로 합치는 배열간 들어갈 구분 요소를 지정해 줄 수 있다.
let arr = ["나는","용돌이","입니다"]; console.log(arr.join(" ")); //나는 용돌이 입니다
arr.split( ) : 하나의 문자열을 배열로 나눠준다.
- 괄호 안에 받는 인수로 배열을 만들때 배열의 각 요소를 구분할 기존 문자열의 구분자를 정할 수 있다.
let arr = "용돌이, 만세!"; console.log(arr.split()); //['용돌이, 만세!'] console.log(arr.split("")); //['용', '돌', '이', ',', ' ', '만', '세', '!'] console.log(arr.split(" ")); //['용돌이,', '만세!'] console.log(arr.split(",")); //['용돌이', ' 만세!'] console.log(arr.split("돌")); //['용', '이, 만세!']
Array.isArray( ) : 괄호 안에 받는 변수가 배열인지 불린형으로 알려준다.
let user = {name: "yong", age: 20}; //객체 let user2 = [1,2,3,4]; //배열(배열도 객체에 속함) console.log(Array.isArray(user)); //false console.log(Array.isArray(user2)); //true //user과 user2는 둘다 객체이나, Array.isArray로 배열인지를 확인할 수 있다.
arr.Sort(fn) : 인수를 함수로 받아서 배열을 재정렬한다.
- 함수가 생략되면 배열 요소를 문자열로 받아 유니코드 순으로 배열을 재정렬한다.
let arr = [25,4,13,88]; arr.sort((a,b)=>{ return a - b //b - a 로 뒤집으면 내림차순이 됨. } ); console.log(arr); //[4, 13, 25, 88]
arr.reduce(fn) : 누적계산값(a)과 현재값(b)를 받아 함수를 사용해 배열의 각 요소를 순회하며 함수의 실행 값을 누적하여 하나의 결과값을 반환 한다.
- 초기값을 빈 배열 [ ], 0 과 같이 반드시 설정해줘야한다.
let userList = [ {name : "yong", age: 18}, {name : "Tom", age: 28}, {name : "ave", age: 35}, {name : "hong", age: 13}, {name : "gigi", age: 5}, ]; let result = userList.reduce((p,c)=>{ return (p += c.age)} //모든 age를 더한 값 구하기 ,0); let result2 = userList.reduce((p,c)=>{ if(c.age > 19){ p.push(c.name) //현재(c) age가 19보다 클때, //p(누적 계산값)에 c의 name을 추가한다. //즉 초기값 []에 하나씩 추가한다. } return p; },[]) let result3 = userList.reduce((p,c)=>{ if(c.name.length === 3){ //현재(c)의 name의 길이가 3일때, //p(누적 계산값)에 c의 name을 추가한다. //즉 초기값 []에 하나씩 추가한다. p.push(c.name) } return p },[]) console.log(result); //88 console.log(result2); //["Tom","ave"] console.log(result3); //["Tom","ave"]
구조 분해 할당이란, 배열이나 객체의 각 속성을 분해해서,
그 값을 변수에 할당할 수 있게 해주는 표현식을 말한다.
<배열 구조 분해> [ ]
배열 구조 분해의 개념은 아래와 같다.
let [user1, user2, user3] = ["yong", "ga", "ri"]; console.log(user1); //yong console.log(user2); //ga console.log(user3); //ri
배열에 기본값을 미리 할당해 변수가 undefined 되는걸 막을 수도 있다.
let [a=1, b=2, c=3] = [4,5]; console.log(a); //4 console.log(b); //5 console.log(c); //3
일부 반환값을 무시할 수도 있다.
let [user1, ,user3] = ["Tom","Eve","Mike"]; //user2부분은 공백으로 둔 상태 console.log(user1); //Tom console.log(user2); //undefined (공백) console.log(user3); //Mike (user3가 공백을 건너뛰고 Mike를 할당받음)
배열의 값을 바꿔치기 할때도 구조 분해 할당은 유용하다.
let a = 1; let b = 2; [a,b] = [b,a]; console.log(a); //2 console.log(b); //1
<객체 구조 분해> { }
객체 구조 분해는 배열 구조 분해와 동일하나
한가지 차이점은 객체 요소의 순서를 무시해도 된다는 점이다.let user = {name: "yong", age: 27}; let {name,age} = user; //이 표현식은 let name = user.name; // let age = user.age; 와 같다. //let {age,name} = users; //이렇게 순서를 바꿔도 정상 작동 console.log(name); //yong console.log(age); //27
새로운 변수 이름으로 할당해 사용할 수도 있다.
let user = {name: "yong", age: 27}; let {age: userAge, name: userName} = user; console.log(userAge); //27 console.log(userName); //yong
배열 구조 분해와 동일하게 기본값을 지정해줄 수 있다.
let user = {name: "yong", age: 27}; let {name, age, gender = "data is not defined."} = user; console.log(name); //yong console.log(age); //27 console.log(gender); //data is not defined. //만약 user에 gender값이 할당되어 있다면, 당연히 그 값이 //기본값을 덮어씌우고 그 값이 반환된다.
함수에서 매개변수를 받을때 마지막 매개변수에 ...을 넣어서 남는 나머지 인수들을
모두 할당 받을 수 있다. 나머지 매개변수는 반드시 마지막에 위치해야한다.
- 나머지 매개변수는 array의 형태로 반환되기 때문에, array 메소드(forEach,map,filter등)
를 따로 사용할 수가 있다.function add(...numbers){ //받는 모든 인수를 number가 매개변수로 활용 let result = 0; numbers.forEach((num)=>(result += num)) //배열 메소드 forEach를 사용 console.log(result); } add(1,2,3); //6
생성자 함수를 사용해 좀 더 실용적인 예제를 만들 수 있다.
function Users(name, age, ...skills){ this.name = name; this.age = age; this.skills = skills; } let user1 = new Users("yong", 18, "a", "b", "c"); console.log(user1) //아래와 같이 name과 age에 할당되고 남은 인수들이, //모두 나머지 매개변수인 ...skills에 할당되어 배열 형태로 반환되었다.
...은 전개구문으로 사용할 수도 있다. 배열과 객체를 다룰때
복잡한 메소드를 사용하지 않고 대신 전개구문으로 쉽게 배열과 객체에 활용할 수 있다.let a = [1,2,3]; let b = [4,5,6]; let c = [...a, ...b]; console.log(c); //[1, 2, 3, 4, 5, 6]
배열 중간에 전개구문을 넣을 수도 있다.
let a = [1, 2, 3]; let b = [0, ...a, 4, 5, 6]; console.log(b); //[0, 1, 2, 3, 4, 5, 6]
전개구문으로 object.assign()을 쓰지 않고도 객체와 배열 모두 복제가 가능하다.
let num1 = [1,2,3,4]; let num2 = [...num1]; console.log(num2); //[1,2,3,4] let user1 = {name: "yong", age: 27}; let user2 = {...user1}; console.log(user2); //{name: "yong", age: 27} **여기서 user2의 name을 Tom으로 바꾸어도 user1의 객체에는 아무런 영향을 끼치지 않는다. 즉, user2는 별개의 객체로 복제되었다.** user2.name = "Tom"; console.log(user1.name); //yong console.log(user2.name); //Tom
setTimeout : 지정한 일정 시간이 지난 뒤 함수를 실행하게 한다.
setInterval : 지정한 일정 시간 간격으로 함수를 실행하게 한다.
<setTimeout>
let num = 0;
function showTime(){
console.log(`현재 접속한지 ${num+=3}초가 지났습니다.`)
};
setTimeout(showTime,3000); //(3초 뒤)현재 접속한지 3초가 지났습니다.
<setInterval>
let num = 0;
function showTime(){
console.log(`현재 접속한지 ${num++}초가 지났습니다.`)
};
setInterval(showTime,1000); //현재 접속한지 0초가 지났습니다. (1초마다)
//현재 접속한지 1초가 지났습니다.
//현재 접속한지 2초가 지났습니다.
// ...
각각 set -> clear 으로 바꿔서 멈추게 할 수 있다.
<clearTimeout>
let num = 0;
function showTime(){
console.log(`현재 접속한지 ${num+=3}초가 지났습니다.`)
};
const tId = setTimeout(showTime,3000);
clearTimeout(tId); //(아무 출력 없음)
`clearTimeout이 setTimeout보다 밑에 있는데도 먼저 실행되는 이유는,
스케줄 함수들은 모든 코드가 쭉 실행된 후에 실행되기 때문에 아무 출력이 없음`
<clearInterval>
let num = 0;
function showTime(){
console.log(`현재 접속한지 ${num++}초가 지났습니다.`)
if(num>3){ //num이 3보다 커지면 아래 함수를 실행
clearInterval(tId); //tId를 clearInterval 시킨다.
}
};
const tId = setInterval(showTime,1000);
//현재 접속한지 0초가 지났습니다. (1초마다)
//현재 접속한지 1초가 지났습니다.
//현재 접속한지 2초가 지났습니다.
//현재 접속한지 3초가 지났습니다.
// (끝)
- 세가지 모두 함수의 호출방식과 상관없이 this값을 지정해줄 수 있다.
call : 모든 함수에서 사용할 수 있으며, this를 특정값으로 지정 할 수 있다.
const mike = {
name: "Mike",
};
const tom = {
name: "Tom",
};
function showName(){
console.log(this.name); //this에는 이 함수를 호출한 그 인수가 들어간다.
};
showName(); //
showName.call(tom); //Tom
//call은 모든 함수에서 접근이 가능하기 때문에, 함수안에 없던 변수를 불러넣음!
function update(birthYear, skills){
this.birthYear = birthYear;
this.skills = skills;
};
update.call(tom,1999,'HTML5');
//call()에서 받는 첫번째 매개변수는 this를 지정한다.
//call()에서 받는 두번째 매개변수 부터는 update에 지정 된
//매개변수(birthYear, skills)에 차례로 들어간다.
console.log(tom); //{name: 'Tom', birthYear: 1999, skills: 'HTML5'}
apply : call 과 완전히 동일하나, apply는 받는 매개변수를 배열로 받는다는 차이점이 있다.
const nums = [1, 2, 3, 5, 8];
const minNum = Math.min.apply(null, nums); //Math.min.apply(null, [1,2,3,5,8])과 같고,
//이는 Math.min(1,2,3,5,8)이 된다.
//apply(null, nums)에서 null에는 this에 들어가는
//매개변수를 지정해야하나, 현재 Math.메소드에서는 딱히 this가 필요가 없으므로 null을 넣음.
console.log(minNum); //1
const maxNum = Math.max.call(null, ...nums); //Math.max.call(null, 1,2,3,5,8)과 같고,
//이는 Math.max(1,2,3,5,8)이 된다.
console.log(maxNum); //8
bind : 함수의 this값을 영구히 바꿀 수 있다.
const user = {
name: "Mike",
showName: function(){
console.log(`hello, ${this.name}`);
},
};
user.showName(); //hello, Mike
//변수 user의 지역함수 showName을 실행하면
//user에 할당 된 name인 "Mike"가 this로 들어가
//정상적으로 호출한다.
let fn = user.showName //하지만 fn이라는 새로운 함수를 만들어
//user의 showName함수를 불러온다면,
fn(); //hello,
//이렇게 user(this).name을 잃어버리기 때문에 hello,만 출력된다.
let boundFn = fn.bind(user); //따라서 boundFn이라는 새로운 함수를 만들고,
//변수 fn에 .bing(user)로 fn의 this의 값을
//user로 영구히 지정해버린다.
boundFn(); //hello, Mike
//따라서 user 변수가 맨위에 const로 생성되어 있기 때문에,
//boundFn()은 fn()이고, fn()은 user를 this로 받는 showName함수를 실행한다.
- 프로토타입 객체 (prototype) : 다른 객체의 원형이 되는 객체이다.
모든 객체는 프로토타입 객체에 접근할 수 있다.
<Bmw는 redBmw의 프로토타입이다.>
const Bmw = function(color){
this.color = color; //Bmw의 color는 ()의 인수.
}
Bmw.prototype.wheels = 4;
Bmw.prototype.nav = 1; //Bmw의 원형 객체, 즉 프로토타입을 각각 지정하였다.
Bmw.prototype.blackbox = 1;
const redBmw = new Bmw("red"); //redBmw를 Bmw의 red color로 생성.
console.log(redBmw);
//(아래사진)
그럼 redBmw의 현재 모든 프로퍼티는 무엇인지 살펴보자.
for(p in redBmw){ console.log(p) }; //color //wheels //nav //blackbox
하지만 Object.keys( )나 Object.values( )로 출력을 해보면,
console.log(Object.keys(redBmw)); //['color'] console.log(Object.values(redBmw)) //['red]
이렇게 프로토타입의 프로퍼티들은 출력되지 않는것을 확인 할 수 있다.
이를 구분해서 사용하자.
또, Bmw.prototype.wheels 말고 다른 방법으로 프로토타입 객체를 만들어 줄 수도 있다.
const car = {
wheels: 4,
nav: 1,
blackbox: 1,
};
const bmw = {
color : "white",
};
bmw.__proto__ = car;
console.log(bmw);
//(아래 사진)
이와 같이 (프로토타입 객체가 되는 변수명).__proto__ = (그것을 받는 객체)
(.언더바2개 proto 언더바2개) 를 사용해서 손쉽게 특정 객체를 프로토타입으로 지정해줄 수 있다.
다른 방법으로 원하는 객체에 직접 프로토타입 프로퍼티를 지정해줄 수 있으나,
이는 constructor(생성자)가 표기되지 않으므로 처음의 Bmw.prototype.wheels 의 방법을 주로 쓰거나, 만약 써야 한다면 직접 constructor를 지정해줘야 한다.
const Bmw = function (color) {
this.color = color;
};
Bmw.prototype = {
constructor: Bmw, //Bmw.prototype의 constuctor(생성자)를 Bmw로 직접 지정해줘야 한다.
wheels: 4,
nav: 1,
blackbox: 1,
};
const redBmw = new Bmw("red");
console.log(redBmw.constructor === Bmw); //true
프로토타입은 상속의 개념이 적용된다.
클래스는 생성자 함수와 역할이 동일하나, 사용이 비교적 편하고 new 없이는 사용을 못하는등 개발자가 버그를 찾아내는데에 좀 더 수월하게 한다.
클래스와 생성자함수는 어떤점이 다른지 살펴보자.
- 생성자함수와 달리 클래스는 new없이는 사용이 불가하다.
<User1은 생성자함수로, User2는 클래스로 만든 객체이다.>
const User1 = function (name, age) {
this.name = name;
this.age = age;
this.showName = function () {
console.log(this.name);
};
};
const mike = /*new*/ User1("Mike", 30); //undefined
console.log(mike); //new를 빼도 undefined를 반환하여 에러가 발생하지 않는다.
//따라서 개발자는 new를 빠뜨린 실수를 했음에도 불구하고 에러를 확인하지 못한다.
class User2 {
constructor(name, age) {
this.name = name;
this.age = age;
}
showname() {
console.log(this.name);
}
}
const tom = /*new*/ User2("Tom", 25); //error
console.log(tom); //하지만 클래스는 생성자함수와 다르게 에러를 반환한다.
new를 빠뜨려도 두가지가 다른 결과를 반환하는 이유는 여기에 있다.
보시다시피 클래스는 생성자함수와 다르게 constuctor(생성자)가 User2로 명시되어있다.
이게 바로 new를 쓰지않고서는 사용할 수 가 없는 이유다.
- 또한, 위 사진처럼 이 객체의 생성자가 어떤것인지 바로 알 수가 있다.
- for in문을 사용했을 때 프로토타입 프로퍼티까지 반환하지 않는다.
const User1 = function (name, age) {
this.name = name;
this.age = age;
};
User1.prototype.showName = function () { //showName함수를 프로토타입 형태로 바꿈
console.log(this.name);
};
for (const p in mike) {
console.log(p);
} //name
//age
//showName
이 처럼 생성자함수로 만든 mike의 프로퍼티를 확인하면 프로토타입의 프로퍼티까지
모두 반환되어 구분을 할 수 없다.
따라서 프로퍼티가 객체만의 것인지 프로토타입의 것인지 확인하려면 hasOwnProperty를 사용해야했지만,
for (const p in tom) {
console.log(p);
} //name
//age
클래스로 만든 tom은 객채의 프로퍼티만 반환하는것을 확인할 수 있다.
- extends를 사용해 클래스간 상속이 가능하다.
class Car {
constructor(color) {
this.color = color;
this.wheels = 4;
}
drive() {
console.log("drive...");
}
stop() {
console.log("STOP!!");
}
} //Car이라는 클래스를 생성하고,
class Bmw extends Car { //extends를 사용해 Bmw가 Car의 프로퍼티들을 상속받는다.
nav = 1; //nav는 객체 프로퍼티로 들어감!
park() { //함수인 park는 프로토타입 프로퍼티로 들어감!
console.log("PARK");
}
}
const redBmw = new Bmw("red");
console.log(redBmw); //아래 사진
위와 같이 redBmw는 Car클래스에서 선언한 color와 wheels는 객체 프로피티로,
drive(),stop()은 프로토타입 프로퍼티로 들어가 있고,
Bmw가 Car를 상속받으면서 추가된 nav는 객체 프로퍼티,
park()는 프로토타입 프로퍼티로 들어가 있다!
- 오버라이딩(Overriding)
: 프로퍼티가 중복될때, 자식 객체의 프로퍼티가 우선시 되어 덮어쓰인다.
하지만, super.프로퍼티 를 사용해서 부모 객체의 값을 받아올 수 있다.
class Car {
constructor(color) {
this.color = color;
this.wheels = 4;
}
drive() {
console.log("drive...");
}
stop() {
console.log("STOP!!"); //중복
}
}
class Bmw extends Car {
nav = 1;
park() {
console.log("PARK");
}
stop() { //중복
super.stop(); //이럴때 super.stop()을 넣어서 부모의 프로퍼티를 가져온다.
console.log("OFF!!"); //super를 넣지 않으면 그대로 자식 객체의 프로퍼티를 사용!
//'부모'의 stop을 쓰려면 아무것도 안쓰기
//'자식'의 stop을 쓰려면 덮어 씌우기(오버라이딩)
//'부모'와 '자식'의 stop을 모두 쓰려면 super.stop과 새로운 stop쓰기
}
}
const redBmw = new Bmw("red");
console.log(redBmw);
constructor가 자식 객체에서 추가될때는, 부모의 constructor가 모두 생략되기 때문에
반드시 부모의 constructor를 super로 불러와야하며, 또한 부모의 constructor가 받는
인수들도 constructor와 super에 모두 대입시켜줘야 한다.
class Car {
constructor(color) {
this.color = color;
this.wheels = 4;
}
drive() {
console.log("drive...");
}
stop() {
console.log("STOP!!");
}
}
class Bmw extends Car {
constructor(color) { //this.nav가 포함된 새로운 constructor를 넣기 위해선,
super(color); //super로 부모 생성자를 불러오고, 그 안에 받는 인수도
//부모와 동일하게 넣어줘야한다.(넣지 않으면 color의 값이 undefined 됨)
this.nav = 1;
}
}
const redBmw = new Bmw("red");
console.log(redBmw);
프로미스는 Promise(resolve, reject)로 정의하고,
then(성공,실패), catch(실패), finally(항상)로 그 값을 받는다.
위와 같이 then의 첫번째 인수는 성공했을때 값을, 두번째 인수는 실패했을때 값을 반환한다.
가독성을 위해 실패했을 경우는 catch를 쓰는것이 좋다.
(then(null, f)와 catch(f)는 완벽하게 같다.)
<pr이 성공일 때>
const pr = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Ok");
}, 2000); //2초 뒤에 pr을 성공시키고 ("Ok)를 출력.
});
pr.then((result) => {
console.log(result + `, 가져가세요`); //pr이 성공할때 받은 resolve를 result에 넣고,
//result에 ', 가져가세요'를 붙여서 출력시킨다.
})
.catch((err) => {
console.log(err);
})
.finally(() => {
console.log("끝"); //finally는 pr이 성공이든 실패든 항상 나오는 값!
});
<pr이 실패일 때>
const pr = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("err..."));
}, 2000); //2초 뒤에 pr을 실패시키고 새로운 Error를 생성: "err..."
});
pr.then((result) => {
console.log(result + `, 가져가세요`);
})
.catch((err) => {
console.log(err + `다시 실행하세요.`); //실패 시 실행 된 reject값을 err로 가져온다.
//그리고 그 err에 "다시 실행하세요"를 붙이고 출력.
})
.finally(() => {
console.log("끝"); //finally는 pr이 성공이든 실패든 항상 나오는 값!
});
프로미스 체이닝 : 스크립트를 불러오는 것과 같이 순차적으로 처리해야 하는 비동기 작업이 여러 개
있을때 사용하면 좋다.
<프로미스 체이닝>
const order1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res(`1번 주문 완료`);
}, 1000);
});
};
const order2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`2번 주문 완료`);
}, 2000);
});
};
const order3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`3번 주문 완료`);
}, 3000);
});
};
order1()
.then((result1) => order2(result1)) //order1의 res값을 result1으로 받고,
//order2의 인수로 넘겨줌.
.then((result2) => order3(result2)) //order2의 res값을 result2으로 받고,
//order3의 인수로 넘겨줌.
.then((result3) => console.log(result3)) //order3의 res값을 콘솔창에 출력.
.catch(console.error) //실패시 콘솔에 에러를 표시.
.finally(() => {
console.log(`주문이 끝났습니다.`); //끝날때 항상 '주문이 끝났습니다' 출력.
});
Promise.all( [ ] ) : 모든 프로미스를 동시에 이행한다. 주어진 프로미스 중 하나라도 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부한다.
예로 "하나의 정보라도 누락되면 페이지를 보여주거나/안보여주거나" 처럼 사용할 수 있다.
<promise.all을 사용해 모든 res값을 출력>
const order1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res(`1번 주문 완료`);
}, 1000);
});
};
const order2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`2번 주문 완료`);
}, 2000);
});
};
const order3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`3번 주문 완료`);
}, 3000);
});
};
Promise.all([order1(), order2(), order3()]) //promise.all은 매개변수를 배열로 받는다.
//배열안에 이행할 프로미스들을 지정해준다.
.then((res) => {
console.log(res); //"모든"프로미스가 res일때 콘솔에 배열로 출력함.(promise.all이기 때문에)
})
.catch(console.error) //promise.all은 하나의 프로미스라도 거부당하면 해당 catch문을 출력하고 모두 거부한다.
.finally(() => {
console.log("끝났습니다."); //끝날때는 항상 "끝났습니다"를 출력함.
});
Promise.race([ ]) : promise.all과 동일하게 사용하면 된다. 모든 작업이 끝날때 까지 기다리는 all과 달리, race는 가장 먼저 프로미스가 이행되면 즉시 수행을 끝낸다는 점이다.
용량이 큰 이미지들을 로딩하는데, 그 중 하나라도 완료되면 그 이미지를 보여주는 등 처럼 사용할 수 있다.
<위의 all코드와 동일하고 promise.all -> race로 만 바꾸었을 때>
const order1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res(`1번 주문 완료`);
}, 1000);
});
};
const order2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`2번 주문 완료`);
}, 2000);
});
};
const order3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`3번 주문 완료`);
}, 3000);
});
};
Promise.race([order1(), order2(), order3()]) //배열 내 프로미스 하나가 먼저 실행되면 즉시 중단
.then((res) => {
console.log(res);
})
.catch(console.error)
.finally(() => {
console.log("끝났습니다.");
});
async은 함수의 맨 앞에 추가해서 해당 함수가 항상 값을 프로미스로 반환하게 해준다.
await은 반드시 async함수 내에서만 사용 가능하며, 프로미스가 처리될 때 까지 기다린다.
위에서 사용했던 order코드에서 프로미스를 async과 await을 사용해서
코드를 줄이고 가독성을 높여보자.
async과 await
<async과 await을 사용해서 코드 줄이기>
const order1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res(`1번 주문 완료`);
}, 1000);
});
};
const order2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`2번 주문 완료`);
}, 2000);
});
};
const order3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`3번 주문 완료`);
}, 3000);
});
};
async function doOrder() { //반드시 function앞에 async 넣어주기
try {
const result1 = await order1(); //순차적으로 프로미스가 처리될때 까지 기다리는 중
const result2 = await order2(result1); //이 코드는 프로미스 체이닝을 했을때와 똑같다.
const result3 = await order3(result2); //then에 사용되는 코드 모두 try문으로 묶어준다.
console.log(result3);
} catch {
console.log("에러가 발생했습니다.");
} finally {
console.log("주문이 끝났어유");
}
}
doOrder();
동일한 코드에 Promise.all을 사용할 수도 있다.
const order1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res(`1번 주문 완료`);
}, 1000);
});
};
const order2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`2번 주문 완료`);
}, 2000);
});
};
const order3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res(`3번 주문 완료`);
}, 3000);
});
};
async function doOrder() {
try {
const result = await Promise.all([order1(), order2(), order3()]);
console.log(result);
} catch {
console.log("에러가 발생했습니다.");
} finally {
console.log("주문이 끝났어유");
}
}
doOrder();
제너레이터는 함수의 실행을 중간에 멈췄다가 재개할 수 있는 기능을 가지고 있는 함수다.
제네레이터 함수는 특별하게 function*으로 선언할 수 있고, 원하는 값을 yield(반환)문으로 나누어 next()를 사용해 가장 가까운 yield문을 만날때 까지 실행되고 객체를 반환한다.
function* generator() {
console.log("첫번째");
yield 1; //반환되는 객체의 value는 yield의 오른쪽에 있는 값이다.
console.log("두번째");
yield 2;
return "finish";
}
let a = generator();
`콘솔창에 입력`
a.next();
a.next();
a.next();
next로 찍어서 반환된 객체는 위의 사진과 같이 value 와 done 프로퍼티를 가진다.
value는 yield의 오른쪽에 있는 값이고, done은 함수 코드가 끝났는지를 확인한다.
(ture면 끝, flase면 진행 중)
제네레이터 함수는 next(), return(), throw() 메소드를 가지고 있다.
return은 입력 시 함수가 즉시 종료되고, done: true를 반환한다.
function* generator() {
console.log(1);
yield 1;
console.log(2);
yield 2;
console.log(3);
yield 3;
}
let a = generator();
`콘솔창에 입력`
a.next();
a.return();
a.return("finish");
a.next();
이후에 next()를 해도 value를 받을 수 없고 done은 true 상태를 유지한다.
return() 괄호 안의 인수가 반환된 객체의 value에 들어간다.
throw()는 제너레이터 함수 내에서 try, catch문에서 catch문을 호출할 때(즉, 에러를 반환할때) 사용할 수 있으며 이 역시 즉시 함수가 종료되고 done을 true로 반환한다.
function* generator() {
try {
console.log(1);
yield 1;
console.log(2);
yield 2;
console.log(3);
yield 3;
} catch (e) {
console.log(e); //catch문에서 받는 인수를 콘솔에 출력하도록 되어 있음.
}
}
let a = generator();
`콘솔에 입력`
a.next();
a.throw(new Error("error!!!"));
throw 역시 즉시 함수가 종료 되고 done: true가 되는것을 확인할 수 있다.
next()에 인수를 직접 전달 할 수도 있다.
<a.next()를 입력할때 마다 어디에서 멈추는지 잘보기>
function* generator() {
const num1 = yield "첫번째 숫자를 입력하세요"; //a.next() yield 문에서 멈추고, 다음에 입력하는 a.next()안의 인수가 num1의 값이 된다.(value는 yield 오른쪽에 있는 값이기 때문)
console.log(num1);
const num2 = yield "두번째 숫자를 입력하세요";
console.log(num2);
return num1 + num2; //num1과 num2에 저장된 값을 더한 값을 리턴함.
}
let a = generator();
`콘솔에 입력`
a.next();
a.next(2);
a.next(4);
이처럼 제너레이터는 외부로 부터 값을 입력받을 수 있다.
제너레이터는 값을 미리 만들어 두지 않고 필요할때마다 그떄 그때 값을 처리한다.
즉, 필요한 순간까지 계산을 미루어 둘 수 있다는 장점이 있다.
<break가 없는 while(true)문으로 무한 반복을 막는 제너레이터 함수>
function* fn() {
let i = 0;
while (true) { //이 함수는 일반 함수라면 무한히 반복되는 break가 없는 while(true)문이다.
yield i++; //하지만 제너레이터 함수를 사용하면 next를 입력할 떄마다 값을 받을 수 있다.
}
}
const a = fn();
`콘솔창에 입력`
a.next();
a.next();
a.next();
a.next();
yield* 을 사용해서 다른 제너레이터를 불러올 수 있다.
function* fn() {
yield "Y";
yield "O";
yield "N";
yield "G";
}
function* fn2() {
yield "Hello,";
yield* fn(); //yield*로 제너레이터 함수 fn()을 불러온다.
yield "!"; //yield* 오른쪽에는 반복가능한 모든 객체가 올 수 있다.
}
fn2를 구조분해할당으로 콘솔에 출력하여, fn 함수를 yield* 을 사용해 불러온걸 확인할 수 있다.
fn 을 불러올때, done이 true가 될때 까지 (for of문 처럼)값을 불러온다.
-끝-