JavaScript에서 변수 할당은 어떻게 작동합니까?


97

그래서 저는 자바 스크립트에서 대량 할당이 정확히 어떻게 작동하는지 확인하기 위해 며칠 동안 놀았습니다.

먼저 콘솔에서이 예제를 시도했습니다.

a = b = {};
a.foo = 'bar';
console.log(b.foo);

결과는 경고에 "막대"가 표시되었습니다. 즉 공정의 충분하다, a그리고 b정말 같은 객체 단지 별칭이다. 그런 다음 어떻게이 예제를 더 간단하게 만들 수 있을지 생각했습니다.

a = b = 'foo';
a = 'bar';
console.log(b);

그것은 거의 똑같지 않습니까? 이번에 는 첫 번째 예제의 동작에서 예상했던대로 반환 foo되지 않습니다 bar.

왜 이런 일이 발생합니까?

NB 이 예제는 다음 코드를 사용하여 훨씬 더 단순화 할 수 있습니다.

a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);

a = 'foo';
b = a;
a = 'bar';
console.log(b);

(자바 스크립트가 문자열과 정수와 같은 프리미티브를 해시와 다르게 취급한다고 생각합니다. 해시는 포인터를 반환하고 "코어"프리미티브는 자신의 복사본을 반환합니다)


여기에 할당 설명 : syntaxsuccess.com/viewarticle/…
TGH

답변:


114

첫 번째 예에서는 기존 개체의 속성을 설정합니다. 두 번째 예에서는 새로운 개체를 할당합니다.

a = b = {};

ab같은 객체에 대한 포인터는 지금. 그래서 당신이 할 때 :

a.foo = 'bar';

그것은 설정 b.foo이후뿐만 아니라 ab포인트 같은 객체.

하나!

대신 이렇게하는 경우 :

a = 'bar';

a지금은 다른 대상 을 가리키고 있습니다. 이것은 a이전에 지적한 것에 영향을 미치지 않습니다 .

JavaScript에서 변수 할당과 속성 할당은 두 가지 다른 작업입니다. 변수를 개체에 대한 포인터로 생각하는 것이 가장 좋습니다. 변수에 직접 할당 할 때는 개체를 수정하는 것이 아니라 변수를 다른 개체로 다시 지정하는 것입니다.

그러나 같은 속성을 할당하면 가리키는 a.foo객체가 수정 a됩니다. 물론 이것은 모두 동일한 객체를 가리 키기 때문에이 객체를 가리키는 다른 모든 참조도 수정합니다.


3
"당신은 지금 다른 물체를 가리키는 것입니다." 아니요, 개체라는 단어를 사용하지 마십시오. 문자열은 JavaScript에서 객체가 아닙니다.
Nosredna

9
문자열은 기술적으로 자바 스크립트 유형 "Object"가 아니지만 OO의 의미에서 객체로 생각할 수 있습니다.
Alex Wayne

2
@Squeegy : 문자열은 객체가 아닌 원시입니다. 문자열에 임의의 속성을 할당 할 수 없습니다! 그들은 자바에서 오토 박싱이라고 불리는 것 때문에 객체처럼 행동 할뿐입니다
Christoph

11
그러나 문자열에는 메서드와 속성이 있으며 String의 프로토 타입은 확실히 수정할 수 있습니다. 그들은 확실히 물건처럼 행동합니다.
Cameron Martin

9
@ddlshack : Christoph가 설명했듯이 이것은 오토 박싱 때문입니다. 를 통해 문자열을 정의한다면 var foo = new String('foo');, 그것은 문자열 객체가 될 것입니다 (그리고 typeof이것을 확인할 것입니다). 그러나 문자열 리터럴을 통해 선언하면 문자열 프리미티브입니다. 참조 : developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
Lèse majesté

26

귀하의 질문은 이미 Squeegy에 의해 만족스럽게 답변되었습니다. 객체 대 기본 요소와는 아무 관련이 없지만 동일한 참조 객체에서 변수 재 할당 대 속성 설정과 관련이 있습니다.

답변과 주석에서 JavaScript 유형에 대해 많은 혼란이있는 것 같으므로 다음은 JavaScript의 유형 시스템에 대한 간단한 소개입니다.

자바 스크립트에는 근본적으로 다른 두 종류의 값이 있습니다. 프리미티브와 객체입니다 ( '해시'와 같은 것은 없습니다).

문자열, 숫자, 부울뿐만 아니라 null하고 undefined있다 프리미티브 객체는 속성을 가질 수있는 모든 수 있습니다. 배열과 함수조차도 일반 객체이므로 임의의 속성을 보유 할 수 있습니다. 내부 [[Class]] 속성 만 다를뿐입니다 (함수에는 [[Call]] 및 [[Construct]]라는 속성이 추가로 있지만 세부 사항입니다).

프리미티브 값이 객체처럼 작동하는 이유는 오토 박싱 때문이지만 프리미티브 자체는 속성을 보유 할 수 없습니다.

다음은 예입니다.

var a = 'quux';
a.foo = 'bar';
document.writeln(a.foo);

