[221118] JS 특성

뜨개발자·2022년 11월 18일
0

TIL

목록 보기
8/75

JavaScript의 자료형과 JavaScript만의 특성

  • 느슨한 타입(loosely typed)의 동적(dynamic) 언어
    변수는 특정 타입으로 할당되지 않는다.
    모든 타입의 값으로 재할당이 가능하다.

  • JavaScript 형변환
    자바 스크립트의 형변환은 대부분 적절한 타입으로 자동으로 이루어진다.

    let a = 10
    alert(a)

    위 코드에서 alert는 문자열을 출력해야 하므로 a가 필요에 따라 자동으로 문자열로 바뀐다. 이렇게 자동으로 이루어지는 경우를 암시적 변환이라고 한다.
    작성자가 의도를 가지고 String(a)와 같이 형을 변환하는 것은 명시적 변환이라고 한다.

  • ==, ===
    JS는 동적 언어라는 특성 때문에, 다른 언어처럼 ==으로 비교하는 경우 의도대로 작동하지 않을 가능성이 있다.

    1 == "1"

    위의 코드를 입력하면 true를 출력한다.
    타입을 변경했을 때, 두 값이 같기 때문이다.

    1 === "1"

    이와 같은 경우에는 false를 입력한다. 즉, ===을 사용하면 형변환 없이 엄격한 비교가 가능하다.

  • 느슨한 타입(loosely typed)의 동적(dynamic) 언어의 문제점
    변수에 예상하지 못한 값이 들어와 오류가 발생할 가능성이 있다.
    동적 언어는 런타임 시에 확인해야 하므로, 코드가 길어질수록 오류를 찾기 힘들어진다.

  • 보완 방법
    엄격한 문법을 지원하는 TypeSciptFlow를 사용한다.

  • undefined와 null
    undefined는 선언했지만 값을 할당하지 않은 변수나, 값이 주어지지 않은 인수에 자동으로 할당된다.
    값을 할당하지 않은 변수, 함수가 값을 리턴하지 않는 경우에 undefined가 할당된다.

    null은 의도적으로 값을 비운 상태이다. undefined는 값이 지정되지 않았음을 의미하지만, null은 해당 변수가 가리키고 있는 값이 없음을 의미한다.

    참고 : undefined == nulltrue가 나온다.


