프론트엔드 개발을 위한 자바스크립트 [스터디/10기]

Derek·2021년 1월 17일
0

Programmers_JS_Study_FE

목록 보기
1/6
post-thumbnail

안녕하세요, Derek입니다.

벌써 1월 반이 지나갔습니다!
시간 진짜 빠른것 같아요.

요즘 진행되는 작은 과제때문에 약간 업로드가 뜸해졌네요..!
마무리가 잘 되었으니, 추후에 업로드할 게시물 기대해주세요 :)

오늘 글은 꽤 오래전에 등록했던 [스터디/10기] 프론트엔드 개발을 위한 자바스크립트 에 대해서 잠깐 소개 겸, 사전에 풀었던 Quiz를 정리해보고자 합니다.


[스터디/10기] 프론트엔드 개발을 위한 자바스크립트

[스터디/10기] 프론트엔드 개발을 위한 자바스크립트 는요,

4주간 스터디 리더가 당신의 성장을 위한 미션을 매 주 부여합니다.
실무 경험이 풍부한 리더가 당신의 코드를 직접 리뷰하고, 피드백을 나눕니다.
코드에 대해 더 풍부한 의견을 나누기 위해 리뷰어 세 명도 함께합니다.
자바스크립트에 영 자신이 없는 모두에게 추천할게요.

라는 소개로, 온라인으로 4주동안 과제를 부여받고 제출하는 스터디입니다.
이곳, Programmers 사이트에서 확인 하실 수 있어요.
이렇게 크게 4개의 주제를 가지고 미션 및 피드백을 진행 하는 형태입니다.

이는 1월 20일 에 시작이되구요, 그 전에 워밍업으로 진행되었던 퀴즈를 정리해볼까해요.


사전 테스트 Quiz

사전 테스트로는 8개의 퀴즈를 풀어보았어요. 하나하나 정리해볼게요 😉

1. 아래의 코드를 실행하면 무엇이 출력되는가?

function Cat(name, age) {
  this.name = name;
  this.age = age;
}

const tabby1 = Cat("nana", 5);
console.log(tabby1. name);

Derek 답변

"nana" 라는 출력값을 가집니다.

tabby1라는 이름을 가진 Cat 객체를 만들며 속성을 'name''nana'로, 'age'5 로 설정했기 때문입니다.

인줄 알았지만.. 완전히 오답이였습니다.

정답

정답은 '오류가 발생한다'. 입니다.

apply, call, bind 등으로 this에 대해 주입한 상황이 아니고 new 키워드없이 실행한 함수 내 this전역 객체(window)를 바라본다.
this.name = name의 결과는 window.name = name 이라는 이야기.

너무 당연하게 착각을 한 것 같았고, 중요한 사실을 깨달았습니다.

new 키워드가 없이 실행한 함수 내의 this 는 전역, 즉 window 를 가르킨다!


2. 아래의 코드를 실행하면 무엇이 출력되는가?

(function(name) {
  console.log(`hello ${name}`)
}) ("roto")

Derek 답변

"hello roto" 라는 출력값을 가집니다.

IIFE 으로 바로 실행되는 함수로, 인자를 "roto" 를 넘겨주어 바로 실행하게 됩니다.

정답이였습니다!

정답

"hello roto"가 출력된다.

백틱으로 감싼 문자열은 ES6에 있는 template strings라는 문법으로,
즉시 실행 함수 표현(IIFE, Immediately Invoked Function Expression)이라고 하며, 함수를 정의함과 동시에 실행한다.
JavaScript 특성상 변수의 scope는 해당 변수를 감싸고 있는 function에 한정되는데, 이걸 이용해 변수나 함수의 전역화를 최소화 시킬 수 있다.


3. 아래의 코드를 실행하면 무엇이 출력되는가?

var idiots = {
  name : "idiots",
  genre : "punk rock",
  members : {
      roto : {
          memberName : "roto", 
          play : function () {
                      console.log(`band ${this.name} ${this.memberName} play start.`)
      }
     }
    }
  }

idiots.members.roto.play();

Derek 답변

"band undefined roto play start" 라고 출력됩니다.

idiots 객체 안에는 name, genre, members라는 멤버 변수 혹은 객체가 있는데, members 객체안에는 또 roto 라는 객체가, 그 안에는 멤버변수 memberName과 멤버함수 play가 있습니다.

