[javascript] JavaScript는 참조 기준 또는 값 기준 언어입니까?

기본 유형 (숫자, 문자열 등)은 값으로 전달되지만 값을 통해 전달 될 수 있기 때문에 객체를 알 수 없습니다 (객체를 보유한 변수가 실제로 객체를 참조하는 것으로 간주하는 경우) ) 및 참조로 전달 (객체에 대한 변수가 객체 자체를 보유하고 있다고 생각할 때).

마지막에는 중요하지 않지만, 규칙을 통과하는 논쟁을 제시하는 올바른 방법이 무엇인지 알고 싶습니다. JavaScript 사양에 대한 발췌문이 있습니까? 이것에 대한 의미론을 정의해야합니다.



답변

JavaScript에서 흥미 롭습니다. 이 예제를 고려하십시오.

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);
console.log(obj1.item);
console.log(obj2.item);

출력이 생성됩니다.

10
changed
unchanged
  • 경우 obj1다음 변경, 전혀 참조하지 않았다 obj1.item상의 영향이 없을 것입니다 obj1함수의 외부.
  • 인수가 적절한 참조라면 모든 것이 변경되었을 것입니다. num100, 그리고 obj2.item읽을 것이다 "changed".

대신, 전달 된 품목이 값으로 전달되는 상황입니다. 그러나 가치에 의해 전달되는 항목 자체 는 참조입니다. 기술적으로이를 공유 호출 이라고 합니다 .

당신은 매개 변수 자체 (와 같이 변경하면 실제적인 측면에서,이 방법은 numobj2), 그 매개 변수에 공급 된 항목에 영향을 미치지 않습니다. 그러나 매개 변수 의 내부 를 변경하면 (와 같이 obj1) 전파됩니다 .


답변

항상 값으로 전달되지만 객체의 경우 변수 값이 참조입니다. 이로 인해 객체를 전달하고 멤버 를 변경하면 해당 변경 사항이 함수 외부에 유지됩니다. 이것은 참조로 전달하는 것처럼 보입니다 . 그러나 실제로 객체 변수의 값을 변경하면 변경 사항이 지속되지 않고 실제로 값을 통과한다는 것을 알 수 있습니다.

예:

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 */

산출:

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

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


답변

변수는 객체를 “보유”하지 않습니다. 참조를 보유합니다. 해당 참조를 다른 변수에 할당 할 수 있으며 이제 둘 다 동일한 객체를 참조합니다. 항상 값으로 전달됩니다 (값이 참조 일 때도).

매개 변수로 전달 된 변수가 보유한 값을 변경할 방법이 없습니다. JavaScript가 참조로 전달을 지원하는 경우 가능합니다.


답변

내 두 센트 … 이것이 내가 이해하는 방식입니다. (내가 틀렸다면 자유롭게 고쳐주십시오)

이제 당신이 아는 모든 것을 가치 / 기준으로 전달할 때입니다.

JavaScript에서는 값으로 전달되는지 또는 참조로 전달되는지 여부는 중요하지 않습니다. 중요한 것은 함수에 전달 된 매개 변수의 돌연변이 대 돌연변이입니다.

자, 제가 의미하는 바를 설명하기 위해 최선을 다하겠습니다. 몇 가지 물건이 있다고 가정 해 봅시다.

var object1 = {};
var object2 = {};

우리가 한 것은 “할당”… 변수 “object1″과 “object2″에 2 개의 별도의 빈 개체를 할당했습니다.

이제 object1을 더 좋아한다고 가정 해 봅시다. 그래서 새로운 변수를 “할당”합니다.

var favoriteObject = object1;

다음으로, 어떤 이유로 든 객체 2를 더 좋아하기로 결정합니다. 그래서 우리는 단순히 약간의 재 할당을합니다.

favoriteObject = object2;

object1 또는 object2에 아무런 변화가 없습니다. 우리는 데이터를 전혀 변경하지 않았습니다. 우리가 한 일은 우리가 가장 좋아하는 물건을 다시 할당하는 것입니다. object2와 favoriteObject가 모두 동일한 오브젝트에 지정되어 있음을 알아야합니다. 변수 중 하나를 통해 해당 개체를 변경할 수 있습니다.

object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe

자, 예를 들어 문자열과 같은 프리미티브를 살펴 보겠습니다.

var string1 = 'Hello world';
var string2 = 'Goodbye world';

다시, 우리는 마음에 드는 것을 골라냅니다.

var favoriteString = string1;

우리의 favoriteString과 string1 변수는 모두 ‘Hello world’에 할당됩니다. 이제 favoriteString을 변경하려면 어떻게해야합니까 ??? 무슨 일이 일어날 것???

favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'

어 .. 무슨 일이야. favoriteString을 변경하여 string1을 변경할 수 없습니다 … 왜 ?? 문자열 객체를 변경 하지 않았기 때문 입니다. 우리가 한 것은 favoriteString 변수 를 새 문자열 에 “RE ASSIGN”하는 것뿐입니다 . 이것은 본질적으로 string1에서 연결을 끊었습니다. 이전 예제에서 객체의 이름을 바꿀 때 아무 것도 할당하지 않았습니다. ( 변수 자체가 아니라 , name 속성을 새 문자열에 할당했습니다.) 대신, 단순히 2 개의 변수와 기본 개체 사이의 연결을 유지하는 개체를 변경했습니다. ( 문자열 객체 자체 를 수정하거나 변경 하려는 경우에도문자열은 실제로 JavaScript에서 변경할 수 없기 때문에 가질 수 없었습니다.)

이제 함수와 매개 변수 전달에 대해 … 함수를 호출하고 매개 변수를 전달할 때 기본적으로 수행하는 작업은 새 변수에 “할당”하는 것입니다. 등호 (=) 부호

