항해99 2주차 #2

장민영·2022년 9월 23일
0

javascript 객체와 불변성이란?

기본형 데이터(Primitive Type) : 값을 할당

Primitive Type은 더이상 _값을 그대로 할당 함
-> 값을 할당할 때 값 그 자체를 다른 메모리에 할당하기 때문에, 원래의 값과 복사된 값이 서로 영향을 미치지 않음
immutable value (변경 불가능한 값)
메모리 내에 고정된 크기로 저장되면서, primitive data 값 자체를 보관

Primitive Type의 종류

  • Number
  • String
  • Boolean
  • null
  • undefined
  • Symbol (New in ECMAScript 6)
const a = 1;
let b = a;

b = 2

console.log(a); //1
console.log(b); //2

참조형 데이터(Reference Type) : 값이 저장된 주소 값을 할당(참조)

Reference Type 데이터는 '값이 지정된 주소값'을 할당한다/
-> 참조값은 '해당 변수가 객체의 주소를 가르키는 값'이다
Reference Type은 기본형 데이터의 집합
mmutable Value (변경 가능한 값)

Reference Type 종류

  • Object : array, function, map,
const a = {number: 1};
let b = a;

b.number = 2

console.log(a); // {number: 2}
console.log(b); // {number: 2}

불변 객체를 만드는 방법

불변 객체(immutable data pattern)를 만들어야 하는 이유??

  • 의도하지 않은 객체의 변경이 발생하여 오류를 발생하기 때문이다.

문제 해결방법

  • 객체의 방어적 복사(defensive copy):Object.assign,전개연산자
  • 불변객체화를 통한 개체 변경 방지:Object.freeze

얕은 복사(Shallow copy)와 깊은(Deep copy) 복사

얕은 복사 ( Shallow copy)

Shallow copy는 참조 (주소)값을 복사하는 것이다.

const stu = { vaule: 1 }
const newStu = obj;

newStu.vaule = 2;

console.log(stu.vaule); // 2
console.log(stu === newStu); // true
  • stu 객체를 새로운 newStu 객체에 할당였으며 이를 참조 할당이라고 부른다. 복사 후 newStu 객체의 value값을 변경하였더니 기존의 obj.value값도 같이 변경된다.
    두 객체를 비교해도 true로 나온다. 이는 얕은 복사로, 데이터가 생성되는 것이 아니라 해당 데이터의 참조 값(메모리 주소)를 전달하여 한 데이터를 공유하는 것이다.

Deep copy

값 자체의 복사

let a = 1;
let b = a;

b = 2;

console.log(a); // 1
console.log(b); // 2
console.log(a === b); // false

deep copy 와 shallow copy로 나눠지는 이유

  • 효율성

예를 들어 객체 내에 개체가 1000개 있는 경우, 개체를 생성하고 할당하는데 시간이 1초 걸린다고 가정하면, deep copy를 하게 되면 최소 1000초가 소요되고, shallow copy를 하면 메모리를 가르키는데 필요한 시간만 소요하게 된다.
따라서 shallow copy만 해도 되는 경우에는, shallow copy를 하게 되는 것이다.

호이스팅

함수 안에 있는 선언들을 모두 끌어 올려서 해당 함수 유효 스코프의 최상단에 선언 하는 것을 말한다.

호이스팅의 대상

자바스크립트는 ES6에서 도입된, let,const를 포함하여 모든 선언(var,let,const,function,class)를 호이스팅함.
호이스팅(hoisting)이란, var선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말함 : 순서없이 막 쓰여도 위부터 읽히는게 아니라 호이스팅을 함으로써 개떡같이 써놔도 찰떡같이 알아듣게끔 한다는 내용인거같다.

let/const 변수 선언과 함수 표현식에서는 호이스팅 발생하지 않음


  foo();
  foo2();

  function foo() { // 함수선언문
          console.log("hello");
  }
  var foo2 = function() { // 함수표현식
          console.log("hello2");
  }

함수 선언문과 함수 표현식에서 호이스팅

함수 선언문에서의 호이스팅

  • 함수 선언문은 코드를 구현한 위치 상관없이 자바스크립트의 특징인 호이스팅에 따라 브라우저가 자바스크립트를 해석 할 때 맨 위로 끌어 올려짐
