Frontend/프로그래머스 FE 데브코스

[DAY 9] VanillaJS를 통한 자바스크립트 기본 역량 강화 I (1)

BeNI 2022. 10. 27. 16:53
728x90
사전 문제 1
function Dog(name, age) {
  this.name = name;
  this.age = age;
}

const dog = Dog('happy', 3);
console.log(dog.name);

위 코드는 오류가 발생하는데, 그이유는

Dog 함수는 반환 값이 없기에 dog엔 undefiend 값이 들어가게 되고, undefined.name을 찾을 수 없기에 오류가 발생한다.

또한 추가로 함수안에 있는 this는 window를 가르키기에 window.name을 찍으면 happy 가 나온다

✅ 왜 this가 window를 가르킬까 ? 

- 그 이유는 함수를 new를 통해 생성하지 않았기 때문이다.

- new를 사용하지 않고 함수를 선언할 시 함수 내부의 this는 window를 가르킨다.

- new를 사용하여 dog 을 생성하면 this는 Dog함수를 가르키게 된다.

 

 

사전 문제 2
(function(name){
  console.log(`Hello, ${name}`)
})('beni');

위 코드는 Hello, beni 가 출력된다.

ㅅ위 처럼 작성하는 함수 방식을 IIFE(즉시실행함수)라고 하는데, 사용하는 이유는 크게 두가지가 있다.

 

  ◼ 전역(window)에 필요없는 변수 생성을 막을 수 있다.

- 즉시실행함수 내부에 변수를 선언할 시, 내부 변수는 전역 변수가 아닌 지역변수로 남는다. 

  따라서 전역스코프가 오염되는 것을 줄일 수 있다.

 

 ◼ privte 변수를 생성할 수 있다.

const person = (function(){
  let age = 24;
  function getAge(){
    return age;
  }
  return { getAge : getAge }
})();

위 코드에서 age는 직접적인 변경이 불가능하며, 접근자함수(getAge)로만 age를 확인할 수있다.

 

 

 사전문제 3

- this의 범위에 대한 문제

var obj = {
  name : "beni",
  obj2 : {
    obj3 : {
      name : "euna",
      newName : function(){ console.log(`${this.name}`)}
    }
  }
}

newName() 함수는 euna를 출력한다.

newName() 함수내 this는 obj3를 가르키기에 beni가 아닌 euna를 가르킨다.

 

 

사전문제 4
function school(students){
  this.students = students;
  this.play = function () {
    setTimeout(function(){
      this.students.forEach(function(student){
        student.play();
      })
    }, 1000)
  }
}

var catholic = new school([
  {
    student: 'beni',
    play: function() {}
  }
});

catholic.perform();

위 문제도 this의 범위에 대한 문제인데, setTimeout() 함수 내 this는 setTimeout() 내 function 을 가르킨다 

따라서 this안에 students가 없기때문에 에러가 발생한다.

 

위 문제를 해결할 수 있는 방법은 크게 3가지가 있다.

 

◼ Arrow Function 이용하기

setTimeout(() => {
   this.students.forEach(function(student){
        student.play();
      })
   }, 1000)

- Arrow Function은 자기 자신의 함수 스코프를 만들지 않고 해당 Arrow Function 상위의 Scope를 가진다.

따라서 this는 school 객체를 가르키게 된다.

 

◼ bind() 이용하기

setTimeout(function(){
      this.students.forEach(function(student){
        student.play();
      })
    }.bind(this), 1000)

- bind() 메서드를 이용하면 this를 지정해 줄수 있다.  

  bind는 새로운 함수를 생성하는 메서드로 위 코드에서의 bind안 this는 school을 가르키기에 

  내부 함수에서 this가 school을 가르키게 된다.

 

◼ 클로저 이용하기

function school(students){
  var that = this;
  this.students = students;
  this.play = function () {
    setTimeout(function(){
      that.students.forEach(function(student){
        student.play();
      })
    }, 1000)
  }
}

- school을 가르키는 속성을 선언해주고 내부에서 사용해주는 방식이다.

 

 

사전문제 5
function counting() {
  let i = 0;
  for(i=0; i<5; i++){
    setTimeout(function (){
      console.log(i);
    }, i*100);
  }
};

counting();

 - 위 코드를 출력하면 5만 5번 출력한다.

- 그 이유는 setTimeout()에 인자로 넘긴 익명함수는 0.1초후에 호출되는데,

  이미 0.1초 동안 반복문은 모두 순회하여 i 가 5가 되버렸기에 이미 5가된 i를 출력하게 되는 것이다.

 

👉 해결방법 1 IIFE(즉시 실행 함수 표현)

function counting() {
  let i = 0;
  for(i=0; i<5; i++){
    (function (number) {
      setTimeout(function (){
        console.log(i);
      }, i*100);
    })(i);
  }
};

counting();

 

👉 해결방법 2 : 매 루프마다 클로저 생성하게 하기

function counting() {
  for(let i=0; i<5; i++){  // var 쓰면 안된다(호이스팅되기때문)
    setTimeout(function (){
      console.log(i);
    }, i*100);
  }
};

counting();

👉 해결방법 3 : forEach 메서드 사용하기

 

 

사전문제 6
var 함수 레벨 스코프
변수 재할당 가능
호이스팅 O
let  블록 레벨 스코프
변수 재할당 가능
const 블록 레벨 스코프
변수 재할당 불가능

* 호이스팅 : function scope상 맨 위로 var 선언이 끌어올라지는 현상

* let과 const가 hosting이 일어나지 않는 것은 아니다. 스코프에 변수가 만들어지고 TDZ(Temporal Dead Zone)이 

  생성되지만, 코드 실행 변수 실제 위치에 도달할 때까지 액세스 할 수 없는 것 (할당되기전에 호출 시 에러남)

 

 

사전문제 7

💡 클로저란 ?

함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될때에도 기억한 스코프에 접근할 수 있게 함

- 은닉화 : 클로저를 이용하여 내부 변수와 함수를 숨길 수 있음

 

 

728x90