그럼에도 불구하고

👨‍💻

[JavaScript] Pass by Reference / Pass by Value 란? 본문

JavaScript/JavaScript basics

[JavaScript] Pass by Reference / Pass by Value 란?

zenghyun 2022. 12. 19. 20:39

 

 

오늘은 Pass by Reference와 Pass by Value에 대해 알아보자

 

 

 

 

[ Pass by Reference ] 

object type을 객체 타입 또는 참조 타입이라고 한다.

참조 타입이란 객체의 모든 연산이 실제 값이 아닌 참조 값으로 처리됨을 의미한다.

원시 타입은 값이 한번 정해지면 변경할 수 없지만(immutable), 객체는 프로퍼티를 변경, 추가, 삭제가 가능하므로 변경 가능(mutable)한 값이라 할 수 있다. 

 

따라서 객체 타입은 동적으로 변화할 수 있으므로 어느 정도 메모리 공간을 확보해야 하는지 예측할 수 없기 때문에 런타임에 메모리 공간을 확보하고 메모리의 힙 영역(Heap Segment)에 저장된다.

 

이에 반해 원시 타입은 값(value)으로 전달된다. 즉, 복사되어 전달되며 이를 Pass by Value라 한다.

 

아래 예시를 보자

 

// Pass by Reference 

var num1 = {
	value : 100
}; 

var num2 = num1;
console.log(num1.value. num2.value); // 100 100 
console.log(num1 === num2); //true 

num2.value = 200; 
console.log(num1.value, num2.value); // 200 200 
console.log(num1 === num2); // true

 

 num1 객체를 객체 리터럴 방식으로 생성하였다.

이때 변수 num1은 객체 자체를 저장하고 있는 것이 아닌, 생성된 객체의 참조값(address)을 저장하고 있다.

 

 

변수 num2에 변수 num1의 값을 할당하였다. 변수 num1의 값은 생성된 객체를 가리키는 참조값이므로 변수 num2에도

같은 참조값이 저장된다.

 

 

즉, 변수 num1, num2 모두 동일한 객체를 참조하고 있다.

따라서 참조하고 있는 객체의 value 값이 변경되면 변수 num1, num2 모두 동일한 객체를 참조하고 있으므로 두 변수 모두 변경된 객체의 프로퍼티 값을 참조하게 된다.

 

 

다시 말해, 객체는 참조(Reference)방식으로 전달된다.  

결코 복사되지 않는다.

 

 

 

다음 예시를 보자. 

아래의 예시의 경우는 위의 경우와 약간의 차이가 있다.

 

var num1 = { value: 100 };
var num2 = { value: 100 };

console.log(num1.value, num2.value); // 100 100
console.log(num1 === num2);      // false

var num3 = num2;

console.log(num2.value, num3.value); // 100 100
console.log(num2 === num3);      // true

 

변수 num1과 변수 num2의 value 값은 동일하지만 별개의 객체를 생성하여 참조값을 할당하였다. 

따라서 변수 num1과 num2의 참조값 즉, 어드레스는 동일하지 않다.

 

 

하지만, 변수 num3에는 변수 num2의 값을 할당하였다. 

이 경우에는 변수 num3와 변수 num2는 동일한 객체를 가리키는 참조값을 저장하고 있다. 

따라서 변수 num3와 변수 num2의 참조값은 동일하다.

 

 

좀 더 쉽게 이해하기 위해 객체 자체만 선언하고 비교해보자 

 

var a = {}, b = {}, c = {}; // a, b, c는 각각 다른 빈 객체를 참조
console.log(a === b, a === c, b === c); // false false false

a = b = c = {}; // a, b, c는 모두 같은 빈 객체를 참조
console.log(a === b, a === c, b === c); // true true true

 


 

이번에는 함수를 이용한 Pass by Reference 예시를 보자 

 

function PassbyReference(obj){
	var tmp = obj.a;
    obj.a = obj.b; 
    obj.b = tmp; 
    
    console.log(`참조에 의한 변경 값 => a = ${obj.a} b = ${obj.b}`); 
    
  } 
  
  let obj {
   a: 10;
   b: 20;
 } 
 
 console.log(`Pass By Reference 함수 호출 전 => a = ${obj.a} b = ${obj.b}`); 
 
 PassbyReference(obj);
 
 console.log(`Pass By Reference 함수 호출 후 => a = ${obj.a} b = ${obj.b}`);

 

 

결과: 

 

Pass By Reference 함수 호출 전 -> a = 10 b = 20
참조에 의한 변경 값 -> a = 20 b = 10
Pass By Reference 함수 호출 후 -> a = 20 b = 10

 

함수에서 참조에 의한 전달도 마찬가지로 변수의 참조/주소를 인수로 직접 전달하여 함수를 호출한다.

따라서 함수 내부의 값을 변경하면 원래 값도 변경된다. Javascript에서 배열 및 객체는 참조 속성에 의한 전달을 따른다.

 

Pass by reference에서 인수로 전달된 매개변수는 자체적으로 사본을 생성하지 않고 원래 값을 참조하므로 함수 내부에서 변경한 사항은 원래 값에 영향을 미치게 된다. 

 

 

