2023. 3. 31. 00:41ㆍJavascript/자바스크립트 제대로 배워볼래?
섹션 1. 변수 선언
var의 문제점
정의 된 변수가 함수 스코프(변수가 사용될 수 있는 영역 - 변수가 정의된 위치에 의해 결정됨)를 가진다.
함수 스코프이기 때문에, 함수를 벗어난 영역에서 사용하면 에러가 발생한다.
function example() {
var i = 1;
}
console.log(i);
>> 에러가 나게 된다. i 가 정의되지않았다고! 레퍼런스 에러!
프로그램의 가장 바깥에 정의하면 전역변수가 된다.
함수안에서 var를 이용하지않고, 변수에 값을 할당하면 그 변수는 전역변수가 된다.
그래서 다른곳에서도 사용할 수 있게 된다.
function example1() {
i = 1;
}
function example2() {
console.log(i);
}
example1();
example2();
파일 상단에
‘use strict’ 삽입하고 선언하면, 에러가 나서 정확하게 되기는한다!
Var는 함수 스코프라서, for문이 끝났음에도 계속 남아있는 문제가 있다. For, while, …등
함수 내부에서 선언된 모든 것들이 같은 문제를 지니고 있다.
끝나고도 계속 사용할 수 있다는 점
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log('last:', i);
그래서 즉시실행함수를 사용하기도한다.
즉시실행함수는 실행하고, 바로 사라지는데 > 이로 인해 var의 단점을 제한할 수 있다
(function () {
for (var i = 0; i < 10; i++) {
console.log(i);
}
})();
console.log('last:', i);
>> 그래서 에러가 난다.i에서! 마지막줄!
하지만 즉시실행함수는 작성하기도 어렵고 가독성도 낮다는 단점을 가지고있다.
호이스팅 : var는 그 변수가 속한 스코프의 최 상단으로 끌어올려진다.
직관적이지 않으며, 보통 프로그래밍에서도 찾기 힘든 기능
console.log(myVar);
var myVar = 1;
undefined라고 출력된다.
var myVar = undefined;
console.log(myVar);
myVar = 1;
undefined라고 출력된다.
console.log(myVar);
myVar = 2;
console.log(myVar);
var myVar = 1;
undefined
2
한번 정의한 것을 또 정의 가능 > 직관적이지 않으며, 버그로 이어지기 쉬움
var myVar = 1;
var myVar = 2;
상수처럼 쓸 값도, 무조건 재할당 가능한 변수로 만들어짐.
var PI = 3.141592;
PI = 123;
Const, Let
블록 스코프
if문안에서 정의된 것은, 벗어나면 참조 불가능
let foo = 'bar1';
console.log(foo);
if (true) {
let foo = 'bar2';
console.log(foo);
}
console.log(foo);
/*
bar1
bar2
bar1
*/
const, let 도 호이스팅이 된다!!!
하지만, 변수 선언전 참조하려면 에러는 나는데 >> 레퍼런스 에러 >> var는 에러는 안남
console.log(foo);
const foo = 1;
// ReferenceError: Cannot access 'foo' before initialization
const foo = 1;
{
console.log(foo);
const foo = 2;
}
var는 undefined가 된다면, let과 const는 아무 값도 할당되지 않음
var foo = 1;
(function () {
console.log(foo);
var foo = 2;
})();
//undefined
??????????? 이건 왜이러는걸까????????
const로 정의된 변수는 재할당이 불가능하다.
하지만 let은 재할당 가능
재할당이 불가능 변수는 프로그램의 복잡도를 낮춰주기에 되도록이면 재할당 불가능한 변수를 사용하는게 좋음
const bar = 'a';
bar = 'b'; // error
var foo = 'a';
foo = 'b';
let value = 'a';
value = 'b';
하지만, const로 정의된 객체의 내부 속성값은 수정 가능하다!
수정 및 추가 가능!
const bar = { prop1: 'a' };
bar.prop1 = 'b';
bar.prop2 = 123;
console.log(bar);
const arr = [10, 20];
arr[0] = 100;
arr.push(300);
console.log(arr);
/*
{ prop1: 'b', prop2: 123 }
[ 100, 20, 300 ]
*/
혹시 속성값도 변경 못하게 하고 싶다면, immer와 같은 외부 패키지를 사용하면 된다.
이는 기존 객체를 수정하지않고, 새로운 객체를 생성한다.
수정만 못하게 하고싶다면, 자바스크립트 내장함수를 이용하면 된다.
ex)
Object.preventExtensions
Object.seal
Object.freeze
'use strict';
const bar = Object.freeze({ prop1: 'a' });
bar.prop1 = 'b';
console.log(bar);
/*
bar.prop1 = 'b';
^
이렇게 에러가 난다.
*/
변수 자체를 변경하는 것 또한 불가능하다.
const bar = { prop1: 'a' };
bar = { prop2: 123 };
/*
bar = { prop2: 123 };
^
*/
섹션 2. 타입
8가지 기본 타입
console.log(10 + 5);
console.log('10' + '5');
/*
15
105
*/
// 자바스크립트의 8가지 기본 타입
// number, bigint, string, boolean, object, symbol, undefined, null
const v1 = 12;
const v2 = 123456789123456789123456789n;
const v3 = 'ab';
const v4 = true;
console.log(typeof v1, typeof v2, typeof v3, typeof v4);
const v5 = {};
const v6 = Symbol('abc');
const v7 = undefined;
const v8 = null; //object
console.log(typeof v5, typeof v6, typeof v7, typeof v8);
/*
number bigint string boolean
object symbol undefined object
*/
function f1() {}
console.log(typeof f1);
class MyClass {}
console.log(typeof MyClass);
/*
function
function
*/
typeof로 null을 구분할 수 없다고했는데, Object.prototype.toString를 이용해 알 수 있다..
console.log(Object.prototype.toString.call(null));
console.log(typeof []);
console.log(Object.prototype.toString.call([]));
/*
[object Null]
object
[object Array]
*/
Symbol은 유일한 속성 이름을 만들 때 사용 > 이름 충돌의 문제를 해결
const idSymbol = Symbol('id');
const obj = { id: 123 };
obj[idSymbol] = 456;
console.log(obj);
const arr = [];
console.log(arr[Symbol.iterator]);
/*
{ id: 123, [Symbol(id)]: 456 }
[Function: values]
*/
console.log(global[Symbol.toStringTag]);
// console.log(window[Symbol.toStringTag]);
console.log(Object.prototype.toString.call(global));
const person = {
[Symbol.toStringTag]: 'Person',
};
console.log(Object.prototype.toString.call(person));
/*
global
[object global]
[object Person]
*/
// String, Number, BigInt, Boolean
const v1 = String(123);
const v2 = String(new Date());
console.log(typeof v1, v1);
console.log(typeof v2, v2);
const v3 = Number('123');
const v4 = BigInt('123');
console.log(typeof v3, v3);
console.log(typeof v4, v4);
/*
string 123
string Thu Mar 30 2023 22:49:31 GMT+0900 (대한민국 표준시)
number 123
bigint 123n
*/
const v1 = Boolean(123);
const v2 = Boolean(0);
console.log(typeof v1, v1);
console.log(typeof v2, v2);
const v3 = Boolean('abc');
const v4 = Boolean('');
console.log(typeof v3, v3);
console.log(typeof v4, v4);
const v11 = !!123;
const v12 = !!0;
const v13 = !!'abc';
const v14 = !!'';
console.log(typeof v11, v11);
console.log(typeof v12, v12);
console.log(typeof v13, v13);
console.log(typeof v14, v14);
/*
boolean true
boolean false
boolean true
boolean false
boolean true
boolean false
boolean true
boolean false
*/
new 키워드를 사용하면 object로 만들어진다.
console.log(typeof new Boolean(true));
console.log(typeof new Number(1));
console.log(typeof new String('abc'));
const s1 = new String('abc');
s1.id = 123;
console.log('value:', s1.valueOf());
console.log('id:', s1.id);
/*
object
object
object
value: abc
id: 123
*/
console.log(123 === 123);
console.log('123' === '123');
console.log('123' === 123);
console.log(0 === false);
console.log(123 === true);
console.log(123 == 123);
console.log('123' == '123');
console.log('123' == 123);
console.log(0 == false);
console.log(123 == true);
/*
true
true
false
false
false
true
true
true
true
false
*/
number 타입
console.log(Number.parseInt('123'));
console.log(Number.parseInt('123.456'));
console.log(Number.parseInt('123abc'));
console.log(Number.parseFloat('123'));
console.log(Number.parseFloat('123.456'));
console.log(Number.parseFloat('123abc'));
console.log(Number.parseFloat('123.456.789')); //123.456
/*
123
123
123
123
123.456
123
123.456
*/
const v = Number.parseInt('abc');
console.log(v);
console.log('v', Number.isNaN(v));
console.log('123', Number.isNaN(123));
/*
NaN
v true
123 false
*/
const v = 1 / 0;
console.log(v);
console.log('Infinity', v === Infinity);
console.log('Number.isFinite', Number.isFinite(v));
/*
Infinity
Infinity true
Number.isFinite false
*/
// ArrayBuffer
// 자바스크립트 number => 64 bit 부동소수점(floating point)
// 부호(sign) 1 bit, 지수부(exponent) 11 bits, 가수부(fraction) 52 bits
// (-1)^부호 * 가수부 * 10^지수부
// 53 bits precision
// https://en.wikipedia.org/wiki/Double-precision_floating-point_format
// -(2^53 - 1) ~ (2^53 - 1)
// 9007199254740991, 약 16자리
console.log(Math.pow(2, 53) - 1);
console.log(Number.MIN_SAFE_INTEGER);
console.log(Number.MAX_SAFE_INTEGER);
/*
9007199254740991
-9007199254740991
9007199254740991
*/
// Number.MAX_SAFE_INTEGER = 9007199254740991
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER));
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1));
console.log(9007199254740995 - 10);
console.log(9007199254740995n - 10n);
/*
true
false
9007199254740986
9007199254740985n
*/
const a = 9007199254740995;
const b = 10;
const result = a - b;
console.log(
Number.isSafeInteger(a),
Number.isSafeInteger(b),
Number.isSafeInteger(result),
);
console.log('9007199254740995 - 10 =', result);
/*
false true true
9007199254740995 - 10 = 9007199254740986
*/
const a = 9007199254740991;
const b = 10;
const result = a - b;
console.log(
Number.isSafeInteger(a),
Number.isSafeInteger(b),
Number.isSafeInteger(result),
);
console.log('9007199254740991 - 10 =', result);
/*
true true true
9007199254740991 - 10 = 9007199254740981
*/
console.log(0.1 + 0.2 === 0.3);
console.log(0.1 + 0.2);
/*
false
0.30000000000000004
*/
console.log(Number.EPSILON); // 매우 작은 숫자
function isSimilar(x, y) {
return Math.abs(x - y) < Number.EPSILON;
}
console.log(isSimilar(0.1 + 0.2, 0.3)); // 이 둘의 차이가 아주 적어서 값이 비슷하다 여길 수 있음
/*
2.220446049250313e-16
true
*/
console.log(Math.random());
console.log(Math.max(30, 10, 55));
console.log(Math.pow(5, 3));
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomInt(0, 10));
console.log(getRandomInt(0, 10));
console.log(getRandomInt(0, 10));
/*
0.45452066656077594
55
125
4
0
9
*/
string 타입
const s1 = 'abc';
const s2 = "abcd";
const s3 = `abcde`;
console.log(s1.length,s2.length,s3.length)
//3 4 5
const name = 'mike';
const age = 23;
const text1 = 'name: ' + name + ', age: ' + age;
const text2 = `name: ${name}, age: ${age}`;
console.log(text1);
console.log(text2);
/*
name: mike, age: 23
name: mike, age: 23
*/
const text1 = '할 일 목록\n* 운동하기\n* 요리하기';
console.log(text1);
const text2 = `할 일 목록
* 운동하기
* 요리하기
`;
console.log(text2);
/*
할 일 목록
* 운동하기
* 요리하기
할 일 목록
* 운동하기
* 요리하기
*/
const s1 = 'abcd';
const c1 = s1[1];
console.log(c1);
// 자바스크립트 string => 불변(immutable)!!!!!!!!!
const s2 = 'abcd';
s2[1] = 'z';
console.log(s2); //abcd
const input = 'This is my car. The car is mine';
const output = input.replace('car', 'bike');
console.log({ input, output });
console.log(input.replace(/car/g, 'bike'));
// replaceAll: 비교적 최근에 추가됨
console.log(input.replaceAll('car', 'bike'));
/*
b
abcd
{
input: 'This is my car. The car is mine',
output: 'This is my bike. The car is mine'
}
This is my bike. The bike is mine
This is my bike. The bike is mine
*/
const s1 = 'This is my car. The car is mine';
console.log(s1.includes('car'));
console.log(s1.includes('my car'));
console.log(s1.includes('my car', 10)); // 10부터 검사함
//startsWith로 시작하는지
console.log(s1.startsWith('This is'));
console.log(s1.startsWith('is'));
// endsWith로 끝나는지
console.log(s1.endsWith('mine'));
console.log(s1.endsWith('is'));
/*
true
true
false
true
false
true
false
*/
// substr 시작, 갯수
const s1 = 'This is my car. The car is mine';
console.log(s1.substr(0, 4));
console.log(s1.substr(5, 2));
console.log(s1.substr(16));
// indexOf 입력된 위치
let pos = s1.indexOf(' ');
console.log(s1.substr(0, pos));
// lastIndexOf 뒤에서부터 검색
pos = s1.lastIndexOf(' ');
console.log(s1.substr(pos + 1));
// 시작, 인덱스
console.log(s1.slice(5, 7));
/*
This
is
The car is mine
This
mine
is
*/
const s1 = 'This is my car. The car is mine';
console.log(s1.split(' '));
const arr = s1.split('.');
console.log(arr);
console.log(arr.map(item => item.trim()));
console.log(s1.split(' ').join());
console.log(s1.split(' ').join('..'));
/*
[
'This', 'is',
'my', 'car.',
'The', 'car',
'is', 'mine'
]
[ 'This is my car', ' The car is mine' ]
[ 'This is my car', 'The car is mine' ]
This,is,my,car.,The,car,is,mine
This..is..my..car...The..car..is..mine
*/
console.log('12'.padStart(5, '0'));
console.log('123'.padStart(5, '0'));
console.log('123'.padStart(5, '*'));
console.log('123'.padEnd(5, '*'));
const s1 = 'This is my car. The car is mine';
console.log(s1.match(/T[^\s-]*/g));
/*
00012
00123
**123
123**
[ 'This', 'The' ]
*/
strings는 expressions보다 항상 하나가 더 많다
// tagged template literals
function taggedFunc(strings, ...expressions) {
console.log({ strings, expressions });
return 123;
}
const v1 = 10;
const v2 = 20;
const result = taggedFunc`a-${v1}-b-${v2}`;
console.log({ result });
taggedFunc`a-${v1}-b-${v2}-c`;
taggedFunc`a-${v1}-b-${v2}`;
taggedFunc`${v1}-b-${v2}`;
/*
{ strings: [ 'a-', '-b-', '' ], expressions: [ 10, 20 ] }
{ result: 123 }
{ strings: [ 'a-', '-b-', '-c' ], expressions: [ 10, 20 ] }
{ strings: [ 'a-', '-b-', '' ], expressions: [ 10, 20 ] }
{ strings: [ '', '-b-', '' ], expressions: [ 10, 20 ] }
*/
어렵다...
function highlight(strings, ...expressions) {
return strings.reduce(
(acc, str, i) =>
expressions.length === i
? `${acc}${str}`
: `${acc}${str}<strong>${expressions[i]}</strong>`,
'',
);
}
const v1 = 10;
const v2 = 20;
const result = highlight`a ${v1} b ${v2}`;
console.log(result);
highlight(['a ', ' b ', ''], v1, v2);
/*
a <strong>10</strong> b <strong>20</strong>
*/
boolean 타입, nullish coalescing
const c1 = true;
const c2 = false;
if (c1 && c2) {
console.log('c1 && c2');
}
if (c1 || c2) {
console.log('c1 || c2');
}
/*
c1 || c2
*/
const c1 = 123;
const c2 = 'abc';
if (c1 && c2) {
console.log('c1 && c2');
}
if (c1 || c2) {
console.log('c1 || c2');
}
if (c1 && c2 && 0) {
console.log('c1 && c2 && 0');
}
if (c1 && c2 && NaN) {
console.log('c1 && c2 && NaN');
}
if (c1 && c2 && '') {
console.log(`c1 && c2 && ''`);
}
/*
c1 && c2
c1 || c2
*/
논리 연산자의 결과 값은, 마지막으로 평가 된 값
const c1 = 123;
const c2 = 'abc';
const v1 = c1 && c2;
const v2 = c1 && c2 && 0;
const v3 = c1 && 0 && c2;
console.log({ v1, v2, v3 });
const v4 = c1 || c2;
const v5 = '' || c2;
console.log({ v4, v5 });
const v6 = !!(c1 && 0 && c2);
const v7 = !!(c1 || c2);
console.log({ v6, v7 });
/*
{ v1: 'abc', v2: 0, v3: 0 }
{ v4: 123, v5: 'abc' }
{ v6: false, v7: true }
*/
const c1 = 123;
const c2 = 0;
c1 && console.log('log1');
c2 && console.log('log2');
//log1
const price = 0;
const name = '';
const price2 = price || 1000;
const name2 = name || '이름을 입력해주세요';
nullish coalescing
unknown이 기본값
const person = {};
const name = person.name ?? 'unknown';
const name =
person.name === undefined || person.name === null ? 'unknown' : person.name;
nullish coalescing는 or이랑 비슷하지만
빈 문자열에나, 0에는 기본값이 사용되지않음
빈 문자열을 값으로 이용하고 싶다면 nullish coalescing를 사용하고 ??
사용하고 싶지않고, 기본 값을 가지고싶다면 OR을 사용하면된다. ||
const product = { desc: '', price: 0 };
const descInput = product.desc ?? '상품 설명을 입력하세요';
const priceInput = product.price ?? 1000;
const name = '';
const title = '';
const text = (name || title) ?? 'foo';
// 괄호로 꼭 묶어줘야한다
const name = 'mike';
function getDefaultName() {
console.log('called getDefaultName');
return 'default name';
}
console.log(name ?? getDefaultName()); // 함수는 필요한 경우에만 호출된다.
console.log(name || getDefaultName());
//하나씩 출력함 >>이름을
/*
mike
mike
*/
호출이 안된다.
빈 문자열의 경우 호출 됨
const name = '';
function getDefaultName() {
console.log('called getDefaultName');
return 'default name';
}
console.log(name ?? getDefaultName()); // 출력 안함
console.log(name || getDefaultName()); //얘가 다 출력함
/*
called getDefaultName
default name
*/
🌸 Nullish coalescing operator 이란?
- 변수에 다른 변수값을 대입할 때, 변수값이 null나 undefined라면 그 ??의 오른쪽 값을 대입한다.
- 쉽게 말해 OR(||) 연산자라고 생각할 수 있다.
const a = b ?? "age"
- 위와 같은 코드가 있을 때, b가 유효한 변수라면 그 값을 a에 대입한다.
- 만약 b가 null이거나 undefined이라면 그 뒤에 있는 age 문자열을 a에 대입한다.
출처 : https://velog.io/@devgosunman/Nullish-coalescing-operator-%EC%97%B0%EC%82%B0%EC%9E%90
💡 Nullish coalescing operator, '??' 연산자
변수에 다른 변수값을 대입할 때, 변수값이 `null`나 `undefined`라면 그 `??`의 오른쪽 값을 대입한다. 쉽게 말해 `OR(||)` 연산자라고 생각할 수 있다.
velog.io
object 타입, array
const obj = {
age: 21,
name: 'mike',
};
const obj2 = new Object({
age: 21,
name: 'mike',
});
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj));
for (const [key, value] of Object.entries(obj)) {
console.log(key, value);
}
/*
[ 'age', 'name' ]
[ 21, 'mike' ]
[ [ 'age', 21 ], [ 'name', 'mike' ] ]
age 21
name mike
*/
const obj = {
age: 21,
name: 'mike',
};
obj.city = 'seoul';
obj.age = 30;
console.log(obj);
delete obj.city;
console.log(obj);
delete obj['name'];
console.log(obj);
/*
{ age: 30, name: 'mike', city: 'seoul' }
{ age: 30, name: 'mike' }
{ age: 30 }
*/
const arr = [1, 2, 3];
const arr2 = new Array(1, 2, 3);
console.log(typeof arr === 'object');
console.log(Object.values(arr));
console.log(arr.map(item => item + 1));
console.log(arr.filter(item => item >= 2));
console.log(arr.reduce((acc, item) => acc + item, 0));
/*
true
[ 1, 2, 3 ]
[ 2, 3, 4 ]
[ 2, 3 ]
6
*/
const arr = [1, 2, 3];
arr.forEach(item => console.log(item));
for (const item of arr) {
console.log(item);
}
console.log(arr.some(item => item === 2));
console.log(arr.every(item => item === 2));
console.log(arr.includes(2));
console.log(arr.find(item => item % 2 === 1));
console.log(arr.findIndex(item => item % 2 === 1));
/*
1
2
3
1
2
3
true
false
true
1
0
*/
const arr = [1, 2, 3];
// arr.push(4);
// console.log(arr.pop());
// console.log(arr);
arr.splice(1, 1); // 1번에서 1개 삭제
console.log(arr);
arr.splice(1, 0, 10, 20, 30); // 1번에서 0개 삭제후 뒤에거 추가
console.log(arr);
arr.splice(1, 3, 40, 50);
console.log(arr);
arr.sort(); //오름차순
console.log(arr);
arr.sort((a, b) => (a % 10) - (b % 10)); // 1의자리숫자비교
console.log(arr);
/*
[ 1, 3 ]
[ 1, 10, 20, 30, 3 ]
[ 1, 40, 50, 3 ]
[ 1, 3, 40, 50 ]
[ 40, 50, 1, 3 ]
*/
섹션 3. 객체와 배열의 주요 기능
spread operator 및 몇 가지 편의 기능
const name = 'mike';
const obj = {
age: 21,
name,
getName() {
return this.name;
},
};
단축속성명 - name:name했어야하는데, getName: function getName(){ } 해야하는데 간단스 ㅠ
function makePerson1(age, name) {
return { age: age, name: name };
}
function makePerson2(age, name) {
return { age, name };
}
const name = 'mike';
const age = 21;
console.log(name, age);
console.log('name =', name, ', age =', age);
console.log({ name, age });
/*
mike 21
name = mike , age = 21
{ name: 'mike', age: 21 }
*/
계산된속성명
function makeObject1(key, value) {
const obj = {};
obj[key] = value;
return obj;
}
function makeObject2(key, value) {
return { [key]: value };
}
Math.max(1, 3, 7, 9);
const numbers = [1, 3, 7, 9];
Math.max(...numbers);
const arr1 = [1, 2, 3];
const obj1 = { age: 23, name: 'mike' };
const arr2 = [...arr1];
const obj2 = { ...obj1 };
arr2.push(4);
obj2.age = 80;
[1, ...[2, 3], 4]; // [1, 2, 3, 4]
new Date(...[2018, 11, 24]); // 2018년 12월 24일
const obj1 = { age: 21, name: 'mike' };
const obj2 = { hobby: 'soccer' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
// { age: 21, name: 'mike', hobby: 'soccer' }
변경하고싶은거만 입력하면 바뀜
const obj1 = { x: 1, x: 2, y: 'a' };
const obj2 = { ...obj1, y: 'b' };
console.log({ obj1, obj2 });
// { obj1: { x: 2, y: 'a' }, obj2: { x: 2, y: 'b' } }
destructuring (비구조화문법)
const arr = [1, 2];
const [a, b] = arr;
console.log(a);
console.log(b);
/*
1
2
*/
let a, b;
[a, b] = [1, 2];
const arr = [1];
const [a = 10, b = 20] = arr;
console.log({ a, b });
//{ a: 1, b: 20 }
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log({ a, b });
// { a: 2, b: 1 }
건너뛰고 싶은 만큼 , 로 뛰어넘으면된다.
const arr = [1, 2, 3];
const [a, , c] = arr;
console.log({ a, c });
// { a: 1, c: 3 }
첫번째 빼고 남는것 rest1에 넣게됨
const arr = [1, 2, 3];
const [first, ...rest1] = arr;
console.log(rest1);
const [a, b, c, ...rest2] = arr;
console.log(rest2);
/*
[ 2, 3 ]
[]
*/
객체의 비구조화
const obj = { age: 21, name: 'mike' };
const { age, name } = obj;
console.log({ age, name });
//{ age: 21, name: 'mike' }
순서는 상관없음, 없던거라면 undefined
const obj = { age: 21, name: 'mike' };
const { age, name } = obj;
const { name, age } = obj;
const { a, b } = obj;
const obj = { age: 21, name: 'mike' };
const { age: theAge, name } = obj;
console.log(theAge);
console.log(age);
/*
console.log(age);
^
ReferenceError: age is not defined
*/
원래 값이 undefined인 경우만, 기본값이 할당이된다.
null인 경우 안됨!
const obj = { age: undefined, name: null, grade: 'A' };
const { age = 0, name = 'noName', grade = 'F' } = obj;
console.log({ age, name, grade });
// { age: 0, name: null, grade: 'A' }
속성값 이름을 변경하면서 동시에 기본값도 정의가능
const obj = { age: undefined, name: 'mike' };
const { age: theAge = 0, name } = obj;
기본값으로 함수의 반환값을 넣을수 있는데
기본값이 사용될 때만 함수가 호출된다.
age가 undefined일때만 함수가 호출됨 안될때는 그 기존에 되어있던 값을 그대로 들옴
function getDefaultAge() {
console.log('hello');
return 0;
}
const obj = { age: undefined, grade: 'A' };
const { age = getDefaultAge(), grade } = obj;
console.log(age);
/*
hello
0
*/
const obj = { age: 21, name: 'mike', grade: 'A' };
const { age, ...rest } = obj;
console.log(rest);
/*
{ name: 'mike', grade: 'A' }
*/
const people = [
{ age: 21, name: 'mike' },
{ age: 51, name: 'sara' },
];
for (const { age, name } of people) {
// ...
}
const obj = { name: 'mike', mother: { name: 'sara' } };
const {
name,
mother: { name: motherName },
} = obj;
console.log({ name, motherName }); //{ name: 'mike', motherName: 'sara' }
console.log(mother);
/*
console.log(mother);
^
ReferenceError: mother is not defined
*/
const [{ prop: x } = { prop: 123 }] = []; // 배열의 첫번째, 아이템이 없기에 들어감
console.log(x); //123
const [{ prop: x } = { prop: 123 }] = [{}]; //아이템이 하나있어서 기본값이 사용되지않음, prop사용값이없음
console.log(x); //undefined
const index = 1;
const { [`key${index}`]: valueOfTheIndex } = { key1: 123 };
console.log(valueOfTheIndex);
// 123
const obj = {};
const arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
console.log(obj);
console.log(arr);
/*
{ prop: 123 }
[ true ]
*/
optional chaining
const person = null;
const name = person.name;
/*
null이기 때문에 에러가 나타나게 된다
const name = person.name;
^
TypeError: Cannot read properties of null (reading 'name')
*/
const person = null;
// 에러가 발생하지 않도록 하기위해 앞에서 검사하는방법도 있지만,
const name = person && person.name; // null
// optional chaning을 사용하여 간단하게 검사할수도있다.
const name2 = person?.name; // undefined
const name = person?.name;
const name = person === null || person === undefined ? undefined : person.name;
const person = {
getName: () => 'abc',
};
const name = person.getName?.();
console.log(name); // abc
const person = {
// getName: () => 'abc',
};
const name = person.getName?.();
console.log(name); //undefined
/*
함수 호출 시, optional chaining 사용하는 것은
함수를 매개변수로 받아서
호출할 때 유용하게 사용될 수 있다.
매개변수가 optional일때 아래와 같이 사용
그러면, 함수를 입력하지않은 경우에도 문제없이 실행됨
*/
function loadData(onComplete) {
console.log('loading...');
onComplete?.();
}
loadData();
// loading...
/*
배열의 아이템 접근에도 사용됨
index전에 ?.를 입력하면됨
optional chaining사용하지않으면, runtime error가 발생함
*/
const person = { friends: null, mother: null };
const firstFriend = person.friends?.[0];
// 일반 객체에서 동적으로 속성값 이름을 입력할 때에도 이렇게 입력하면됨
const prop = 'name';
const name = person.mother?.[prop];
const name =
person &&
person.friends &&
person.friends[0] &&
person.friends[0].mother &&
person.friends[0].mother.name;
const name2 = person?.friends?.[0]?.mother?.name;
const person = {};
const name = person?.friends?.[0]?.mother?.name ?? 'default name';
/*
??은 nullish coalescing
?.은 ?? 와 함께 쓰기 좋음
??로 부터의 기본값을 쓸수있도록 하면 좋지
*/
'Javascript > 자바스크립트 제대로 배워볼래?' 카테고리의 다른 글
4-04.데이터테이블 만들기 (0) | 2023.03.30 |
---|---|
4-03.HTML 스타일 컨트롤 (0) | 2023.03.30 |
4-02.HTML 이벤트 컨트롤 (0) | 2023.03.30 |
4-01.HTML Element 컨트롤 (0) | 2023.03.30 |
3-17.정규식(RegExp) (0) | 2023.03.30 |