play 함수에서 수행되는 코드는 단순한 출력인데, this를 호출합니다. this는 바로 윗 머리(?)인 roto 객체이므로, roto에는 name이 없어서 undefined 가 출력되고, memberName 에는 선언이 이미 된 "roto" 가 있기때문에, 정상적으로 출력됩니다.

결과는 맞았는데, 제가 생각하는.. 개념이 맞는지 확실하지 않은것 같더라구요.

정답

function scope 관련 문제

정답은 band undefined roto play start. 출력
play 함수의 this 내에는 name이 없기 때문에 undefined가 출력 되는 것

뭐 어느정도 반정도는 맞은것 같네요! 😅

this 에 대한 개념은 다음과 같습니다:

this 를 쓰고 있는 scope에서 그 scope를 호출한 객체


4. 아래 코드의 의도는 perform() 함수를 실행하면, 각 memberperform 을 실행하려고 하는 코드입니다. 실제로 실행시 의도대로 동작하지 않는데, 해당 코드가 본래의 의도대로 실행되게 하는 법에 대해 아는 방법을 모두 나열하고 설명해주세요.

function RockBand(members) {
    this.members = members;
    this.perform = function() {
        setTimeout(function() {
            this.members.forEach(function(member) { member.perform() })
        }, 1000)
    }
}

var theOralCigarettes = new RockBand( [
    {
        name : "takuya",
        perform : function() { console.log("a e u i a e u i")}
    }
])

Derek 답변

RockBandfunction 으로 하지 않고 class 로 하면 되지 않을까, 생각해보았습니다.

제가 아는 선에서 코드를 분석하자면, theOralCigarettes 에는 RockBand 객체가 있습니다.
그 객체는 nameperform() 이라는 함수로 이루어진 객체의 배열입니다.

따라서 function RockBand(members) {...} 에서 members 에는 객체의 배열이 들어가게됩니다.
theOralCigarettes.perform() 을 실행시키면 당연히 setTimeout 함수를 객체의 배열만큼 수행하는 줄 알았는데, 그렇지 않은 것을 보아 제 이해가 잘못됨을 알 수 있었습니다.

기각! 딴소리를 했네요.

정답

맨 아래 theOralCigarettees.perform() 을 실행하는 게 빠졌습니다.

perform 함수 아래 setTimeout 으로 인해 실행되는 함수의 thisRockBandthis 가 아니기 때문에, 참조 오류가 발생

즉, setTimeout 함수 내에서 실행되는 함수에서 this 가 잘못 참조되었다는 뜻이였습니다.

해결법

function RockBand(members) {
  var that = this;
  this.members = members;
  this.perform = function() {
    setTimeout(function(){
      that.members.forEach(function(member){ member.perform() })
    }, 1000)
  }
}

var theOralCigarettes = new RockBand([
  {
    name: 'takuya',
    perform: function() { console.log('a e u i a e u i')}
  }
])

theOralCigarettes.perform();

RockBand 함수의 this 를 변수에 저장하여 넘겨줘서 제대로 실행되게끔 해주게 수정하면 됩니다! :)


5. 아래 코드를 실행하면 숫자가 순차저그로 0부터 4까지 출력되지 않고 모두 5만 출력된다. 왜 그런 현상이 발생하는지, 또 어떻게 수정해야 본래의 의도대로 동작할지 설명해주세요.

const numbers = [1, 2, 3, 4, 5];

for(var i = 0 ; i < numbers.length ; i++) {
      setTimeout(function () {
          console.log(`number index ${i}`)
  }, 3000)
}

Derek 답변

var -> let 으로 바꿉니다. 반복문 내에서 var 가 아닌 let 으로 선언해야합니다.

이유는 다음과 같습니다.

만약 var 로 선언한다면, i 의 값은 계속 변합니다. 즉, i = 0 일때 number index 0 이 3초 후에 출력되어야 하지만, 그 전에 i 값은 계속 증가하니, hoisting 에 의해서 마지막 값인 5로 되어 number index 5 만 5번 찍히게 됩니다.

var 가 아닌 let 이라면, value hoisting 이 일어나지 않기 때문에 해당 문제점을 해결할 수 있습니다.

정답! 완벽하게 맞췄답니다 히히.

정답

전형적인 closure 문제

setTimeout 이 실행되는 시점에는 루프가 이미 끝나있어서 i 는 5가 들어가있어서 생기는 문제