JavaScript 객체와 불변성이란 ?

  • 기본형 데이터와 참조형 데이터
    기본(원시)형 데이터는 값을 그대로 할당한다. Number, String, Boolean, null, undefined이 기본형 데이터에 속하고, ES6부터는 Symbol도 기본형 데이터에 추가되었다.

    참조형 데이터는 값이 저장된 주소값을 할당(참조)한다. 배열(Array), 함수(Function), 정규표현식(RegExp)등이 참조형 데이터에 속하고, ES6부터는 Map, Set, WeakMap, WeakSet등도 추가되었다.

  • 불변 객체를 만드는 방법
    const로 선언하는 경우 상수가 되기 때문에 변경하지 못한다고 알려져있다. 값을 변경하는 재할당은 불가능하지만, 객체의 속성은 변경이 가능하다.

    const test = {}
    test.name = "js"

    위 코드를 입력한 후, test를 확인해보면 {name: 'js'}를 확인할 수 있다.
    실제 객체가 변경은 되지만 객체와 변수(test)사이의 바인딩은 변경이 되지 않기 때문에 객체의 속성이 변경 가능하다.
    따라서 const불변 객체라고 보기는 어렵다.

    Object.freeze()는 객체 속성 변경을 불가하게 만든다.

    test = {
    	name: "js"
    }
    Object.freeze(test)
    
    test.name = "javascript"

    위 코드를 실행한 후 test를 확인해보면 여전히 {name: 'js'}를 확인할 수 있다.
    그러나 Object.freeze()는 재할당이 가능하다.

    • 결론: 불변 객체는 위 두 가지를 결합하여 사용할 수있다.
      const test {
      	name: "js"
      }
      Object.freeze(test)
      위처럼 작업하면 재할당도, 속성 변경도 불가능하다.
  • 얕은 복사와 깊은 복사
    얕은 복사객체의 참조값(주소 값)을 복사한다. 주소를 복사하기 때문에, 복사한 변수와 원래 변수가 같은 객체를 가리키고 있다. 따라서 하나를 변경하게 되면 다른 하나도 변경된다.
    깊은 복사객체의 실제 값을 복사한다. 복사한 변수와 원래 변수가 가리키는 객체가 다르기 때문에, 하나를 변경해도 다른 하나에는 영향을 주지 않는다.


  • 스코프, 호이스팅, TDZ
    스코프 : 변수, 함수, 클래스가 접근할 수 있는 유효한 범위를 뜻한다.
    전역 스코프라고 하면 어디서든 접근이 가능하고, 지역 스코프라고 하면 해당 범위 내에서만 접근이 가능하다는 뜻이다.

    호이스팅 : 함수의 코드를 실행하기 전에 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 말한다.
    호이스팅 때문에, 함수의 선언이 함수의 호출보다 뒤에 있더라도 코드가 실행된다.

    TDZ(일시적 사각지대)

    pi; // throws `ReferenceError`
    const pi = 3.14;

    위 코드에서 두 번째 줄 전까지 pi는 TDZ(일시적 사각지대)에 놓여있다고 한다.
    var, function, import의 경우에는 호이스팅이 일어나 호출을 먼저 하고 선언을 해도 문제가 없다. 따라서 위 세 경우는 TDZ의 영향을 받지 않는다고도 말할 수 있다.
    반대로 호이스팅이 일어나지 않는 let, const, class등은 TDZ의 영향을 받는다.

  • 함수 선언문과 함수 표현식에서 호이스팅 방식의 차이
    함수 선언문의 경우, function을 사용하므로 함수 전체를 호이스팅한다.
    함수 표현식의 경우, const, let 등을 사용하므로 호이스팅이 일어나지 않는다.
    함수 선언문으로 정의한 함수를 사용하는 경우, 변수가 덧씌워지기 쉬운 JS 특성 상 의도하지 않은 결과를 도출할 가능성이 높다.

  • let, const, var, function
    재선언 가능 : var
    재선언 불가능 : let, const

    재할당 가능 : var, let
    재할당 불가능 : const

    호이스팅 발생 : var, function
    호이스팅 발생 없음 : const, let

  • 실행 컨텍스트와 콜 스택
    Execution context(실행 컨텍스트) : 자바스크립트 코드가 실행되는 환경을 의미한다.
    Global Execution context는 자바스크립트 엔진이 처음 코드를 실행할 때 생성된다. 전역 객체인 Window Object (Node는 Global) 를 생성하고 this가 Window 객체를 가리키도록 한다.
    Function Execution context는 함수가 호출될 때 생성된다. 모든 함수는 호출되는 시점에 자신만의 실행 컨텍스트를 갖게 된다.

    실행 컨텍스트가 활성화되는 시점에 아래 세 가지 현상이 발생한다.

  1. 호이스팅이 발생한다.

  2. 외부 환경 정보를 구성한다.

  3. this 값을 설정한다.

    call stack : 코드가 실행되면서 생성되는 Execution Context를 저장하는 자료구조를 의미한다.
    엔진이 처음 스크립트를 실행할 때, Global Execution contextcall stack에 push한다. 이후, 함수를 호출할 때마다 그 함수를 위한 Function Execution contextcall stack에 push한다. 함수가 종료되면 pop을 하여 call stack에서 해당 함수의 Function Execution context를 제거하고, 다음 top에 있는 함수로 이동한다.

  • 스코프 체인과 변수 은닉화
    스코프 체인 : 변수를 참조할 때, 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프로 이동하면서 선언된 변수를 검색한다. 이를 스코프 체인이라고 한다.

    변수 은닉화 : 스코프 체인 때문에, 여러 스코프에 동일한 이름의 변수가 있어도 가장 안쪽에서 검색된 변수만을 참조한다. 이러한 특성을 이용하여, 직접 변경하면 안 되는 변수에 대한 접근을 외부로부터 차단하는 것을 변수 은닉화라고 한다.


실전문제1

let b = 1;

function hi () {
const a = 1;
let b = 100;
b++;
console.log(a,b);
}
//console.log(a);

console.log(b);
hi();
console.log(b);
  • 위 코드를 실행했을 때, 출력되는 값 예상
    1
    1 101
    1

  • 실제 출력된 값
    1
    1 101
    1

  • 코드 분석
    console.log(b); 에서 최상단에 선언한 b 값인 1이 출력된다.

    hi(); 에서 함수 hi을 실행한다. a는 상수 1, 변수 b에는 100을 저장하고, b++;을 수행하므로 b가 101로 변경된다. 이후 console.log(a, b)로 '1 101'을 출력한다.
    여기에서 선언된 b는 이 함수 스코프 내에서만 존재한다. 함수 실행이 종료되며, 할당된 컨텍스트가 콜스택에서 삭제된다.

    console.log(b); 에서 출력하기 위한 b를 검색하면 여전히 최상단에 선언한 b의 값인 1을 출력하게 된다.

  • console.log(a);의 주석처리를 해제하는 경우
    해당 스코프에서 a가 선언되지 않았기 때문에 Reference Error가 발생한다.
    이를 해결하기 위해서는 이 문장 전에 a를 선언해야 한다.

실전문제2

1 == "1";
1 === "1";
  • 위 두 문장의 값이 다른 이유
    상단에서 ==, ===의 차이를 알아볼 때 이미 기술하였다.
    첫번째 문장의 경우, 자바스크립트는 형변환을 통해 어떻게든 비교가 가능하도록 만든다. 따라서 true를 반환한다.
    반면, 두번째 문장의 ===의 경우에는 보다 엄격하게 비교한다. 형변환 없이 비교하기 때문에 false를 반환한다.
profile
뜨개질하는 개발자

0개의 댓글