[JavaScript]변수 다루기

chaewon Im·2022년 11월 23일
0

공부 기록✏️

목록 보기
14/15

이전에 작성한 var,let,const의 차이 (+scope,hoisting,변수 생성 단계) 에 이어 JS에서 변수를 다루는 가이드에 대해 한번 더 정리한 글

1. var 지양하기

💡 const → let 순서대로 지향한다. var는 사용하지 않는 것이 좋다!
const는 재할당만 금지되고 조작에는 문제가 없어서 더 안전하다.

✅var

  1. 함수 레벨 스코프

    • 함수의 코드 블록만을 스코프로 가진다.
    • 함수 내에서 선언된 변수는 함수 내에서만 유효하고, 함수 외부에서는 참조할 수 없다.
    • 함수 외부에서 선언한 변수는 모두 전역 변수이다.
  2. 재선언(중복선언), 재할당이 모두 가능하다.

    • 이미 선언한 변수를 재선언해도 아무 에러가 발생하지 않는다.
    • 이는 문제가 발생할 확률이 높다. 다른 어딘가에서 이미 선언한 변수를 또 선언해도 발견하지 못할 수 있다.
    var name = '김철수'
    var name = '신짱구'
    
    console.log(name) //'신짱구'
  3. 변수 호이스팅

    • var는 변수 선언 시 선언 단계와 초기화 단계가 한번에 이루어진다.
    • 이 때 따로 값을 할당하지 않으면 undefined로 초기화한다.
    • undefined라는 초기화 된 값이 존재하기 때문에 var는 선언문 이전에 변수를 참조해도 참조 에러가 발생하지 않는다. (let,const는 선언 시 값을 초기화하지 않는다.)
    name = '신짱구'
    
    console.log(name)
    var name = ''

✅let/const

  1. 블록 레벨 스코프

    • 블록에서만 유효하다.
  2. TDZ(Temporal Dead Zone) 속성을 가진다

    • TDZ란 직역하면 일시적 사각지대라는 뜻인데, 스코프의 시작점부터 초기화 시작점까지의 구간을 뜻한다.
    • 자바스크립트는 코드를 실행 전 모든 선언을 메모리에 등록해 놓는데, 이 때 let,const는 메모리에 공간만 만들고 초기화를 하지 않는다.
    • 이 초기화가 되기 전 까지의 상태가 TDZ이다.
  3. 호이스팅이 발생하지 않는 것처럼 동작한다.

    • let,const 키워드는 TDZ 속성을 가지기 때문에 선언된 변수를 선언문 이전에 참조하면 참조 에러가 발생한다.
    • 이는 자바스크립트에서 초기화가 되지 않은 변수는 참조할 수 없기 때문이다.
    • 따라서 초기화가 되지 않은 것일 뿐, 호이스팅이 발생하지 않은 것이 아니다.
    console.log(name)
    //ReferenceError
    
    let name = '김철수'
  4. 재선언이 불가능하다.

    • 만약 이미 let,const 키워드로 선언한 변수가 있다면 같은 이름의 변수를 선언할 수 없다.
    let name = '김철수'
    let name = '신짱구'
    
    const age = 5
    const age = 29
    
    //재선언 불가, 에러 발생
  5. let: 변수가 선언되어 있다면 재할당이 가능하다.

  6. const: 재할당이 불가능하다.

    • 따라서 const는 객체 타입, 상수 등에 사용한다.
    • const로 선언한 객체의 경우 직접 수정이 불가능하다.
      const person = {
      	name:'신짱구',
          age:'5',
      }
      
      person.name = '봉미선'
      person.name = 29
      //객체 자체가 아닌 내부의 값만 바꾸는 것이기 때문에 정상 동작이 가능하다.
      
      person.push({
      	name:'신형만',
          age:'35',
      })
      //person

2. function scope & block scope

✅scope란?

  • 식별자의 유효 범위
  • 선언된 위치에 따라 유효 범위가 달라진다.
  • 전역 변수: 전역 스코프 → 전역에서 유효하다. 어디서든 참조 가능하다.
  • 지역 변수: 지역 스코프 → 지역+하위 지역에서만 유효하다.

✅function scope

  • 함수 코드 블록만을 지역 스코프로 가진다.
var global = '전역'

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

console.log(global) //지역

⇒ if블록 안에서 변경된 내용이 if문 밖까지 영향을 미쳤다.

  • 이는 var가 함수 레벨 스코프를 가지기 때문이다.
  • if문은 함수가 아니기 때문에 전역에 영향을 끼친 것.

