Section 1. 변수 다루기

var를 지양하자.

왜? 지양해야함?

  • var는 함수 스코프

  • let, const는 블록 단위 스코프, TDZ (이것들이 코드를안전하게 만들어줌)

    • const가 더 안전하다 (재할당x)

function scope vs block scope

var global = '전역';

if (global === '전역') {
    var global = '지역';
    
    console.log(global); // 지역
}

console.log(global); // 지역 (let으로 바꿨을 때, 전역으로 찍힘)

의도는 함수 안에서만 global이 '지역'으로 찍혀야하는데 모든 global변수가 오염되었다..

이때, let으로 코드를 변경하면 함수 안에 있는 global만 값이 바뀌게 된다.

근데, const 사용하면 객체 다룰 때 힘들지 않나?

그렇지 않다,, 다음 예제를 보자.

const person = {
    name: 'jang',
    age: '30',
};

// Assignment to constatnt variable. 당연히 재할당은 에러
person = {
    name: 'jang2',
    age: '30',
};

person.name = 'lee';
person.age = '22';

console.log(person); // { name: 'lee', age: '22' }

const를 사용해도 객체에 데이터를 변경할 수 있다.

그럼 배열은 어떻게 될까? 배열 안에 객체를 추가해보자.

const person = [{
    name: 'jang',
    age: '30',
}];

// Assignment to constatnt variable. 당연히 재할당은 에러
person.push = [{
    name: 'lee',
    age: '22',
}];

console.log(person); // [ { name: 'jang', age: '30' }, { name: 'lee', age: '22' } ]

배열 안에 데이터를 추가하는 것도 가능하다.

즉, const는 재할당만 금지된다.

전역 공간 사용 최소화

  • 전역 공간 => 최상위 객체

    • Window (브라우저 환경)

    • global (NodeJs 환경)

전역 공간을 사용하지 마라?

규모가 있는 애플리케이션을 만들 때 체감할 수 있다,, 난 아직 체감하지 몬함

실험을 하나 해보자. 파일이 나뉘면 스코프는 나뉠까?

// index.js
var globalVar = 'global';

console.log(globalVar); // global

// index2.js
console.log(globalVar); // global

아이러니하게 파일이 나뉘어도 스코프는 나뉘지 않는다...... 💩

더 안 좋은 사례를 보자..!

// index.js
var globalVar = 'global';

console.log(globalVar); // global

var setTimeout = 'setTimeout';

// index.js2
setTimeout(() => {
    console.log('1초');
}, 1000) // Uncaught TypeError: setTimeout is not a function

setTimeout에 문자열을 할당하면서 브라우저 Web API는 함수가 아니게 되어버렸다,,

결론

  • 전역 공간을 사용하면 어디에서나 접근할 수 있다.

    • 개발자 입장에서 분리되어 있다고 생각하지만 사실 런타임 환경에서는 분리가 되어 있지 않다.

  • 해결 방법 😊

    • 전역 변수를 사용하지 않는다.

    • 지역 변수만 사용한다.

    • Window , global을 조작하지 않는다.

    • constlet을 사용하는 것만으로도 많은 부분이 해소될 수 있다.

    • 근본적으로는 IIFE(즉시 실행 함수), Module, 클로저, 스코브 분리하는 방법이 있다.

임시 변수 제거하기

  • 임시 변수란?

    • 코드의 특정 부분에서만 사용되고 그 이후에는 더 이상 참조되지 않는 변수를 말한다.

    • 예를 들어, 스코프 안에서 전역 변수처럼 활용되는 친구들이 있다.

function getElements() {
    const result = {}; // 임시 객체
    
    result.title = document.querySelector('.title');
    result.text = document.querySelector('.text');
    result.value = document.querySelector('.value');
    
    return result;
}

위 예제에서 result는 임시 변수다. 하지만 굳이 임시 변수를 사용할 필요가 없다. 그럼 어떻게 코드를고칠 수 있을까?

function getElements() {
    return {
        title: document.querySelector('.title'),
        text: document.querySelector('.text'),
        value: document.querySelector('.value'),
    }
}

훨씬 깔끔해졌다! 딱 봐도 이 코드는 사이드 이펙트가 많지 않아 보인다.

또 하나의 예를 보자.

function getDateTime(targetDate) {
    let month = targetDate.getMonth();
    let day = targetDate.getDate();
    let hour = targetDate.Hours();
    
    // 월, 날짜, 시간을 여기서 조작하는데 이런 방식은 문제가 생길 수 있다. (접근 로직 최소화)
    month = month >= 10 ? month : '0' + month;
    day = day >= 10 ? day : '0' + day;
    hour = hour >= 10 ? hour : '0' + hour;
    
    return {
        month, day, hour
    }
}

다음 예제는 특정 Date object를 받은 다음, 원하는 날짜 형식대로 조작 후 리턴을 시키는 함수다.

여기서 추가적인 요구사항이 들어와서 수정을 해야하는 상황이라면?

  1. 함수를 새로 만든다.

  2. 기존 함수를 수정한다.

