본문 바로가기
코딩 정보/js

원시타입, 참조형 관련 헷갈리는 메소드를 정리해보자

by 꽁이꽁설꽁돌 2024. 11. 5.
728x90
반응형

목차

     

    원시  타입  

    string number bigint boolean undefined symbol null 총 7종류가 있다.                           

     

    변경 불가능한 값(immutable value)

    • 변경이 불가능하다는 뜻은 메모리 영역에서의 변경이 불가능하다는 뜻이다. 재할당은 가능하다
    • 변수에 할당될 때, 메모리의 고정 크기로 원시 값을 저장하고 해당 저장된 값을 변수가 직접적으로 가리키는 형태를 띈다.
    • 재할당 시 기존 값이 변하는것 처럼 보일지 몰라도 사실 새로운 메모리에 재할당한 값이 저장되고 변수가 가리키는 메모리가 달라졌을 뿐이다.

    예시

    let a = 100;
    let b = a;
    a = 50;
    
    console.log(b) // 100

     

    즉 메모리에는 100과 50이란 값이 모두 존재하고 있으며, 앞에서 말했듯이 원시타입은 불변성을 갖고 있기 때문에 기존에 메모리에 생성된 값들은 그 자체가 변경될 수 없다. 그저 식별자와 연결 되있는 메모리가 바뀌었기에 우리 눈에는 재할당 된 것처럼 보일뿐이다.

     

    참조형

    자바스크립트에서 원시 타입 이외의 모든 값은 참조형(Reference Type) 객체(Object) 타입이며 대표적으로 배열, 함수 그리고 객체가 있다. 기본형(Primitive type)과의 차이점은 변경 가능한 값(mutable value), 즉 변수의 크기가 동적으로 변한다는 것이다.

     

     

    map vs foreach

    map

    map()은 배열 내의 모든 요소 각각에 대하여 주어진 함수(콜백)를 호출한 결과를 모아 새로운 배열을 반환한다는 특징을 가지고 있다.

    const arr = [1, 2, 3, 4, 5];
    const mulArr = arr.map(num => num * 3);
    
    console.log(arr) //[1, 2, 3, 4, 5] -> 원본 배열 영향x
    console.log(mulArr); // [3, 6, 9, 12, 15]

     

     

    foreach

    forEach()는 문밖으로 리턴값을 받지 못한다. 

    let arr = [1,2,3,4,5];
    let a = arr.forEach(function(value){
    	return value;
    });
    console.log(a);   //undefined

     

    -> 핵심은 forEach() 기존의 Ararry를 변경하는 반면, map()은 새로운 Ararry를 반환한다.

     

     

    forEach 주의사항

    원시 타입 vs 참조 타입

    //원시 타입일때
    let b = [1, 2, 3];
    b.forEach((el) => {
      el += 1;  // `el`의 값은 증가하지만, 원본 배열의 요소와는 별개임
    });
    console.log(b);  // 여전히 [1, 2, 3]
    
    //참조 타입일때
    let c = [{ value: 1 }, { value: 2 }, { value: 3 }];
    c.forEach((el) => {
      el.value += 1;  // 객체의 속성값을 수정하면 원본 배열도 영향을 받음
    });
    console.log(c);  // [{ value: 2 }, { value: 3 }, { value: 4 }]

     

    slice vs splice

     slice

    slice() 메서드는 어떤 배열의 begin 부터 end 까지(end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다. 원본 배열은 바뀌지 않습니다.

    let fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
    let citrus = fruits.slice(1, 3);
    
    // fruits contains ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
    // citrus contains ['Orange','Lemon']

     

    그렇다면 문자열에서는 어떨까?

    문자열은 원시 타입(primitive type)으로, JavaScript에서 불변(immutable) 객체입니다. 따라서 slice를 사용할 때 원본 문자열은 전혀 변경되지 않고, 새로운 문자열을 반환한다.

    let str = "Hello, World!";
    let slicedStr = str.slice(0, 5);
    
    console.log(str); // "Hello, World!"
    console.log(slicedStr); // "Hello"

     

    splice

    문자열에서는 못쓰고 배열에만 사용 가능

    원본 배열을 건드리기 때문에 주의 해야한다.

    const months = ['Jan', 'March', 'April', 'June'];
    months.splice(1, 0, 'Feb');
    // Inserts at index 1
    console.log(months);
    // Expected output: Array ["Jan", "Feb", "March", "April", "June"]
    
    months.splice(4, 1, 'May');
    // Replaces 1 element at index 4
    console.log(months);
    // Expected output: Array ["Jan", "Feb", "March", "April", "May"]

     

    slice와 splice의 차이를 보여주는 예

    > nums = Array(20).fill().map((_, i) => i)
    < [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    > nums.slice(5, 8) // slice() 1회 호출
    < [5, 6, 7]
    > nums.slice(5, 8) // slice() 2회 호출
    < [5, 6, 7]
    > nums.slice(5, 8) // slice() 3회 호출
    < [5, 6, 7]
    > nums.slice(5, 3) // splice() 1회 호출
    < [5, 6, 7]
    > nums.splice(5, 3) // splice() 2회 호출
    < [8, 9, 10]
    > nums.splice(5, 3) // splice() 3회 호출
    < [11, 12, 13]
    반응형