Coding

참조

토픽 Coding > JavaScript > JavaScript 소개

복제

전자화된 시스템의 가장 중요한 특징은 복제다. 현실의 사물과 다르게 전자화된 시스템 위의 데이터를 복제 하는데는 비용이 거의 들지 않는다. 바로 이러한 특징이 소프트웨어를 기존의 산업과 구분하는 가장 큰 특징일 것이다. 프로그래밍에서 복제가 무엇인가를 살펴보자.

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

결과

1

결과는 당연하다. 값을 변경한 것은 변수 b이기 때문에 변수 a에 담겨있는 값은 그대로이다. 변수 b의 값에 변수 a의 값이 복제된 것이다. 이를 그림으로 표시하면 아래와 같다.

 

참조

그런데 자연의 산물이 아니라 거대한 약속의 집합인 소프트웨어의 세계에서 당연한 것은 없다. 이것이 당연하지 않은 이유는 다음 예제를 통해서 좀 더 분명하게 드러난다.

var a = {'id':1};
var b = a;
b.id = 2;
console.log(a.id);	// 2

결과

2

이 코드의 주인공은 아래와 같다.

b.id = 2;
System.out.println(a.id);	

놀라운 차이점이 있다. 변수 b에 담긴 객체의 id 값을 2로 변경했을 뿐인데 a.id의 값도 2가 된 것이다. 이것은 변수 b와 변수 a에 담긴 객체가 서로 같다는 것을 의미하다. 참조(reference)의 세계에 온 것을 환영한다.

앞서 필자는 전자화된 세계에서 가장 중요한 특징으로 복제를 들었다. 그런데 복제만으로 전자화된 시스템을 설명하는 것은 조금 부족하다. 비유하자면 복제는 파일을 복사하는 것이고 참조는 심볼릭 링크(symbolic link) 혹은 바로가기(윈도우)를 만드는 것과 비슷하다. 원본 파일에 대해서 심볼릭 링크를 만들면 원본이 수정되면 심볼릭 링크에도 그 내용이 실시간으로 반영되는 것과 같은 효과다. 심볼릭 링크를 통해서 만든 파일은 원본 파일에 대한 주소 값이 담겨 있다. 누군가 심볼릭 링크에 접근하면 컴퓨터는 심볼릭 링크에 저장된 원본의 주소를 참조해서 원본의 위치를 알아내고 원본에 대한 작업을 하게 된다. 다시 말해서 원본을 복제한 것이 아니라 원본 파일을 참조(reference)하고 있는 것이다. 덕분에 저장 장치의 용량을 절약할 수 있고, 원본 파일을 사용하고 있는 모든 복제본이 동일한 내용을 유지할 수 있게 된다. 참조는 전자화된 세계의 극치라고 할 수 있다.

프로그래밍에서 광범위하게 사용하는 라이브러리라는 개념도 일종의 참조라고 할 수 있다. 공용 라이브러리를 사용하게 되면 하나의 라이브러리를 여러 애플리케이션에서 공유해서 사용하게 된다. 라이브러리의 내용이 변경되면 이를 참조하고 있는 애플리케이션에도 내용이 반영되게 된다. 또 우리가 변수를 사용하는 이유도 말하자면 참조를 위해서라고 할 수 있을 것이다. 본질을 파악하면 이해력도 높아지고 암기할 것도 줄어든다.

아래 두 개의 구문의 차이점을 생각해보자.

a = 1;
a = {'id':1};

무엇일까? 전자는 데이터형이 숫자이고 후자는 객체다. 숫자는 원시 데이터형(기본 데이터형, Primitive Data Types)이다. 자바스크립트에서는 원시 데이터형을 제외한 모든 데이터 타입은 객체이다. 객체를 다른 말로는 참조 데이터 형(참조 자료형)이라고도 부른다. 기본 데이터형은 위와 같이 복제 되지만 참조 데이터형은 참조된다. 모든 객체는 참조 데이터형이다. 이를 그림으로 나타내면 아래와 같다.

정리하면 변수에 담겨있는 데이터가 원시형이면 그 안에는 실제 데이터가 들어있고, 객체면 변수 안에는 데이터에 대한 참조 방법이 들어있다고 할 수 있다.

함수

그럼 일종의 변수할당이라고 할 수 있는 메소드의 매개변수는 어떻게 동작하는가를 살펴보자. 조금 복잡하므로 꼼꼼하게 살펴봐야 한다. 예제를 보자.

다음은 원시 데이터 타입을 인자로 넘겼을 때의 동작 모습이다.

var a = 1;
function func(b){
    b = 2;
}
func(a);
console.log(a);

결과

1

다음은 참조 데이터 타입을 인자로 넘겼을 때 동작하는 장면이다. 