하지만 주의해야 할 점이 있다.

 

Pass by Reference에서 객체를 내부적으로 변경하면 객체에 영향을 미치지만,

객체를 인수로 전달하고 함수 컨텍스트에서 해당 객체의 참조를 업데이트한다면 객체 값에 영향을 미치지 않는다는 것이다.

 

 

예제 1과 예제 2의 차이를 유의해서 보자.

 

[ 예제 1 : 함수에서 객체를 참조하여 업데이트 ] 

 

function PassbyReference(obj) {
 
    // 객체 참조를 변경
    obj = {
        a: 10,
        b: 20,
        c: "UpdateValue"
    }
    console.log(`내부 PassByReference 함수 -> obj `);
         
    console.log(obj);
}
 
let obj = {
    a: 10,
    b: 20
 
}
console.log(` 객체 참조 업데이트 `)
console.log(`PassByReference 함수 호출 전 -> obj`);
console.log(obj);
 
PassbyReference(obj);

console.log(`PassByReference 함수 호출 후-> obj`);
console.log(obj);

 

결과:

 

객체 참조 업데이트 
PassByReference 함수 호출 전 -> obj 
{a: 10, b: 20} 
내부 PassbyReference 함수 -> obj 
{a: 10, b: 20, c: "UpdateValue"} 
PassByReference 함수 호출 후 -> obj 
{a: 10, b: 20}

 

 

[ 예제 2 : 원래 객체를 변경 ] 

 

function PassbyReference(obj) {
 
    // 원래 객체를 변경
    obj.c = "UpdateValue";
    console.log(`내부 PassbyReference 함수 -> obj `);
    console.log(obj);
}
 
let obj = {
    a: 10,
    b: 20
 
}
console.log(`원본 객체 변경 `)
console.log(`PassByReference 함수 호출 전 -> obj`);
console.log(obj);
 
PassbyReference(obj);

console.log(`PassByReference 함수 호출 후 -> obj`);
console.log(obj);

 

결과:

 

원본 객체 변경 
PassByReference 함수 호출 전 -> obj 
{a: 10, b: 20} 
내부 PassbyReference 함수 -> obj 
{a: 10, b: 20, c: "UpdateValue"} 
PassByReference 함수 호출 후 -> obj 
{a: 10, b: 20, c: "UpdateValue"}

 

즉, 함수에서 해당 객체의 참조를 업데이트 하는 것은 객체 값에 영향을 미치지 않지만,  함수 내부에서 객체 자체를 내부적으로 변경하면 객체에 영향을 미친다.

 

 

 

 


 

 

[ Pass by Value ]

원시 타입의 경우 값(value)으로 전달된다. 즉, 값이 복사되어 전달된다.

이를 Pass By Value(값에 의한 전달)이라 한다. 원시 타입은 값이 한번 정해지면 변경할 수 없으며, 이 값은 

런타임(변수 할당 시점)에 메모리의 스택 영역(Stack Segment)에 고정된 메모리 영역을 점유하고 저장된다. 

 

 

// Pass by Value
var a = 1;
var b = a;

console.log(a, b); // 1 1 
console.log(a === b); // true

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

 

변수 a는 원시 타입인 숫자 타입 1을 저장하고 있다. 원시 타입의 경우 값이 복사되어 변수에 저장된다.

즉, 참조 타입이 저장되는 것이 아니라 값 자체가 저장되기 때문에 변수 b에 변수 a를 할당할 경우, 변수 a의 값 1은 복사되어 변수 b에 저장된다.

 

 


 

 

이번에는 함수를 이용한 Pass by Reference 예시를 보자 

 

function Passbyvalue(a, b) {
    let tmp;
    tmp = b;
    b = a;
    a = tmp;
    console.log(`내부 Pass by value 함수 -> a = ${a} b = ${b}`);
}
 
let a = 1;
let b = 2;
console.log(`Pass by value 함수 호출 전 -> a = ${a} b = ${b}`);
 
Passbyvalue(a, b);
 
console.log(``Pass by value 함수 호출 후 -> a =${a} b = ${b}`);

 

결과:

 

Pass by value 함수 호출 전 -> a = 1 b = 2 
내부 Pass by value 함수 -> a = 2 b = 1 
Pass by value 함수 호출 후 -> a = 1 b = 2

 

함수에서의 Pass by Value는 변수의 값을 인수로 직접 전달하여 함수를 호출한다. 

 

 

따라서 함수 내부에서 변경한 내용은 원래 값에 영향을 주지 않는다.

 

 

ref :https://www.geeksforgeeks.org/pass-by-value-and-pass-by-reference-in-javascript/

'JavaScript > JavaScript basics' 카테고리의 다른 글

[JavaScript] 스코프(scope)란?  (0) 2022.12.21
[JavaScript] Immutability와 mutable  (0) 2022.12.19
[JavaScript] 단축 평가  (0) 2022.12.15
[JavaScript] 데이터 타입  (0) 2022.12.12
[JavaScript] 표현식과 문  (0) 2022.12.12
Comments