ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 값에 의한 vs 참조에 의한
    Web/JavaScript 2020. 1. 6. 20:37

     

     

    자바스크립트를 공부하다 보면 C언어에서 매개변수로 값을 줄 때와 포인터를 줄 때처럼 명확한 표현 방식이 없음을 마주할 때가 있다. 그렇다면 어떻게 자바스크립트는 이 둘을 구분할까?

     

    데이터 값 조작 방식으로 값에 의한(by value) 방식과 참조에 의한(by reference) 방식이 존재한다. (이하 값, 참조)

    값을 통해 조작하는 경우는 기본 타입이라고 볼 수 있다. 예시로 숫자, 불리언, 문자열이 있다.

    참조를 통해 조작하는 경우는 참조 타입인데, 객체(배열, 함수 등)가 그러하다.

     

    위 두 가지의 차이점을 보면 참조 타입은 메모리의 크기가 불분명하기 때문에 메모리를 비효율적으로 많이 사용하는 경우에 속한다. (문자열은 이후에 다시 설명)

     

    var n = 1; // 숫자, 문자열, 불리언은 기본 타입 
    var m = n;
    
    function add_to_total(total, x){
        total += x;
    }
    add_to_total(n, m);
    console.log(n,m) // n은 1일까 2일까
    -------------------------------------------------------------------------------------
    var arr = [1,2];
    var temp = arr;
    
    function add_to_array(array, x){
        for(var i = 0; i < array.length; i++){
            array[i] += x;
        }
    }
    
    add_to_array(arr, 2)
    console.log(arr, temp) // arr과 temp는 어떻게 출력될까
    
    var temp2 = arr.slice(); // slice에 의한 얕은 복사(shallow copy)
    add_to_array(arr, 1);
    
    console.log(arr, temp2) // arr과 temp2는 어떻게 출력될까 
    ---------------------------------------------------------------------------------------
    var arrTotal = [1,2,3];
    function add_to_totals(totals, x){
        var newTotals = new Array(3);
        newTotals[0] = totals[0] + x;
        newTotals[1] = totals[1] + x;
        newTotals[2] = totals[2] + x;
        totals = newTotals;
        
        console.log(totals, newTotals)
    }
    add_to_totals(arrTotal, 2);
    console.log(arrTotal); // arrTotal은 어떻게 출력될까

    먼저 기본 타입의 경우를 살펴보자.

    기본 타입은 값에 의한 참조이기 때문에 함수 내에서 실행된 결과 값이 n에 영향을 끼치지 않는다.

    고로 n과 m은 1을 출력하게 된다.

     

    두 번째로 참조 타입에서 배열의 경우를 살펴보자.

    temp는 배열 [1,2]를 참조하는 변수 arr을 통해 배열 [1,2]를 참조하게 된다.

    이후 함수를 통해 arr의 요소 값이 변하게 되고, 참조를 통해 변경되었기 때문에 arr과 temp 모두 [3,4]를 출력하게 된다.

     

    그 밑에 var temp2 = arr.slice(); 라는 식이 있는데 이는 얕은 복사(shallow copy)를 통해 arr을 복사해서 temp2에 대입시켜주는 것이다. 복사를 이용했으므로 arr과 temp2는 별개의 배열을 서로 가리키게 되며, add_to_array를 통해 arr의 값을 변경시켰을 때 arr과 temp2는 서로 다른 결과를 출력하게 된다.

     

    마지막의 코드를 살펴보자.

    arrTotal이라는 변수가 배열[1,2,3]을 참조하도록 하였고, 이후 add_to_totals라는 함수에 매개변수로 제공하게 된다.

    add_to_totals 함수에선 새로운 배열 newTotals를 선언하고, 이후 arrTotal의 각 요소에 x를 더한 값을 가지게 된다.

    그리고 totals = newTotals를 통해 totals라는 변수가 newTotals가 가리키는 값과 동일한 값을 가지게 된다.

     

    그렇다면 맨 마지막 코드인 arrTotal은 어떻게 출력될까? add_to_totals라는 함수의 인자로 전달된 arrTotal은 totals라는 변수에 [1,2,3]에 대한 참조를 덮어쓰게 한다. 이후 totals가 newTotals라는 배열의 참조를 전달하는데, 이렇게 함수 내부에서 전달받은 참조가 함수 내부의 새로운 객체나 배열의 참조를 덮어쓸 경우, 함수 외부의 객체나 배열에는 영향을 끼치지 않는다.

    고로 arrTotal은 [1,2,3]을 출력하게 된다.

     

    문자열을 살펴보자.

    문자열은 길이가 임의적이므로 참조 타입들이 가지는 특성을 가지고 있기 때문에 자칫 참조 타입처럼 보인다.

    이를 알아보기 위해 위의 코드처럼 문자열을 바꾸는 식의 코드를 작성하고 싶지만, 문자열에는 그러한 조작방식이 존재하질 않는다.

    var str = 'hello'
    str[0] = 'a'
    
    console.log(str); //aello?

    str을 출력하게 되면 hello를 출력하는 것을 알 수 있다. 위 코드처럼 임의의 문자열을 변경할 수 있는 방식이 존재하지 않기 때문이다.

    그렇다면 어떻게 값에 의해 전달되는지 참조에 의해 전달되는지를 알 수 있을까?

    그건 바로 우연히 두 변수가 동일한 값을 갖게 되었을 때 두 변수가 동일한 지를 살펴보면 된다.

    var str1 = 'catnap'
    var str2 = 'catna' + 'p';
    if(str1 === str2) console.log(str1,str2);

    위 코드를 통해 문자열 또한 기본 타입임을 알 수 있게 된다.

     

     

    댓글

Designed by Tistory.