TIL - Day10

정태호·2023년 6월 14일

TIL

목록 보기
8/23

JS 사전문제를 풀며 오류 개선하기

Case1. 아래 코드에서 오류가 발생하는 이유는?

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

var testcase1 = new test([
    {
        name : 'takuya',
        perform : function() {
            console.log('Sing : a e i o u')
        }
    }
]);

testcase1.perform();
//TypeError: Cannot read properties of undefined (reading 'forEach')

문제 발생 원인

  • this.members.forEach의 this는 setTimeout 함수안의 펑션을 가르키지 test의 this를 가리키지 않는다.
  • 즉, merbers의 값은 undefined 인 것이다.

개선법

1. arrow function

  • 화살표 함수는 자체로 펑션 스코프를 만들지 않아 상위 펑션의 스코프를 찾아가게 된다
function test(members){
    this.members = members;
    this.perform = function() {
        setTimeout(() => {
            this.members.forEach(function(member){
                member.perform();
            })
        }, 1000)
    }
}

...
 
testcase1.perform(); // Sing : a e i o u

2. bind 사용

  • 함수 내의 this를 변경된 함수의 this로 만든다...
  • 펑션 밖에 있으므로 test의 this를 가리키게 된다!
function test(members){
    this.members = members;
    this.perform = function() {
        setTimeout(function() {
            this.members.forEach(function(member){
                member.perform();
            })
        }.bind(this), 1000) // bind 사용 펑션 끝에 붙여줌
    }
}

...
 
testcase1.perform(); // Sing : a e i o u

3. 클로져 사용

  • 선언된 환경을 기억하기 때문에 외부의 변수나 함수가 접근하여도 사용할 수 있다.
function test(members){
    var cur = this;
    this.members = members;
    this.perform = function() {
        setTimeout(function() {
            cur.members.forEach(function(member){
                member.perform();
            })
        }, 1000)
    }
}

...
 
testcase1.perform(); // Sing : a e i o u

Case2. 아래 코드에서 undefiend가 출력되는 이유?

const arr = [0,1,2,3,4];

for(var i=0; i<arr.length; i++){
    setTimeout(function(){
        console.log(i, arr[i]);
    },i*1000);
}
//5 undefined 5 undefined 5 undefined 5 undefined 5 undefined

문제 발생 원인

  • i는 console.log를 찍는 코드의 안에 있는 변수가 아니다.
  • setTimeout이 실행되는 시점에 i는 for 루프가 다 끝난 뒤 5이다.
  • arr 배열에는 인덱스 5번이 없기 때문에 undefined가 반환된다.

개선법

즉시 실행 함수(IIFE)

  • i가 0,1,2,3,4 일 때를 각각의 함수 스코프로 가두어서 처리한다.
  • setTimout이 실행되는 시점에서 참고하는 index는 IIFE에서 인자로 넘긴 i값을 참고한다.
const arr = [0,1,2,3,4];

for(var i=0; i<arr.length; i++){
    (function(index) {
        setTimeout(function(){
            console.log(index, arr[index]);
        },i*1000);
    })(i)
}

// 0 0, 1 1, 2 2, 3 3, 4 4

let 사용

  • let은 블록 수준 스코프로 IIFE와 마찬가지로 i의 값이 각각 참조된다.
const arr = [0,1,2,3,4];

for(let i=0; i<arr.length; i++){
    setTimeout(function(){
        console.log(i, arr[i]);
    },i*1000);
}

// 0 0, 1 1, 2 2, 3 3, 4 4

for 대신 forEach 사용

  • arr 배열을 순회하며 요소마다 각각의 펑션을 만들기 때문에 i의 값이 고유해진다.
const arr = [0,1,2,3,4];

arr.forEach((item,i)=>{
    setTimeout(()=> {
        console.log(i, item);
    }, i * 1000)
})

// 0 0, 1 1, 2 2, 3 3, 4 4

var, let, const의 차이에 대해 간단하게 정리해보자!

var

  • 함수 수준 스코프, 변수 재할당 가능

let

  • 블록 수준 스코프, 변수 재할당 가능

const (자주 사용 -> 안전하다)

  • 블록 수준 스코프, 변수 재할당 불가능(상수)

블록 수준 스코프란 ?
📌 if, for 등 block 구문 단위로 범위를 갖는다.

호이스팅

  • var로 선언된 변수, 함수는 호이스팅이 일어난다. 실행될 때 function scope상 맨 위로 var 선언이 끌어올려진다.
  • 함수 선언부 위로 끌어올려지기 때문에 값 할당 전에 호출될 수 있다.
    • 이러한 점 때문에 예상치 못한 버그가 일어날 수 있다.
  • let, const 에도 호이스팅은 일어나지만 TDZ(Temporary Dead Zone) 개념 덕분에 할당되기 전에 호출하면 에러가 발생한다.

클로져란?

function outter() {
    const name = 'jth';

    return function () {
        console.log(name);
    }
}

const printName = outter();
printName(); //js
  • 위 코드에서 console.log(name)은 새로운 내부 함수에서 실행되어 지고 있지만 외부의 name 변수를 참고하여 잘 출력되는 것을 볼 수 있다.

함수와 함수가 선언된 어휘적 환경의 조합이라고도 한다.

  • private 효과
function Counter() {
    let count = 0;

    function increase(){
        count++; //내부 함수에서 외부 변수 값을 가져다 씀
    }

    function print(){
        console.log(`count : ${count} `);
    }

    return {
        increase,
        print,
    }
}

const test = Counter(); // test에는 리턴된 함수들만 들어가 있음

test.increase();
test.increase(); // count 변수 조작
test.print();

console.log(test.count); // count는 외부에서는 접근 불가
// count : 2 undefined
profile
주니어 프론트엔드 개발자가 되고 싶습니다!

0개의 댓글