var a = {'id':1};
function func(b){
    b = {'id':2};
}
func(a);
console.log(a.id);	// 1

결과는 아래와 같다.

1

함수 func의 파라미터 b로 전달된 값은 객체 a이다. (b = a) b를 새로운 객체로 대체하는 것은 (b = {'id':2}) b가 가르키는 객체를 변경하는 것이기 때문에 객체 a에 영향을 주지 않는다.

하지만 아래는 다르다.

var a = {'id':1};
function func(b){
    b.id = 2;
}
func(a);
console.log(a.id);	// 2

파라미터 b는 객체 a의 레퍼런스다. 이 값의 속성을 바꾸면 그 속성이 소속된 객체를 대상으로 수정작업을 한 것이 되기 때문에 b의 변경은 a에도 영향을 미치게 된다. 

참조

댓글

댓글 본문
  1. 코딩박
    2023.11.16. JavaScript 입문 수업 - 객체지향 - 참조 파트 수강했습니다.
  2. DreamBoy
    2023.10.17. JavaScript 입문 수업 - 객체지향 - 참조 파트 수강했습니다.
  3. 늦은개발자
    23.07.30 완료
  4. 진진리
    22.05.16
  5. 낀찐
    2022. 02. 06 완료
  6. pmxsg
    2021.12.18 수강
  7. 드림보이
    2021.12.12. 참조 파트 수강완료
  8. GelandeWagen
    ok
  9. Grit
    감사합니다.
  10. choi
    완료
  11. labis98
    20210822 good!!!
  12. 낭만고양이
    수강완료
  13. Amousk
    좋은 강의 감사합니다.
  14. hanel_
    21.3.13
  15. 손보선
    swap 함수를 구현해보면 언어별 특성을 잘 파악할 수 있겠더군요.

    https://m.blog.naver.com......%2F
  16. 자바스크립트에서 참조(주소)와 복제(값)의 차이는 c언의 call by reference(참조) 와 call by value(값)의 차이와 매우 유사하다.
    만약 변수를 원시데이터로 정의하면 이는 복제한 값이되며, 객체를 활용해 정의하면 참조한 값이된다.
  17. 강승
    감사합니다.
  18. 박병진
    2020.11.02 완강
  19. 허접신삥
    제가 알기론 함수 선언은 호이스팅 되기 때문에 그렇습니다.
    코드가 해석될 때 함수 선언 부분이 상위로 올라가서 해석돼서 코드에서 실행한 func 함수는 둘 다 두번째 함수가 되어버립니다.
    대화보기
    • 거룩한깜상
      오 저도 c의 포인터가 생각났어요
      대화보기
      • 한강
        예전에 c 공부할때 배웠던 내용과 비슷하네요. 감사합니다.~~^^!
      • Huma Norm
        감사합니다. 잘 보았습니다.
      • 아 함수명이 같았네요.
        답변 감사합니다.
        대화보기
        • 간단합니다. 한번에 두 개의 코드 스니펫을 작성하면
          함수의 경우 아래의 있는 함수에 위의 함수가 덮어쓰기(무시)되면서
          func 호출 시 아래에 있는 함수만 두 번이 호출되기 때문입니다.
          대화보기
          • 굼벵이
            완료
          • 강의 덕분에 참조와 복사의 개념을 잘 이해 했습니다.
            그런데 한 가지 이해가 안 되는 점이 있어서 질문 드립니다.

            첫 번째 코드 덩어리
            let a0 = { id: 1 };
            function func(v) {
            v = { id: 2 };
            }
            func(a0);
            console.log(a0.id); // 1
            위의 코드에서 출력이 1이 나오는 것도 이해가 가고

            두 번째 코드 덩어리
            let a1 = { id: 1 };
            function func(value) {
            value.id = 2;
            }
            func(a1);
            console.log(a1.id); // 2
            여기서도 2가 출력 되는것도 이해가 갑니다.

            그런데 문제는 위의 코드 덩어리 두개를 차례대로 쓸 경우
            이상하게도 첫 번째 코드 덩어리의 출력도 아래의 코드 덩어리(참조 샘플)와 같이 2로 바껴버립니다.


            2
            2
            이런 결과가 나와버립니다. 단지 두개의 코드 덩어리를 연달아 실행한다고 저런 결과가 나오는게
            이해가 안 가네요. 뭔가 연관된 것도 없고 전역 변수도 없는데...
            이유를 아시는 분은 조언을 부탁 드립니다.
          • 홍주호
            20191103 완료
          • 박창신
            완료
          • 심승경
            와... func(b)가 정의되고
            func(a)로 호출되었을 경우
            당연히 a = b라고 생각하고 함수를 해석해나갔는데 알고보니 b = a 라는 사실을 알고 정말 감탄했습니다..
            위에 코드들 중 헷갈리는 모든 부분이 한번에 해소되는 느낌입니다..
          • 김영기
            var a = {'id':1};
            function func(b){
            b = {'id':2};
            }
            func(a);
            console.log(a.id);

            결과가 2가 나옵니다.
          • 김진수
            var a = 1;
            function func(b){
            b = 2;
            }
            func(a);
            console.log(a);

            위에서 func(b)의 b(매개변수) 와 b = 2; 의 b 는 이름만 같지 서로다른건가요?
            아무리 생각해도 func(a); 실행했을때 a 가 함수안에 b = 2;에 b자리에 들어가는게 맞는거 같은데 그게 아닌거 같아서요
          • 호두
            20190211 , 고맙습니다
          • choon
            감사합니다.
          • 미완성
            20190109
          • Solar
            이해하기 쉬운 비유를 들어주셔서 좀 더 편하게 공부할 수 있었습니다. 감사합니다.
          • 김주현
            덕분에 객체에 대한 전반적인 개념을 잡아나가고 있습니다. 혼자 책으로써 독학하려니 여만저만 힘든것이 아니네요..
            좋은 강의 자료만들어 주신것 감사합니다.
            egoing님 덕분에 많은 사람들이 자신이 가고싶었지만, 다리가 없어 가지못햇던 길들을 하나하나 놓아주시고 계신것 같습니다. 그 많은 사람들 중에 하나가 바로 저이니깐요.
            수업 유익하고 재밌습니다. 어렵던 프로그래밍이 쉽게 이해가 되요. 소박한 꿈이지만, 먼 훗날 저의 꿈을 이룬다음
            opentutorials를 후원하는 후원 회원이 되고 싶습니다. 저와 같은 꿈을 꾸었던 사람들을 위해서요....
          • 스탐
            감사합니다.
          • 몽기징
            3번째 영상 함수와 참조 부분에서의 문의사항 입니다.
            영상 내용에서는 3가지 경우에 따라 원시데이터 또는 객체가 대입된 a의 출력값을 비교하였는데요
            경우별로 1/2/3 숫자를 붙여서 말씀드리면

            3. 참조를 통해 값에 접근하여 수정하는 경우

            var a = {'id':1};
            function func(b){
            b.id = 2;
            }
            func(a);
            console.log(a.id);

            에서는 2가 출력됩니다. 이는, func(a)를 통해 변수 a가 func()의 인자로 들어감으로써 참조를 통해 a.id 값으로 직접 접근하고, a.id=2;가 되어 결과적으로 앞서 선언된 var a = {'id':1};의 id에 대응하는 값이 1에서 2로 변경된다는 것으로 이해했습니다. 따라서 아래 코드와 위 코드가 동일하다고 말씀해주신것도 이해가 됩니다.

            var a = {'id':1};
            var b = a;
            b.id = 2;
            console.log(a.id); // 2

            문제는 1/2번입니다.

            1. 원시 데이터 타입을 인자로 넘겼을 때의 동작

            var a = 1;
            function func(b){
            b = 2;
            }
            func(a);
            console.log(a);

            에서는 1이 출력되는데, 위 흐름과 동일하게 생각해보면.. func(a)로 a가 func()의 인자로 들어가고, 따라서 a=2;가 실행되어 변수 a에 할당된 원시데이터 값이 1에서 2로 수정될 것 같은데. 생각과는 다르게 1이 출력되네요..
            또한 예시로 아래 코드와 동일하다고 말씀하셨는데, 위 코드에서 console.log(b);를 입력하면 에러가 나지만(인자 b가 함수 안에서만 선언되었기 때문이라고 생각하면 될까요? 지역변수일까요?), 아래 코드에서는 console.log(b);로 2가 출력됩니다. (이는 말씀해주신 것 처럼 var b=a;를 통해 a 값이 b에 복제되었고, 이후 b=2로 수정되었기 때문일 것입니다.) 위/아래 코드가 정말 동일하다고 볼 수 있는 것인가요?

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

            2. 참조 데이터 타입을 인자로 넘겼을 때의 동작

            var a = {'id':1};
            function func(b){
            b = {'id':2};
            }
            func(a);
            console.log(a.id); // 1

            이 예시도 역시 func(a)로 a가 func()의 인자로 들어가고, 따라서 a={'id':2};가 실행되어 변수 a에 할당된 객체의 id에 할당된 값이 2로 수정될 것이라 생각되는데 그렇지 않네요..

            마찬가지로 동일하다고 비교해주신 아래 코드에서 결과값이 1이 출력되는 것은 이해가 갑니다. b에는 id값이 2인 객체가 a와는 별도로 생성되었기 때문이지요. 다만 아래 코드의 경우 console.log(b.id);의 결과로 2가 출력 되지만, 위 코드에 console.log(b.id); 결과값은 undefined입니다.

            var a = {'id':1};
            var b = a;
            b = {'id':2};
            console.log(a.id);


            추가 질문.

            추가로 한가지 더 문의드리자면.. 예시에서 나온 아래 함수에서 b 앞에는 var이 사용되지 않았는데, 이럴 경우에 b는 전역변수인가요 지역변수인가요?? 전역변수라기엔 이전에 선언된 적이 없기에 혼란스러워서 문의드립니다.

            function func(b){
            b = {'id':2}; 또는 b = 2;
            }

            몇 달 간 생활 코딩을 통해 공부를 하며 대부분 반복 학습하다보면 이해가 되었는데, 이번 예는 이해가 도저히 되지 않아 문의드립니다. 좋은 강의 만들어주셔서 감사합니다.
          • def dict
            감사합니다! 완전 명강의네요
          • moon
            감사합니다.
          • 김진홍
            감사합니다!
          • 방파제
            원시데이터 타입을 대입하는 경우 C언어에 비유하자면 call by value 즉 , 값의 복제가 이루어지고
            객체를 대입하는 경우 call by reference 즉 , 값을 가르키는 주소가 대입되어 공유되기 때문에 조심해야한다
            이런 의미로 받아들이면 되는건가요?
          • Seo Yun Seok Tudoistube
            감사합니다.
            지난번 함수의 유효범위에서 var 를 붙이면 지역변수라고 배운 부분을 적용해서,
            함수부분 첫번째 예제에서 a 값이 2가 나오게 해보려고 콘솔에서 var 를 붙였다가 뗐다가 하는데
            계속 1만 나오네요. 이개념이랑 다른건가봐요^^;;

            함수2번째 예제에서 a 와 b 가 같은 값을 참조해서 원래는 한살림이었다가 b = {'id':2}; 로 a 와 b 는 각각 다른 살림으로 분가했다고 이해하면 되겠죠^^
            그런 의미에서 함수3번째 예제도 a 와 b 가 같은 값을 참조하는 한살림인건 공통점인거 같아요.

            외우기 싫은데 이해를 이제 제대로 하는거겠죠^^;;
          • jKei
            이미지 퍼가요
          • 박인호
            12-20
            수강완료.
            변수에 할당되는 값의 데이터타입이 중요하군요 결국은.
            원시데이터인지, 객체인지에 따라 복제, 참조로 각각 다르게 작동하게 되네요
          • Jupi
            아주 쉬워 보이는,
            var a = 1; 을 해석하자면,
            1이라는 숫자(원시데이터타입)을 생성하여, 변수 a에 대입한다.
            또한,
            var a = {'id' : 1};을 해석하면,
            id가 1이라는 객체를 생성하여, 변수 a에 대입한다.

            그리고, 변수에 변수를 대입할경우,
            var b = a; 를 해석하자면,

            ## a가 원시데이터타입을 가지고 있을때
            변수 a가 가지고 있는 숫자나 문자 불리언 을 *복사* 해서 변수 b에 대입한다.

            ## a가 객체를 가지고 있을때
            변수 a에 대입되어 있는 객체에 변수 b도 링크(참조)한다.
            즉, 변수 a와 변수 b는 같은 객체를 바라본다.

            이 두가지만 잘 이해하고 있으면 Ok
          • Gihoon Lim
            {id:1} -> {key:value}

            a와 b는 모두 id라는 key를 참조하고 있기 때문에
            b.id를 통해 value를 변경하면 a도 똑같이 변경된다.
          • GoldPenguin
            완료했습니다.
          • epsxk82
            맞습니다. C#이나 Java, Python처럼 Javascript도 가비지컬렉터가 메모리 관리를 자동으로 해줍니다.
            대화보기
            • 열공열공
              안녕하세요. 좋은 강의 감사드립니다.

              질문이 있는데요. 아래와 같은 코드의 경우, 처음에 변수 a가 { 'id':1} 의 객체를 참조 하고 있다가, 그 다음에 새로운 객체인 { 'name': 'Ku' } 객체를 참조 하게 될 텐데요. 그럼 객체 { 'id' : 1 } 은 메모리상에서 어떻게 되는 건가요?
              coding을 하는 사람은 메모리 관리도 신경을 써야 할텐데, javascript의 경우, 참조가 없는 경우에 자동적으로 메모리에서 삭제 되나요?

              var a = { 'id': 1}
              a = { 'name': 'Ku' }