ivar 대신 let 을 쓰는 걸로 해결할 수 있음
혹은 setTimeoutIIFE 로 감싸고, 파라메터로 i 를 넘기는 것으로 해결 가능


6. 아래 구문에서 type"cat""name" 을 한 줄로 출력해주세요.

const users = [
    {
        name : "roto",
        type : "human"
    },
    {
        name : "nana",
        type : "cat"
    },
    {
        name : "chai",
        type : "cat"
    }
]

Derek 답변

function printCats() {
let result = "";
    users.filter(x => {
        if(x.type === "cat") {
            result += `${x.name}, `
        }
  })
result = result.substring(0, result.length - 2);
}

filter 함수를 사용해 원라는 값의 name 속성을 뽑아냈습니다.

정답

function printCats() {
  const userNames = []
  for(let i = 0; i < users.length; i++) {
    if (users[i].type === 'cat') {
      userNames.push(users[i].name);
    }
  }
  console.log(userNames.join(''));
}

혹은, 아래의 방법이 가장 좋을것 같아요! 한줄로 딱 나오는게 dog 멋있어요.

function printCats() {
  console.log(users.filter(user => user.type === 'cat').map(user => user.name).join(''));
}

매번 map 이랑 join 을 사용해서 한줄로 구현하는 것 한번 해보자 하는데, 생각보다 어렵네요 :(


7. var, let, const 의 차이점은?

Derek 답변

5번에서 잠깐 언급한것처럼, 선언 시기에 따라 다른점이 존재합니다.

var 로 선언한 변수는 선언 전에 변수를 사용해도 무방합니다.
letconst 는, 에러가 발생합니다.
이는 var함수 레벨 스코프 이고, letconst블럭 레벨 스코프 이기 때문입니다.

또한, var 는 변수를 또 선언하고 마음대로 지지고 볶을 수 있지만, letconst 는 재선언시 에러가 발생합니다.

const 변수는 선언과 동시에 할당하며, 이 값은 변동 될 수 없습니다.

hoisting 개념을 빌려 설명을 했었습니다. 더 첨언하면, 아래 정답이 더 깔끔합니다!

정답

var : function level scope 를 가지며 이로 인해 호이스팅 현상이 일어난다. 재할당 가능
let : block level scope 를 가지며 재할당이 가능하다.
const : block level scope 를 가지며 재할당이 불가능하다. 그러나 할당된 객체의 함수를 이용해 객체를 변경하는 일은 가능하다.

당연한 사실이지만, 나름 새롭네요! 아래와 같이 const 로 선언된 배열은 함수로 변경이 가능하답니다.

const arr1 = [];
arr1 = [1,2]; // Error!
arr1.push(1); // 가능
arr1.push(2); // 가능

8. 클로저란?

Derek 답변

클로저c++ 과 약간은 비슷하다고 느껴졌습니다.

함수레벨 스코프전역변수 처럼 어디서나 접근가능한 범위를 말하며, 블럭 레벨 스코프for , if , while , function 내에서만 접근 가능한 범위를 말합니다.

호출 스택 과도 약간 연관이 있어보입니다. function play 안에 let number 를 선언하고, 그 함수안에 또 다른 function sum 이 있다면, sum 에서 number 를 쓸순 있지만 sum 함수에서 선언된 그 어떤 변수도 play 함수에선 사용할 수 없습니다.

제가 기존에 다루던 언어인 C++ 과 약간 개념이 비슷해서, 그를 활용해 답변했습니다.

정답

자신의 scope 외부에 있는 것을 가져와 쓰는 것.

예시)

var a = 1;
function hello() {
  console.log(a); // a가 hello function scope에 없는데에도 접근 가능함.
}

??? 당연한거 아닌가.. 싶네요! 뭐 정답은 맞춘 것 같습니다 :)




오늘은 이렇게 1월 20일 에 시작할 프론트엔드 개발을 위한 자바스크립트 소개겸, 사전 퀴즈를 정리해보았습니다!

이제부터 매 주 과제 정리하고 제가 진행현황을 정리해보려고 해요 :)

갑사합니다! 😍

profile
Whereof one cannot speak, thereof one must be silent.

1개의 댓글

comment-user-thumbnail
2022년 10월 12일

스터디에서 코드리뷰 말고도 자바스크립트 문법 강의도 해주시나요?

답글 달기