HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
💌
JJong’s Archive
/
🌞
JS
/
8. this 등

8. this 등

1.

//error 발생, 원인은 ? function Cat(name, age){ this.name = name; this.age = age; } const tabbt1 = Cat('nana', 7); console.log(tabby1.name);
JS는 this가 일정하지 않다.(동적으로 결합) ⇒ 선언한 곳이 아닌 호출한 곳을 가리킨다.
  • [문제1] 객체 인스턴스를 생성하지 않고, 그러니까 new 생성자를 사용하지 않고 함수를 호출하면 this가 window를 가리키게 됨.
    • window를 가리키면, Cat 함수는 반환 값이 없는 이상 tabbit1은 undefined가 됨. 그리고 undefined의 name을 참조하니 error 발생
  • [해결]
    • new Cat()으로 객체를 생성하면, 함수가 return하는게 없어도 객체를 반환, this는 그 생성된 객체가 되어 변수에 접근해도 입력을 넣어준대로 올바른 값이 나옴
    • new.target 으로 함수 또는 생성자가 new 연산자를 사용하여 호출됐는지를 감지할 수 있음
    • 인스턴스화된 생성자 및 함수에서, new.target은 생성자 또는 함수 참조를 반환.
      • 일반 함수 호출에서는, undefined 을 반환
    • new.target은 new에 의해 호출된 생성자(여기서는 생성자 함수)를 가리킴.
      • new.target은 new 라는 객체의 프로퍼티가 아님.
      • 함수 생성 시 생성되는 것으로 new.target 자체가 내부에서만 작동하는 하나의 변수
 
  • 객체 생성 방법
      1. 객체 초기자 사용
        1. const a = {} 형식
        2. key : 식별자, 속성이름, value: 속성 이름에 할당할 표현식
      1. 생성자 함수 사용 (위 코드와 같이)
        1. 생성자 함수를 작성해서 객체 타입을 정의하고(내부에는 this 사용)
        2. 자신을 프로토타입으로 지정하고 그 객체를 리턴
        3. new 연산자를 사용해 객체 인스턴스를 생성
        4. 일반 함수와 차별점을 두기 위해 함수 이름의 첫글자를 대문자로 권고
      1. Object.create 메서드 사용
        1. 2에서 new 대신 Object.create(객체 이름)을 사용
        2. 1처럼 객체가 선언되어도, 즉 생성자 함수 정의가 없어도 객체의 프로토타입을 지정할 수 있다
 

2.

