13일차 - 원시*참조 자료형, 스코프와 변수

dudu00·2022년 11월 7일
0

codestates

목록 보기
13/25

원시 자료형과 참조 자료형

자바스크립트에서 원시 자료형이 아닌 모든 것은 Object
배열([])과 객체({}), 함수(function(){})가 대표적 ( 참조 자료형 )

number, string, boolean과 같은 고정된 저장 공간을 차지하는 데이터를 모두 원시 자료형
대량의 데이터를 다루기에 적합한 배열과 객체는 참조 자료형(reference data type)

const 키워드로 선언하면, 재할당은 불가
원시 자료형이 할당될 때에는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다
그래서 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용할 수 있다.

let first = [10, 20, 30, 40];
let second = first;
second[0] = 5;

second는 first가 가지고 있는 주소를 그대로 가지고 있다.
값만 복사했다면 second의 0번째 인덱스에 있는 요소를 변경하면 first는 변경되지 않겠지만, 주소를 공유하고 있기 때문에 first도 똑같이 변경

console.log([1,2,3] === [1,2,3]);
console.log({ foo: 'bar' } === { foo: 'bar' });
ㅡ> false, false	

이미 두 개의 heap 저장 공간의 주소를 확보했다
다만 우리는 눈으로 확인하지 못할 뿐.
배열([])과 객체({}) 등 참조 자료형을 읽을 때, 미리 주소값과 메모리 값을 잡아둔다고 생각하면 편하다. 그러므로 [] === [] 도 true가 나오지 않는다.

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

스코프

렉시컬 환경 ㅡ 그 함수가 정의된 환경

범위가 중괄호(블록) 또는 함수에 의해 나누어지고, 그 범위를 스코프라고 부른다.

바깥쪽 스코프에서 선언한 변수는 안쪽 스코프에서 사용 가능
반면에, 안쪽에서 선언한 변수는 바깥쪽 스코프에서는 사용할 수 없다

서울에 사는 김코딩은 서울시 복지혜택도 받을 수 있고
대한민국 복지혜택 받을 수 있다.
경기도에 사는 박해커는 경기도 혜택 받을 수 있지만
서울시 복지혜택은 받을 수 없다. 

변수 접근 규칙에 따른 유효 범위

  • 스코프는 중첩이 가능하고
    안쪽 스코프에서 바깥쪽 스코프로는 접근할 수 있지만 반대는 불가능
  • 가장 바깥의 스코프를 전역 스코프라고 부르고 나머지는 다 지역 스코프
    지역 변수는 전역 변수보다 더 높은 우선순위를 가진다
    (지역 스코프에 선언한 변수는 지역 변수, 전역 스코프에서 선언한 변수는 전역 변수)
let name = '김코딩';
function showName() {
  name = '박해커';
  console.log(name); // 두 번째 출력
}
console.log(name); // 첫 번째 출력
showName();
console.log(name); // 세 번째 출력

ㅡ> 김코딩, 박해커, 박해커

앞서 문제와는 다르게, 세 번째 줄에서 let 키워드를 사용한 선언이 존재하지 않는다

이는, '박해커'라는 값으로 할당하고 있는 name 변수는 전역에 선언된 name 변수를 그대로 사용하겠다는 의미

지역 스코프에서 새로 선언되지 않으면 그냥 같은 변수입니다.

따라서 showName 함수가 실행되기 전, 처음에는 '김코딩'을 출력하고, 그 이후에는 전역변수 name의 값이 바뀌기 때문에 두 번째 및 세 번째 출력에 '박해커'가 출력

변수 선언과 스코프

블록 스코프(block scope)라고 부르며, 중괄호를 기준으로 범위가 구분된다.
함수 스코프(function scope)가 있다
function 키워드가 등장하는 함수 선언식 및 함수 표현식은 함수 스코프를 만든다
화살표 함수는 블록 스코프로 취급됨. 함수 스코프 아님

for (let i = 0; i < 4; i ++) {
	console.log(i); // 4번 반복
}
console.log('final i:', i); // ReferenceError

블록 스코프 안에서 정의된 변수 i는 블록 범위를 벗어나는 즉시 접근할 수 없다.
따라서 결과로는 ReferenceError가 나오게 된다.

var 키워드는 for 문이 만들어낸 블록 스코프를 무시합니다.
위에 결과값 출력됨 // 4

var 키워드와 let 키워드

변수를 정의하는 또따른 키워드 var

  • var 키워드는 블록 스코프를 무시하고, 함수 스코프만 따른다 ( 이전 방식 )
    (단, 화살표 함수의 블록 스코프는 무시하지 않는다)
  • 블록 단위로 스코프를 구분했을 때, 훨씬 더 예측 가능한 코드를 작성할 수 있으므로
    let 키워드의 사용이 권장된다
  • var를 사용하지 않더라도 함수 스코프는 let으로 선언된 변수의 접근 범위를 제한한다

함수 내에서 선언 키워드 없는 선언은, 함수의 실행 전까지 선언되지 않은 것으로 취급

var 키워드는 재선언을 해도 아무런 에러도 내지 않지만, let 키워드는 재선언을 방지한다

const 라는 키워드. 변하지 않는 값, 곧 상수(constant)를 정의할 때에는 const를 이용합니다.
const는 값의 재할당이 불가능합니다

변수 선언할 때 주의할 점

브라우저에만 존재하는 window 객체

개발자 도구를 열어 콘솔에 window 라고 입력해 보세요. 객체 하나를 조회할 수 있다. 이 객체는 사실 브라우저의 창(window)을 의미하는 객체이지만, 이와 별개로 전역 영역을 담고 있기도 함

함수 선언식으로 함수를 선언하거나, var로 전역 변수를 만들면, window 객체에서도 동일한 값을 찾을 수가 있다.

전역 변수는 가장 바깥 스코프에 정의한 변수입니다. 따라서, 어디서든 접근이 가능

얼핏 "모든 변수를 바깥으로 빼면 스코프 걱정을 하지 않아도 되겠네?" 라는 생각이 들 수 있지만
전역 변수를 많이 만드는 것은 그다지 좋은 선택이 아닙니다.

보통 애플리케이션을 만들 때에는, 내가 직접 작성하지 않은 수많은 다른 함수와 로직이 포함된다. 너도나도 똑같은 이름으로 전역 변수를 선언하려고 한다면 분명 문제가 발생

선언 없이 변수를 할당하지 말자
선언 없이 변수를 할당하면, 해당 변수는 var로 선언한 전역 변수처럼 취급됩니다.( 함수 내에서도 동일 )

profile
성장일지

0개의 댓글