이 예제들을 보자.

var myString = 'hello';

// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment

console.log(myString); // Logs 'hello'
console.log(param1);   // Logs 'world'

자, 똑같은 기능이지만

function myFunc(param1) {
    param1 = 'world';

    console.log(param1);   // Logs 'world'
}

var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);

console.log(myString); // logs 'hello'

자, 이제 함수없이 먼저 객체를 사용하는 몇 가지 예를 들어 보겠습니다.

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;

// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl

console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'

// Now, let's reassign the variable
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';

자, 똑같은 것이지만 함수 호출

function myFunc(otherObj) {

    // Let's mutate our object
    otherObj.firstName = 'Sue';
    console.log(otherObj.firstName); // Logs 'Sue'

    // Now let's re-assign
    otherObj = {
        firstName: 'Jack',
        lastName: 'Frost'
    };
    console.log(otherObj.firstName); // Logs 'Jack'

    // Again, otherObj and myObject are assigned to 2 very different objects
    // And mutating one object doesn't magically mutate the other
}

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);

console.log(myObject.firstName); // Logs 'Sue', just like before

이 글 전체를 읽으면 JavaScript에서 함수 호출이 어떻게 작동하는지 더 잘 이해할 수있을 것입니다. 무언가가 참조에 의해 전달되는지 또는 가치에 의해 전달되는지는 중요하지 않습니다 … 중요한 것은 할당 대 돌연변이입니다.

변수를 함수에 전달할 때마다 등호 (=) 기호를 사용하는 것처럼 매개 변수 변수의 이름이 무엇이든 “할당”됩니다.

항상 등호 (=)는 할당을 의미합니다. JavaScript에서 매개 변수를 함수 전달하는 것도 할당을 의미한다는 것을 항상 기억하십시오 . 그것들은 동일하고 2 개의 변수는 정확히 같은 방식으로 연결됩니다 (즉, 동일한 객체에 할당되었다고 계산하지 않는 한 그렇지 않습니다).

“변수 수정”이 다른 변수에 영향을 미치는 유일한 시간은 기본 개체가 변경되는 경우입니다 (이 경우 변수를 수정하지 않고 개체 자체).

객체와 프리미티브를 구별 할 필요는 없습니다. 왜냐하면 함수가없는 것과 같은 방식으로 작동하고 등호를 사용하여 새 변수에 할당했기 때문입니다.

함수에 전달하는 변수의 이름이 함수 매개 변수의 이름과 같은 경우가 유일한 문제입니다. 이런 일이 발생하면 함수 내부의 매개 변수를 함수 전용의 완전히 새로운 변수 인 것처럼 취급해야합니다.

function myFunc(myString) {
    // myString is private and does not affect the outer variable
    myString = 'hello';
}

var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';

myFunc(myString);
console.log(myString); // Logs 'test'


답변

다음을 고려하세요:

  1. 변수는 메모리의 값을 가리키는 포인터 입니다.
  2. 변수를 다시 할당하면 해당 포인터가 새로운 값을 가리 킵니다.
  3. 변수를 다시 할당해도 동일한 객체를 가리키는 다른 변수에는 영향을 미치지 않습니다

그래서 잊어 “참조 / 값에 의해 패스” 에 끊었되지 않기 때문에 “참조 / 값 통과”

  1. 이 용어는 언어 의 동작 을 설명하는 데만 사용되며 실제 실제 구현은 아닙니다. 이러한 추상화의 결과로, 적절한 설명에 필수적인 중요한 세부 사항이 손실되며, 이는 단일 용어가 실제 행동을 적절하게 설명하지 못하고 추가 정보를 제공해야하는 현재 상황으로 이어질 수밖에 없습니다
  2. 이 개념은 원래 자바 스크립트를 설명하려는 의도로 정의되지 않았으므로 혼란에 빠질 때만 사용하도록 강요하지 않습니다.

귀하의 질문에 대답하기 위해 : 포인터가 전달됩니다.

// 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'

마지막 의견 :

  • 프리미티브 는 특수 규칙에 의해 시행되는 반면 객체 는 그렇지 않지만 프리미티브는 단순히 포인터 체인의 끝 이라고 생각하고 싶어합니다 .
  • 마지막 예로 배열을 지우는 일반적인 시도가 예상대로 작동하지 않는 이유를 고려하십시오.

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


답변

함수 외부의 객체는 외부 객체에 대한 참조를 제공하여 함수로 전달됩니다.

해당 참조를 사용하여 객체를 조작하면 외부 객체가 영향을받습니다. 그러나 함수 내부에서 다른 것에 대한 참조를 가리 키기로 결정한 경우 외부에있는 객체에 전혀 영향을 미치지 않았습니다.


답변

이것을 다음과 같이 생각하십시오 : 그것은 항상 가치를 지니고 있습니다. 그러나 객체의 값은 객체 자체가 아니라 해당 객체에 대한 참조입니다.

다음은 숫자 (원시 유형)를 전달하는 예입니다.

function changePrimitive(val) {
    // At this point there are two '10's in memory.
    // Changing one won't affect the other
    val = val * 10;
}
var x = 10;
changePrimitive(x);
// x === 10

이것을 객체와 함께 반복하면 다른 결과가 나타납니다.

function changeObject(obj) {
    // At this point there are two references (x and obj) in memory,
    // but these both point to the same object.
    // changing the object will change the underlying object that
    // x and obj both hold a reference to.
    obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
// x === { val: 100 }

하나 더 예 :

function changeObject(obj) {
    // Again there are two references (x and obj) in memory,
    // these both point to the same object.
    // now we create a completely new object and assign it.
    // obj's reference now points to the new object.
    // x's reference doesn't change.
    obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
// x === { val: 10}