YDNJSY Get Started - 3. Digging to the Roots of JS

코스·2020년 11월 5일
1

You Don't Know JS Yet

목록 보기
3/8
post-thumbnail

Hits

이 시리즈는 You Don't Know JS Yet (1판인 You Don't Know JS의 개정판) 을 가지고 스터디를 진행하면서 요약 정리한 글입니다. 내용에 대한 퀴즈도 깃헙 리포지토리에 올리고 있으니 참고하시면 더 도움이 되실 것 같습니다. 내용에 대해 오류가 있거나 궁금하신 점이 있다면 댓글 달아주세요!

Iteration

프로그램을 만드는 가장 큰 이유는 데이터를 처리하기 위함인데, 데이터를 통째로 처리하는 것이 이해하기 쉽겠지만 데이터가 엄청 클 경우에는 통째로 처리하는것은 어렵습니다. 결국에는 데이터 묶음을 하나하나 처리해야 하는데 이를 처리하는 방식이 iteration 기법입니다. 이때 iteration에 넣는 데이터 묶음을 iterable라고 합니다.

doSomething( ...it );
var vals = [ ...it ];

다른 언어에서 사용하는것 처럼 for..of를 사용해 iterable를 하나하나 처리할 수 있습니다. 특히나 JS에서의 특수한 문법은 바로 Spread인데, iterable를 말 그대로 '뿌려서' 사용할 수 있습니다. 다양하게 활용할 수 있는데 위 코드와 같이 함수에 여러 매개변수를 넣을 때 iterable를 하나하나 나눠서 넣는 것과 같은 작업을 할 수 있고, iterable를 deep copy할때에도 Spread를 사용해 복사할 수 있습니다.

var buttonNames = new Map();
buttonNames.set(btn1,"Button 1");
buttonNames.set(btn2,"Button 2");

for (let [btn,btnName] of buttonNames) {
  btn.addEventListener("click", function(){
    console.log(`Clicked ${ btnName }`);
  });
}

Iterable에는 배열, 문자열, 맵등이 있습니다. 특히 맵을 iterator를 통해 처리될 땐 key와 value가 둘다 가지고 있는 새로운 entry로 데이터를 처리합니다. 위 코드에서 buttonNames에는 DOM Element인 btn을 키로, 이름 문자열을 값으로 가진 맵인데 이를 for..of로 사용하기 위해 대괄호 안에 btnbtnName을 넣어 entry내 값을 두 값에 할당합니다. 이를 'array destructuring'라고 하고, 주로 iterator에서 많이 활용되는 기법중 하나입니다.

Closure

Closure을 책에서 이렇게 정의하고 있습니다.

Closure is when a function remembers and continues to access variables from outside its scope, even when the function is executed in a different scope.

정리하자면, 스코프 밖으로 나가도 일부 값들이 남아있어 밖에서도 값들을 사용할 수 있는 방식을 클로저라고 합니다.

function counter(step = 1) {
  var count = 0;
  return function increaseCount(){
    count = count + step;
    return count;
  };
}

var incBy1 = counter();
var incBy3 = counter(3);

incBy1();       // 1
incBy1();       // 2

incBy3();       // 3
incBy3();       // 6

또한 클로저는 만들 때 마다 새로운 스코프를 가집니다. 위 코드에서 같은 counter() 함수를 사용해도 그 안 step이 다른 것을 저장해 사용되는 것을 확인할 수 있습니다. 또 다른 예시로는 위 map iterator를 보았을 때 for 루프를 통해 addEventListener에 값을 넣어놨는데, 이때 bntName 값은 각각 다르고 이 코드가 작동되는 걸 확인할 수 있습니다.

스코프에 대한 더욱 구체적인 이야기는 YDNJSY 2권 Scope & Closure를 통해 배울 예정입니다.

this Keyword

JS에서 가장 햇갈리는 키워드가 바로 this입니다. this를 호출할 때 마다 용도가 달라지고 내용이 달라지기 때문에 햇갈리기 마련입니다. 여기서 this의 핵심은 코드에서 어떻게 this가 호출되는지에 따라 달라진다는 점입니다. 이와 관련해서는 실행 컨텍스트와 관련이 있는데, 이에 대해서 깊게 다루진 않고 간단하게 this의 원리를 다뤄볼까 합니다.

function classroom(teacher) {
  return function study() {
    console.log(
      `${ teacher } says to study ${ this.topic }`
    );
  };
}
var assignment = classroom("Kyle");

assignment();
// Kyle says to study undefined

var homework = {
    topic: "JS",
    assignment: assignment
};

homework.assignment();
// Kyle says to study JS

var otherHomework = {
    topic: "Math"
};

assignment.call(otherHomework);
// Kyle says to study Math

위 코드가 this를 가장 잘 이해할 수 있는 코드인 것 같습니다. 핵심은 this의 위치가 아니라 코드가 실행되는 위치를 유심히 보시길 바랍니다. classroom()을 호출해 만든 assignment 변수는 study()함수를 받게 되는데 이때 함수 안에 this가 있습니다. 이 this가 코드상으로는 같은 위치에 있지만 실행 위치에 따라 값이 달라집니다. 기본적으로 this는 전역 변수 (브라우저의 경우 window, nodejs의 경우 global)을 가지기 때문에 아무련 연관이 없게 된다면 이 전역변수를 가지게 됩니다. assignment를 처음으로 실행할 때엔 아무런 연관이 없기 때문에 windowglobaltopic이 없기 때문에 undefined가 나오게 되는 것입니다.

다만 아래 두 예시와 같이 실행할 때 연관을 짓게 된다면 this가 변경하게 되는데, homework의 경우에는 homework.assignment()을 실행할 때 앞에 있는 homework가 연관이 있음으로 이때 thishomework가 할당되게 됩니다. 그래서 JS가 출력되는 것입니다. 다른 연관을 짓는 방법으로는 call()을 사용하는 것입니다. 함수 매개변수에 this에 연관시키고 싶은 객체를 넣어놓는다면 다음과 같이 otherHomeworkthis에 할당되게 됩니다.

Prototypes

this가 함수에서의 특성이라면 객체에서의 대표적인 특성은 Prototype입니다. Prototype는 객체 간 관계를 연결하는 특성이라고 생각하시면 될 것 같습니다. 기본적으로 모든 객체는 object.prototype을 Prototype로 가지게 됩니다. 다만 새롭게 프로토타입을 연결하고 싶다면 Object.create()를 통해 관계를 만들 수 있습니다.

var homework = {
    topic: "JS"
};

var otherHomework = Object.create(homework);

otherHomework.topic;   // "JS"

otherHomework.topic = "Math";
otherHomework.topic;   // "Math"

homework.topic;        // "JS"

위 코드와 사진을 보면, otherHomeworkhomework를 통해 만들게 되면서 사진과 같은 Prototype 관계를 가지게 되는 것입니다. 이때 otherHomework의 값을 바꿔도 homework의 값은 바뀌지 않습니다. 이는 직접적으로 참조하는 관계가 아니라 'Prototype'으로 관련되어있기 때문입니다.

profile
잡다한거 하는 개발자

0개의 댓글