자바스크립트 koans 풀이를 하며 처음 본 내용과 헷갈렸던 부분이 있어
이러한 부분들에 대해 추가 학습을 통해 알게 된 것을 정리 해 보았습니다.
var 변수 선언
과 함수 선언문
에서만 호이스팅이 일어난다.var 변수
/함수의 선언
만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.var
와 let/const
변수의 차이console.log('test');
var str = 'hello'; // var 변수
let str2 = 'hi'; // let 변수
const arr = [0, 1, 2]; // const 변수
// -- 위와 같이 코드를 작성했을 때, JS Parser 내부의 호이스팅의 결과는 아래와 같다 --
var str; // str 변수의 선언만 끌어 올려짐
console.log('test');
str = 'hello'; // str 변수에 값 할당
let str2 = 'hi'; // let 변수는 호이스팅이 일어나지 않음
const arr = [0, 1, 2]; // const 변수도 호이스팅이 일어나지 않음
// 일반적인 순서로 작성된 코드
function catName(name) {
console.log("우리 집 고양이의 이름은 " + name + "입니다");
}
catName("카레");
/*
결과: "우리 집 고양이의 이름은 카레입니다"
*/
// 함수를 선언하기 전에 호출한 경우
catName("카레");
function catName(name) {
console.log("우리 집 고양이의 이름은 " + name + "입니다");
} // 함수선언문에서 호이스팅이 일어난다
// 결과: "우리 집 고양이의 이름은 카레입니다"
❗️함수가 “선언” 되었을 경우에만 코드의 최상단으로 옮겨지기 때문에 함수표현식으로 작성된 함수는 호이스팅이 되지 않는다.catName("카레");
const catName = function(name) {
console.log("우리 집 고양이의 이름은 " + name + "입니다");
} // 함수표현식은 호이스팅이 되지 않음
// 결과: Cannot access 'catName' before initialization
⛔ 최대한 호이스팅이 일어나지 않도록 코드를 작성하는 것이 좋다. (남들이 볼 때 한 눈에 이해가 가도록!)
year
: 연도를 나타내는 정수 값입니다.0
부터 99
까지는 1900
부터 1999
로 처리합니다. 다른 모든 값은 그대로 사용합니다.monthIndex
: 월을 나타내는 정수 값입니다. 1월을 나타내는 0
부터 12월을 나타내는 11
까지 사용할 수 있습니다.day
(Optional): 일을 나타내는 정수 값입니다. 기본값은 1
입니다.hours
(Optional): 시를 나타내는 정수 값입니다. 기본 값은 자정을 나타내는 0
입니다.minutes
(Optional): 분을 나타내는 정수 값입니다. 기본 값은 정각을 나타내는 0
입니다.seconds
(Optional): 초를 나타내는 정수 값입니다. 기본 값은 0
초입니다.milliseconds
(Optional): 밀리초를 나타내는 정수 값입니다. 기본 값은 0
밀리초입니다.// Date 객체를 생성하는 여러가지 방법
let today = new Date()
let birthday = new Date('December 17, 1995 03:24:00')
let birthday2 = new Date('1995-12-17T03:24:00')
// 월은 0부터 시작하므로 12월로 생성하고 싶다면 값을 11로 제공
let birthday3 = new Date(1995, 11, 17)
let birthday4 = new Date(1995, 11, 17, 3, 24, 0)
const currentYear = new Date().getFullYear();
currentYear // 2023
const birthday = new Date(1995, 1, 13).getFullYear();
birthday // 1995
메소드는 어떠한 객체의 속성으로 정의된 함수이고,
메소드가 호출될 때 그 ‘어떠한 객체’를 묻는 것이 this 이다.
// 예시로, obj이라는 객체 안에 foo라는 메서드를 선언하고, this를 반환한다고 했을 때
let obj = {
foo: function() {
return this
}
};
console.log(obj.foo() === obj) // true
But❗️ 화살표 함수에서의 this는 다르다.
우선, 화살표 함수는 자신의 this가 없다.
화살표 함수에서의 this는 자신을 감싼 정적 범위(lexical context) 이다. (전역에서는 전역 객체를 가리킴)
const cat = {
name: 'meow',
foo1: function() {
const foo2 = () => {
console.log(this.name);
/*
화살표 함수는 자신의 this가 없으며, 화살표 함수 자신을 감싼 상위 환경에서의 this를 참조한다
(내부 스코프에서 변수를 찾는 방식과 유사)
*/
}
foo2();
}
};
cat.foo1(); // meow
arguments
객체는 함수에 전달된 인수에 해당하는 Array
형태의 객체로,arguments
를 통해 spread syntax
와 비슷하게 함수의 전달인자들을 다룰 수 있다. (spread syntax
도입 이전 사용)arguments
는 모든 함수의 실행 시 자동으로 생성되는 '객체'이며, 생성된 객체의 key는 0부터 순서대로 붙는다.function getAllParamsByArgumentsObj() {
return arguments;
};
const arg = getAllParamsByArgumentsObj('first', 'second', 'third');
arg // { [Iterator] 0: 'first', 1: 'second', 2: 'third' }
// Object.keys()는 해당 객체의 속성 이름을 배열로 반환
// Object.values()는 해당 객체의 속성 값을 배열로 반환
console.log(Object.keys(arg)) // [ '0', '1', '2' ]
console.log(Object.values(arg)) // [ 'first', 'second', 'third' ]
// 구문: 문자열.repeat(횟수)
'abc'.repeat(-1) // RangeError
'abc'.repeat(0) // ''
'abc'.repeat(1) // 'abc'
'abc'.repeat(2) // 'abcabc'
Object.assign() 메소드는 소스(출처)객체의 열거 가능한 속성만을 타겟(목표)객체로 복사한다.
빈 객체에 복사할 원본 객체를 넣어줌으로써 깊은 복사와 유사하게 복사할 수 있다.
다만, 중첩 객체가 있는 경우 문제점이 발생한다.
let original = {
a: 1,
b: {
c: 2,
},
}
// Object.assign() 메소드를 사용하여 빈 객체에 original를 복사해 clone에 할당
let clone = Object.assign({}, original);
console.log(clone); // { a: 1, b: { c: 2 } }
original.a = 10;
console.log(original); // { a: 10, b: { c: 2 } }
console.log(clone); // { a: 1, b: { c: 2 } }
clone.a = 20;
console.log(original); // { a: 10, b: { c: 2 } }
console.log(clone); // { a: 20, b: { c: 2 } }
// 이 위 까지는 original와 clone의 주소값이 다르므로 각각 변경이 되었는데,
clone.b.c = 30;
console.log(original); // { a: 10, b: { c: 30 } }
console.log(clone); // { a: 20, b: { c: 30 } }
// 여기에서는 두 객체의 b 프로퍼티의 안에 있는 c 프로퍼티의 값이 모두 수정이 되었다.
// 왜? -> b 프로퍼티는 복사 시 고유한 값을 가지는게 아닌 같은 주소값을 가지기 때문에 (얕은 복사)
// 두 객체 중 하나의 객체가 변하면 나머지 객체도 변하게 된다.
객체를 복사할 때 중첩 객체까지 깊은 복사를 하려면?
→ 여러 방법이 있지만 그 중 하나인 structuredClone() 메서드를 활용하면 된다.
// 구문: structuredClone(복사 대상인 원본 객체)
const original = { a: 1, b: { c: 2 }, d: [ 3, 4, 5] };
const clone = structuredClone(original);
console.log(clone) // { a: 1, b: { c: 2 }, d: [ 3, 4, 5 ] }
clone.a = 5;
console.log(original); // { a: 1, b: { c: 2 }, d: [ 3, 4, 5 ] }
console.log(clone); // { a: 5, b: { c: 2 }, d: [ 3, 4, 5 ] }
original.b.c = 30;
original.d[0] = 'change';
console.log(original); // { a: 1, b: { c: 30 }, d: [ 'change', 4, 5 ] }
console.log(clone); // { a: 1, b: { c: 2 }, d: [ 3, 4, 5 ] }
const name = "김코딩";
const age = 28;
const person = {
name,
age,
level: "Junior",
};
console.log(person) // { name: "김코딩", age: 28, level: "Junior" }
console.log(person.name === { name }.name); // true
// 객체 분해 시 나머지 매개변수로 받은 arguments는 객체로 할당됨
const student = { name: "최초보", major: "물리학과" };
const { name, ...args } = student;
name // "최초보"
args // { major: "물리학과" }
const student = {
name: "최초보",
major: "물리학과",
lesson: "양자역학",
grade: "B+",
};
// name은 name의 속성 값, grade는 grade의 속성 값, *course는 lesson의 속성 값*
function getSummary({ name, lesson: course, grade }) {
return `${name}님은 ${grade}의 성적으로 ${course}을 수강했습니다`;
}
getSummary(student) // "최초보님은 B+의 성적으로 양자역학을 수강했습니다"