이것은 다음을 출력 할 것입니다 undefined: a속성을 할당 할 때 객체로 승격되는 원시 값을 보유합니다 foo. 그러나이 새 개체는 즉시 삭제되므로의 값 foo이 손실됩니다.

다음과 같이 생각하십시오.

var a = 'quux';
new String(a).foo = 'bar'; // we never save this new object anywhere!
document.writeln(new String(a).foo); // a completly new object gets created

Mozilla Foundation의 페이지 'A re-introduction to JavaScript (JS tutorial)'에서는 JavaScript 객체를 "이름-값 쌍의 간단한 모음으로 설명합니다. 따라서 ...와 유사합니다."다음 사전 목록, 해시 , 해시 테이블 및 다양한 프로그래밍 언어의 해시 맵. 동일한 페이지에서 해시 테이블 조회로 개체 속성 참조를 설명합니다. 따라서 객체는 '해시'테이블과 같은 모든 것입니다. 이것은 다른 유용한 정보를 무효화하지는 않지만 Chris Lloyd의 원래 특성화는 정확하지 않았습니다.
C 퍼킨스

2

"해시"라고 부르는 것이 실제로는 Object에 대한 속기 구문이라는 점을 제외하고는 다소 정확합니다.

첫 번째 예에서 ab는 모두 동일한 객체를 참조합니다. 두 번째 예제에서는 다른 것을 참조하도록 a 를 변경 합니다 .


그렇다면 Object에 대한 이중 표준이 필요한 이유는 무엇입니까?
Chris Lloyd

이중 표준이 아닙니다. 첫 번째 예에서 a와 b는 여전히 동일한 객체를 참조하며 해당 객체의 속성을 수정하는 것입니다. 두 번째 예에서는 다른 물체를 가리키고 있습니다.
Kevin

1
아니요, 차이점은 두 번째 경우에는 객체가 아니라 문자열을 처리한다는 것입니다.
Nosredna

1
명확하게 말하면, 이것은 자신의 복사본을 반환하는 문자열과 관련이 없습니다. 두 코드 스 니펫이 다른 이유는 Kevin의 두 번째 단락에 있습니다 (Squeegy의 답변에서 더 자세히 설명 됨).
Chuck

변수에 문자열이나 객체가 있는지 여부는 중요하지 않습니다. 새롭고 다른 값을 할당하면 변수에 새롭고 다른 값이 포함됩니다.
sth

2

여기에 내 버전의 답변이 있습니다.

obj = {a:"hello",b:"goodbye"}
x = obj
x.a = "bonjour"

// now obj.a is equal to "bonjour"
// because x has the same reference in memory as obj
// but if I write:
x = {}
x.a = obj.a
x.b = obj.b
x.a = "bonjour"

// now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
// because x points to another place in the memory

0

a는 새 문자열 객체를 가리 키도록 설정하고 b는 이전 문자열 객체를 계속 가리 킵니다.


0

첫 번째 경우에는 변수에 포함 된 개체의 일부 속성을 변경하고 두 번째 경우에는 변수에 새 값을 할당합니다. 그것은 근본적으로 다른 것입니다. 변수가 ab어떻게 든 마술 첫 임무로 연결되지 않은, 그들은 단지 동일한 개체가 포함되어 있습니다. b변수에 새 값을 할당 할 때까지 두 번째 예제에서도 마찬가지입니다 .


0

차이점은 단순 유형과 객체입니다.

객체 (배열 또는 함수 등) 인 모든 것은 참조로 전달됩니다.

단순한 유형 (문자열 또는 숫자와 같은)은 복사됩니다.

나는 항상 copyArray 함수를 편리하게 사용하므로 동일한 배열에 대한 많은 별칭을 만들지 않을 것입니다.


차이점은 많은 시나리오에서 눈에 띄지 않지만 Javascript는 실제로 참조로 전달되거나 할당되지 않습니다. 참조 값을 복사합니다.
Juan Pablo Califano

이 사람들은 이미 그것을 설명하는 좋은 작업을 했으므로 링크를 붙여 넣을 것입니다. stackoverflow.com/questions/40480/is-java-pass-by-reference (나는 Java를 참조하지만 전달 및 할당에 대한 의미는 값 / 참조는 자바 스크립트와 동일)
Juan Pablo Califano

1
실제로이 대답은 올바르지 않으며 모든 것이 JavaScript의 값으로 전달됩니다. MDN에서 "함수 호출의 매개 변수는 함수의 인수입니다. 인수는 값으로 함수에 전달됩니다. 함수가 인수의 값을 변경하면이 변경 사항은 전역 적으로 또는 호출하는 함수에 반영되지 않습니다. 그러나 객체 참조는 다음과 같습니다. 값도 특별합니다. 함수가 참조 된 객체의 속성을 변경하면 해당 변경 사항이 함수 외부에 표시됩니다. " developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
bittersweetryan

프리미티브는 불변 객체처럼 작동합니다 ( 엄격 모드에서와 똑같이 ). 이 대답은 정확하지 않습니다.
Ry-
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.