이때, 우리는 기존 함수를 수정한다고 해보자. 이 유틸 함수를 다른 파일에서 많이 쓰고 있다면 기존 코드를 해치지 않으면서 추가적인 요구사항도 충족되게 만들어야한다.

먼저, letconst로 바꾸자. 재할당 가능성을 제거하는 것이 좋으니까!

function getDateTime(targetDate) {
    const month = targetDate.getMonth();
    const day = targetDate.getDate();
    const hour = targetDate.Hours();
        
    return {
        month: month >= 10 ? month : '0' + month,
        day: day >= 10 ? day : '0' + day,
        hour: hour >= 10 ? hour : '0' + hour,
    }
}

그리고 기존 함수에서 객체를 바로 반환시켜버리자.

function getDateTime(targetDate) {
    const month = targetDate.getMonth();
    const day = targetDate.getDate();
    const hour = targetDate.Hours();
        
    return {
        month: month >= 10 ? month : '0' + month,
        day: day >= 10 ? day : '0' + day,
        hour: hour >= 10 ? hour : '0' + hour,
    }
}

function getDateTime(params) {
    const currentDateTime = getDateTime(new Date());
    
    // 필요한 요구사항에 따라 작성했다치고,,
    return {
        month: currentDateTime.month + '분 전',
        day: currentDateTime.day + '일 전',
        hour: currentDateTime.hour + '시간 전',
    }
}

함수를 한 번 더 추상화했기 때문에 재활용할 수 있다.

임시 변수라는 유혹에 빠지면, 임시 변수만 계속 내부에서 조작하게 된다.

마지막으로 한 가지 예제를 더 보자.

function genRandomNumber(min, max) {
    const randomNumber = Math.floor(Math.random() * (max + 1) + min);
    
    randomNumber * 100; // 누가 조작할 위험이 있음
    
    return randomNumber;
}

우리는 함수를 만들 때, 함수 내부의 임시 변수에 대한 유혹을 받지 않도록 단 하나의 역할만 할 수 있는 함수로 만들어주는 것이 좋다.

이번엔 배열 고차 함수 예제를 살펴보자.

보통 자바스크립트 입문자들이 아래와 같은 형식으로작성한다. 나..도 별반 다르지 않은 것 같은데

function getSomeValue(params) {
    let tempVal = ''; // 이 임시 변수는 반복문과 조건문을 넘나들며 계속 변경된다. 
    
    for (let index = 0; index < array.length; index++) {
          temp += array[index];
          temp += array[index];
          temp += array[index];
          temp += array[index];   
    }
    
    if (temp ??) {
          tempVal = ??;
    } else if (temp ??) {
          temp += ??
    } else {
          temp += ??
    }
    
    return temp;
}

따라서 우리는 어떻게 작성해야하냐?

임시 변수를 사용하지 않는 방법을 많이 고민해야한다..! 💪

결론

  • 임시 변수를 제거하자!

    • 명령형으로 가득한 로직이기 때문에

    • 디버깅이 힘들다..

    • 추가적인 코드를 작성하려는 유혹이 생긴다..

  • 해결 방법 😊

    • 함수 나누기

    • 바로 반환하기

    • 고차 함수(map, filter, reduce ...)

    • 선언형 프로그래밍

호이스팅

  • 호이스팅이란?

    • 간단히 말해서 선언과 할당이 분리된 것을 말한다.

    • 언제? 런타임(프로그램이 동작할 때)에

    • 변수 호이스팅

      • var로 선언한 변수가 초기화가 제대로 되어 있지 않을 때 undefined로 최상단에 끌어올려줄 수 있는 것을 말한다.

      • letconst를 쓰면 이런 현상이 잘 없음(TDZ)

    • 함수 호이스팅

      • 함수 표현식은 호이스팅이 일어나지 않는다.

      • 그러나, 함수 선언식은 호이스팅이 발생한다!

다음 예제를 보자.

var sum;

console.log(typeof sum); // function

function sum() {
    return 1 + 2;
}

sum 변수에 함수가 덮어쓰여져서(함수 호이스팅)sum의 타입을 찍어보면 function으로 나온다.

이러한 호이스팅은 프로그래밍에 안좋은 영향을 준다.

따라서, 함수를 만들 때 const를 사용한 함수 표현식을 사용하는 것이 좋다.

console.log(sum()); // ReferenceError: Cannot access 'sum' before initialization

const sum = function sum() {
    return 1 + 2;
}

const를 사용한 덕분에 선언하기 전에 접근하지 말라는 에러가 난다.

결론

  • 호이스팅은 런타임 시에 바로 선언을 최상단으로 끌려올려주는 것

  • 문제

    • 코드를 작성할 때 예측하지 못한 실행 결과가 노출된다.

  • 해결 방법 😊

    • var를 지양한다. => const를 지향하자!

    • 함수 표현식을 사용한다.

Last updated