/* 정상 출력 */
function printName(firstname) { // 함수선언문 
    var result = inner(); // "선언 및 할당"
    console.log(typeof inner); // > "function"
    console.log("name is " + result); // > "name is inner value"

    function inner() { // 함수선언문 
        return "inner value";
    }
}

printName(); // 함수 호출

함수 표현식에서의 호이스팅

  • 함수 표현식은 함수 선언문과 달리 선언과 호출 순서에 따라서 정상적으로 함수가 실행되지 않을 수 있다.
    *함수 표현식에서는 선언과 할당의 분리가 생김
    
/* 오류 */
 function printName(firstname) { // 함수선언문
     console.log(inner); // > "undefined": 선언은 되어 있지만 값이 할당되어있지 않은 경우
     var result = inner(); // ERROR!!
     console.log("name is " + result);

     var inner = function() { // 함수표현식 
         return "inner value";
     }
 }
printName(); // > TypeError: inner is not a function

호이스팅은 함수 선언문과 함수 표현식에서 서로 다르게 동작하기 때문에 주의해야 한다. 변수에 할당된 함수 표현식은 끌어올려지지 않기 때문에 이때는 변수의 스코프 규칙을 그대로 따른다.

Q.printName 에서 'inner is not defined' 라고 오류가 나지 않고, 'inner is not a function'이라는 TypeError가 나는 이유?

A.printName이 실행되는 순간 (Hoisting에 의해) inner 는 'undefined'으로 지정되기 때문 inner가 아니라 undefined라는 것은 즉, 아직은 함수로 인식이 되지 않고 있다는 것을 의미

**😺함수 표현식의 선언이 호출보다 아래에 있는 경우

 /* 오류 */
 function printName(firstname) { // 함수선언문
     console.log(inner); // ERROR!!
     let result = inner();  
     console.log("name is " + result);

     let inner = function() { // 함수표현식 
         return "inner value";
     }
 }

printName(); // > ReferenceError: inner is not defined

console.log(inner);에서 inner에 대한 선언이 되어있지 않기 때문에 inner is not defined 오류가 발생함.

✍호이스팅 우선순위

같은 이름의 var 변수 선언과 함수 선언에서의 호이스팅

  • 변수 선언이 함수 선언보다 위로 끌어올려집니다.
  var myName = "hi";

  function myName() {
      console.log("yuddomack");
  }
  function yourName() {
      console.log("everyone");
  }

  var yourName = "bye";

  console.log(typeof myName);
  console.log(typeof yourName);
/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 --- */
  // 1. [Hoisting] 변수값 선언 
  var myName; 
  var yourName; 
  
  

  // 2. [Hoisting] 함수선언문
  function myName() {
      console.log("yuddomack");
  }
  function yourName() {
      console.log("everyone");
  }

  // 3. 변수값 할당
  myName = "hi";
  yourName = "bye";

  console.log(typeof myName); // > "string"
  console.log(typeof yourName); // > "string"

✔값이 할당되어 있지 않은 변수와 값이 할당되어 있는 변수에서의 호이스팅


  var myName = "Heee"; // 값 할당 
  var yourName; // 값 할당 X

  function myName() { // 같은 이름의 함수 선언
      console.log("myName Function");
  }
  function yourName() { // 같은 이름의 함수 선언
      console.log("yourName Function");
  }

  console.log(typeof myName); // > "string"
  console.log(typeof yourName); // > "function"
  • 값이 할당되어 있지 않은 변수의 경우, 함수 선언문이 변수를 덮어 씀.
  • 값이 할당되어 있는 변수의 경우, 변수가 함수 선언문을 덮어 씀.

🚫 호이스팅 사용시 주의할 점

  • 코드의 가독성과 유지 보수를 위해 호이스팅이 일어나지 않도록 한다.
    *호이스팅을 제대로 모르더라도 함수와 변수를 가급적 코드 상단부에서 선언하면,호이스팅으로 인한 스코프 꼬임 현상은 방지할 수 있다.
    -var를 쓰면 혼란스럽고 쓸모없는 코드가 생길수 있으므로 const,let 을 사용
profile
개발새발자

0개의 댓글