(function(name) { console.log(`hello ${name}) })('roto')
  • IIFE(Immediately-invoked function expression: 즉시 작동하는 함수식)
    • ()로 함수를 감싸서 실행하는 문법
    • 호출하지 않아도 바로 실행됨
    • IIFE안에 사용된 변수, 함수들은 모두 블럭 바깥에 영향을 줄 수 없다, 밖에서 호출도 불가
      • 즉 블록 안에서만 사용 가능하여 다른 코드와 변수나 함수명 등이 충돌하지 않도록 예방이 가능
      • window를 침범하지 않음, 즉 전역을 오염시키지 않음
  • 변수에 IIFE를 할당하면 함수의 리턴 값이 할당된다. (일반 함수는 함수 자체가 변수에 할당)
 

3.

//앞의 변수가 undefined로 출력, 원인은 ? var idiots = { name: 'idiots', genre: 'punk rock', members: { roto: { memberName: 'roto', play: function() { console.log(`band ${this.name} ${this.memberName} play start`) } } } }
  • 일반 객체에서 this는 자신이 속한 객체를 가리킴
    • 여기 play 값 function에서 this는 play가 속한 roto 객체를 가리킴
    • 따라서 roto가 가지고 있지 않은 name은 undefined, 가지고 있는 memberName은 제대로 출력
  • [해결]
    • ${this.name} → ${idiots.name} 으로 수정
 

4.

//error 발생, 원인은 ? function RockBand(members) { this.members = members; this.perform = function() { setTimeout(function() { this.members.forEach(function(member) { //여기 this에서 오류! member.perform(); }) },1000) } } var theOralCigarettes = new RockBand([ { name: 'takuya', perform: function() { console.log('Sing: a e u i a e u i') } } ]); theOralCigarettes.perform();
  • this가 function을 호출시킨 setTimeout의 this를 가리키게 되어, this.members는 undefined가 된다.
  • 'setTimeout 함수는 명시적으로 항상 전역 객체(window)를 this 바인딩한다
 
  • [해결 - 방법3가지]
  1. arrow function
      • setTimeout 안의 함수를 일반 함수에서 arrow function으로 변경한다.
      • arrow function
        • setTieout(()⇒{})
        • ES6에서 탄생한 것
        • 정적(lexically)으로 결합
          • 항상 상위 스코프에 bind된다.(주의! 화살표 함수는 자신의 this가 없다!)
          • 현재 스코프 : setTimeout, 상위 스코프 : RockBand
        • +) 객체의 값, 즉 메소드로 바로 쓸 순 없다. 반드시 외부 함수로 감싸줘야 한다. IIFE로 대응 ㄱㄴ
  1. bind 사용
      • setTimeout(function().bind(this))
      • bind 함수
        • this 값 및 초기 인수를 사용하여 변경한 원본 함수의 복제본. 즉 새로운 함수를 생성
        • 결국 함수가 가리키는 this를 명시해주어 만든 새로운 함수
        • this 다음에 인자를 차례대로 주면 바인딩된 함수에 인자값을 차례로 배당
  1. 클로저 사용
      • var that = this;를 객체안에 선언하고, setTimeout의 콜백함수에서 this대신 이 that을 써서 명시를 해준다.
       
      • setTimeout은 webApI가 타이머를 실행시키고, 종료되면 매개변수인 콜백함수가 매크로 태스크 큐에 들어간다.
      • 메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있다
      • 여기서 객체는 theOralCigarettes가 아니라 RockBand이다. 즉, this = RockBand이다.
 

5.

//5 number undefined turn! 이 다섯번 반복, 원인은 ? const numbers = [0,1,2,3,4] for(var i = 0; i<numbers.length; i++) { setTimeout(function() { console.log(`[${i}] number ${numbers[i]} turn!`) }, i*1000) }
답 : setTimeout의 콜백함수가 실행될 때는 이미 for문이 종료된 상태인데(콜스택도 빈 상태), 이 때 var의 호이스팅으로 i는 5번 모두 같은 i를 공유하기 때문에, 마지막 i값인 5가 되는 것.
 
  • [해결 - 방법3가지]
  1. setTimeout을 function(idx){}(i)으로 감싸서, 중첩함수를 만든다.
    1. for문 돌 때마다 새로운 function scope 발생, 즉 외부 함수의 매개변수가 매번 달라지므로 내부함수는 마찬가지로 달라진 매개변수를 이용
  1. var → let 으로 변경
    1. 블록 스코프가 되므로 for문 돌때마다 i는 매번 달라짐
  1. for문 → forEach(함수)로 변경
    1. forEach는 for와 다르게 매번 새로운 함수를 만들기 때문에, 각자 다른 i를 이용
 
 

6.

var, let, const의 차이
💡
var : function scope, 변수 재할당 가능 ⇒ 호이스팅 발생 let : block scope, 변수 재할당 가능 const : block scope, 변수 재할당 불가능
  • var는 호이스팅 문제 때문에, ES6부터는 쓰지 않는걸 권장하고 있다.
 
호이스팅?
실행할 때 유효 범위의 맨 위로 선언이 끌어올려지는 것
  • function scope의 특징이다.
  • 즉, 함수 내에 블록에서 var로 변수 등을 선언했다고 해도, 블록 밖에 함수 범위에서 선언이 되어 지는 것이다.
  • 이 때문에 값 할당 전에 호출될 수 있다(값은 undefined)
    • const, let는 할당 전에 먼저 호출되면 에러가 발생
  • 함수 내에 블록들끼리 값이 다 공유 가능하다
따라서 생각지도 못한 버그를 만날 수 있다.
 
  1. 변수의 호이스팅(var, const/let 키워드)
      • 함수 범위 내에서 선언은 위로 올라가지만, 초기 값 할당은 할당된 그 라인에서 이루어짐. 따라서 초기화 전에 사용하면 var는 undefined 할당, const, let는 not defined 에러가 난다.
      • const, let은 범위 밖에 있는 변수 이름과 같은 이름으로 범위 안에 변수를 선언해도, 밖에 있는건 상관하지 않고 안에 있는 변수들만 생각한다.
        • +) const, let은 블록범위가 함수 일수도, if, for 등이 다 될 수 있다.
  1. 함수의 호이스팅(function 키워드)
      • function 함수가 맨 위로 올라가는 것
      • 같은 범위 내라면, 함수 선언전에 호출해도 올바른 값이 나온다.
      • but, 함수를 변수에 등록(표현식)하거나 화살표 함수는 호이스팅이 되지 않는다. (이때 선언 전에 호출하면 not defined 에러가 난다.)
  1. 클래스의 호이스팅(class 키워드)
      • 클래스 선언후 객체 인스턴스화 해야한다.
      • 선언 전에 인스턴스화 시도하면 ReferenceError : not defined 에러가 난다.
      • 클래스 역시 변수에 저장하고 인스턴스화 시도하면 not defined 에러가 난다.
       
      결론 : 선언 -> 초기화 -> 사용 순서를 지키는 것이 좋다!