holdanddeepdive/javascript-deep-dive

[번역] 자바스크립트는 pass-by-reference / pass-by-value 중 어떤 언어일까?

Opened this issue · 1 comments

참조 : https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language

해당 질문에도, 자바스크립트 자체를 어떤 언어다 라고 정의하는게 의미기 있겠냐 는 이야기가 나오고, 답변의 종류도 여러가지 인 걸 보면 하나의 정답이 있다고 생각하진 않습니다. 그래도,

  1. pass-by-reference/value를 구분하는 기준
  2. JS동작 원리를 설명할 수 있는 새로운 용어의 등장

등을 중점으로 보다보면 재밌습니다. 그럼 이따봐요~

질문

primitive type(number, string)은 pass-by-value이고 object는 pass-by-reference이다.

그렇다면 JavaScript는 뭐라고 정의할 수 있을까?

답변1

👍🏻1800

function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(num, obj1, obj2);

console.log(num); //10
console.log(obj1.item); //changed
console.log(obj2.item); //unchanged
  • 만약 obj1 이 reference가 아니라면 ⇒ 함수안에서 obj1.item을 수정하는건 전혀 obj1에 영향을 주면 안된다.
  • 만약 argument가 reference라면 ⇒ num100으로 바뀌어야하고, obj2item“changed”로 바뀌어야한다.

우리는 이걸 call-by-sharing 이라고 부른다.

답변 2

👍🏻500+

pass-by-value이다. 객체를 넘기면 객체의 멤버를 수정할 수 있는 것 때문에, pass-by-reference처럼 보인다. 그러나 오브젝트 변수 자체에 할당이 이루어지지 않기때문에 pass-by-value 이다

It's always pass by value, but for objects the value of the variable is a reference. Because of this, when you pass an object and change its members, those changes persist outside of the function. This makes it look like pass by reference. But if you actually change the value of the object variable you will see that the change does not persist, proving it's really pass by value.

Example:

function changeObject(x) {
  x = { member: "bar" };
  console.log("in changeObject: " + x.member);
}

function changeMember(x) {
  x.member = "bar";
  console.log("in changeMember: " + x.member);
}

var x = { member: "foo" };

console.log("before changeObject: " + x.member);
changeObject(x);
console.log("after changeObject: " + x.member); /* change did not persist */

console.log("before changeMember: " + x.member);
changeMember(x);
console.log("after changeMember: " + x.member); /* change persists */

Output:

before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar

답변3

👍🏻80

pass-by-value / pass-by-reference는 중요하지 않다. 이 개념은 JS보다 훨씬 이전에 생성되었으며 JS의 semantics를 정확하게 묘사할 수 없다.

다음 세가지를 고려해서 나는 “pass-by-pointer” 라고 하고싶다. (JS에서 우리는 포인터를 쓰지 않지만 내부엔진에서는 사용하기 때문)

  1. 변수는 값에 대한 포인터이다.
  2. 변수에 값을 재할당하면 변수는 새로운 값을 포인팅한다.
  3. 변수를 재할당해도 동일한 개체를 가리키던 다른 변수에는 영향을 미치지 않습니다. 각 변수는 자체 포인터를 가지고 있기 때문입니다.(?)
// code
var obj = {
    name: 'Fred',
    num: 1
};

// illustration
               'Fred'
              /
             /
(obj) ---- {}
             \
              \
               1
// code
obj.name = 'George';

// illustration
                 'Fred'

(obj) ---- {} ----- 'George'
             \
              \
               1
// code
obj = {};

// illustration
                 'Fred'

(obj)      {} ----- 'George'
  |          \
  |           \
 { }            1
// code
var obj = {
    text: 'Hello world!'
};

/* function parameters get their own pointer to
 * the arguments that are passed in, just like any other variable */
someFunc(obj);

// illustration
(caller scope)        (someFunc scope)
           \             /
            \           /
             \         /
              \       /
               \     /
                 { }
                  |
                  |
                  |
            'Hello world'
  • "pass by value/reference" 는 언어의 동작을 설명할 순 있지만 내부 구현방식을 설명하진 않는다. 이런 추상화때문에, 중요한 설명을 놓칠 수 있고, 추가설명이 필요해진다.
  • primitive가 object와는 별개의 특별한 룰을 가진것처럼 보이지만, 결국 primitives는 단순하게 pointer의 끝이다.
  • 마지막으로, array가 예상처럼 동작하지 않는 이유를 생각해봐라
var a = [1,2];
var b = a;

a = [];
console.log(b); // [1,2]
// doesn't work because `b` is still pointing at the original array

결론: JS를 call by reference나 call by value중에 하나로 결정지을 수 없지만, 이런 논의가 흥미로운 답변을 끌어내는 것 같다.

  • cf. Java는 call by value
    • 객체가 전달될때마다 복사됨