✅block scope

  • 자바스크립트에서 생기는 모든 코드 블록(if, for, while, try/catch 등등 { }가 생기는 모든 것)은 지역 레벨 스코프를 가진다.
  • 이를 블록 레벨 스코프라고 한다.
const global = '전역'

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

console.log(global) //전역

⇒ 블록 내에서의 변수와 블록 바깥의 변수가 독립적이다.


3. 전역 공간 사용 최소화

💡 전역 공간을 더럽히지 않기 위해 전역 공간 사용을 최소화 해야 한다.

전역에는 두 가지 종류가 있다.

  1. window(브라우저)
  2. global(nodeJS)

자바스크립트는 언어에 개입해서 내장 메서드를 수정할 수가 있다.

전역을 사용할 경우 언어에 의도치 않게 개입되며 전역 공간을 더럽힐 수 있다.

  • case1) 나도 모르게 내장 메서드를 덮어 씌우는 경우 ex) var setTimeout = ‘setTimeout' ⇒ setTimeout() 함수를 사용할 수 없게 된다.
  • case2) 선언한 변수를 어디서든(다른 파일에서도) 접근할 수 있다. → 데이터의 관리가 어려워지고 스코프 분리 위험이 있다.

✅전역 공간을 더럽히지 않기 위해 할 일

  1. 전역 변수 사용하지 않기
  2. window, global을 조작하지 않기
  3. var대신 const, let을 사용한다.
  4. IIFE, Module, closure 스코프를 나누기(?)

4. 임시 변수 제거하기

💡 임시변수 대신 바로 데이터를 반환하도록 { }로 묶어서 전달한다.

  • 예시 1)임시변수를 사용하는 예시
    function getElements(){
      const result = {};
    
      result.title = document.querySelector('.title');
      result.text = document.querySelector('.text');
      result.value = document.querySelector('.value');
    
      return result;
    }
  • 예시 2) 임시 변수를 사용하지 않고 바로 반환하는 예시
    function getElements(){
      return{
        title:document.querySelector('.title'),
        text:document.querySelector('.text'),
        value:document.querySelector('.value')
      }
    }
    최대한 사용하지 않는 방향을 추구해야 한다.

임시변수를 사용하면 명령형으로 가득한 로직이 된다.

function getSomeValue(params){
  let tempVal = '';
  for(let index=0;index<array.length;index++){
    temp = array[index];
    temp += array[index];
    temp -= array[index];
  }
  if(temp){
    //...some code
  }

  return temp
}

→ 함수의 동작 예측이 어렵고 디버깅이 어려워진다.

→ 함수는 하나의 역할만 해야하는데, 추가적인 코드를 작성하고 싶은 유혹이 생긴다.

✅해결책

  1. 함수 나누기
  2. 바로 반환하기
  3. 고차함수 사용하기(map, filter, reduce)
  4. 선언형으로 코드 작성하기

5. 호이스팅 주의하기

✅호이스팅(hoisting)

💡 런타임 시 함수 안에 있는 모든 선언들을 끌어올려 최상단에서 선언하는 것과 같은 현상, 그러나 실제로 코드가 끌어올려지는 것은 아니다.

  • 자바스크립트는 코드를 실행하기 전 실행 컨택스트를 위한 과정을 거치는데, 이 때 엔진 내부에서 모든 선언(var,let,const,function,class)을 메모리에 등록한다. 따라서 코드가 실행되기 전 이미 필요한 모든 선언들이 저장되어 있기 때문에, 선언문보다 참조/호출이 먼저 나와도 동작에는 오류가 나지는 않는다.
  • 자바스크립트 동작 과정에 따라 모든 선언에는 호이스팅이 일어난다.
    • let, const, class를 이용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다.

    • var는 호이스팅의 영향을 받는다. undefined가 할당되기 때문에 호이스팅의 영향으로 예측하지 못한 결과를 얻을 수 있다.

      참조 에러가 난다고 호이스팅이 일어나지 않은 것이 아니다. 참조 에러가 나는 이유는 메모리에 공간만 생기고, 값을 초기화하지 않기 때문.

✅해결책

  1. var를 사용하지 않는다.

  2. 함수를 만들 때 const로 변수를 선언하고 거기에 익명 함수를 할당하는 방법

    (변수 선언 → 할당 → 초기화 완료 ⇒ 정확한 분리!)

profile
빙글빙글 FE 개발자

0개의 댓글