JS koans

유슬기·2023년 1월 4일
0

프론트엔드

목록 보기
18/64
post-thumbnail

자바스크립트 koans 풀이를 하며 처음 본 내용과 헷갈렸던 부분이 있어
이러한 부분들에 대해 추가 학습을 통해 알게 된 것을 정리 해 보았습니다.

호이스팅(hoisting)

  • 호이스팅이란? JavaScript에서 호이스팅(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다. (뭔 소리..??) → 다시 말해 변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는 것을 말한다.
  • 호이스팅의 대상
    • var 변수 선언함수 선언문에서만 호이스팅이 일어난다.
      • var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
      • let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.
  • varlet/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
    ⛔ 최대한 호이스팅이 일어나지 않도록 코드를 작성하는 것이 좋다. (남들이 볼 때 한 눈에 이해가 가도록!)

new Date()

  • new Date()에 날짜가 없으면 오늘 날짜 기준, 날짜를 입력하면 그 날짜 기준
  • new Date() 메소드로 Date 객체를 생성할 때, 최소 연도와 월이 주어지는 경우 모든 구성 요소(year, monthIndex, day, hours, minutes, seconds, milliseconds)를 모두 매개변수에서 가져온다.
    (Optional)이 붙은 요소는 생략 가능하며, 생략 시 기본 값을 사용한다.
    • 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)

getFullYear()

  • getFullYear() 메소드는 주어진 날짜의 현지 시간 기준 연도를 반환
const currentYear = new Date().getFullYear();
currentYear // 2023

const birthday = new Date(1995, 1, 13).getFullYear();
birthday // 1995

화살표 함수에서의 this

메소드는 어떠한 객체의 속성으로 정의된 함수이고,
메소드가 호출될 때 그 ‘어떠한 객체’를 묻는 것이 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

  • 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' ]

String.repeat()

  • repeat() 메소드는 문자열을 주어진 횟수만큼 반복해 붙인 새로운 문자열을 반환
// 구문: 문자열.repeat(횟수)

'abc'.repeat(-1) // RangeError
'abc'.repeat(0) // ''
'abc'.repeat(1) // 'abc'
'abc'.repeat(2) // 'abcabc'

객체의 얕은 복사, 깊은 복사 (feat. 함정)

  • 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 ] }

객체의 단축(shorthand) 문법

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+의 성적으로 양자역학을 수강했습니다"
profile
아무것도 모르는 코린이

0개의 댓글