>  기사  >  웹 프론트엔드  >  javascript_javascript 스킬에서 연속 할당 연산을 사용하여 발생하는 문제점에 대해 이야기해 보세요.

javascript_javascript 스킬에서 연속 할당 연산을 사용하여 발생하는 문제점에 대해 이야기해 보세요.

WBOY
WBOY원래의
2016-05-16 15:29:361098검색

머리말

기사 제목에 있는 이 문장은 원래 외국 JavaScript 사양에서 볼 수 있었던 내용인데, 최근 JS의 연속 할당 연산의 특징(함정)이 버그로 발견되기 전까지는 그다지 주목을 받지 못했습니다.

온라인 검색 결과 연속 할당의 아주 좋은 예를 찾았습니다(소스 1, 소스 2):

var a = {n:1};
a.x = a = {n:2};
console.log(a.x); // 输出?

답은 다음과 같습니다.

console.log(a.x); // undefined

답이 맞으셨는지 모르겠지만, 적어도 저는 틀렸습니다.

그래서 이번 기회에 JS 연속과제가 어떻게 이루어지는지 자세히 살펴보았습니다

과제순서요?

A=B=C; 코드가 있다고 가정하면 할당문의 실행 순서는 오른쪽에서 왼쪽이므로 문제는 다음과 같습니다.

추측 1: B = C;

아니면 2를 추측해 보세요: B = C;

우리 모두는 두 객체가 동시에 한 객체를 가리키면 다음과 같이 이 객체에 대한 수정이 동기화된다는 것을 알고 있습니다.

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

이 기능을 기반으로 연속 할당 순서를 테스트할 수 있습니다.

추측 1에 따르면 C를 특정 객체로 대체하면 첫 번째와 두 번째 줄이 실행될 때 두 개의 {n:1}이 생성되므로 a의 수정이 b로 동기화되지 않음을 알 수 있습니다. 예:

var b={n:1};
var a={n:1};
a.n=0;
console.log(b);//Object {n: 1}

추측 2에 따르면 C를 특정 객체로 대체하면 a와 b가 동시에 객체를 참조하기 때문에 a의 수정이 b로 동기화되는 것을 볼 수 있습니다.

var b={n:1};
var a=b;
a.n=0;
console.log(b);//Object {n: 0}

진정한 연속 할당 테스트:

var a,b;
a=b={n:1};
a.n=0;
console.log(b);//Object {n: 0}

추측 2와 일치함을 알 수 있습니다. 누구든지 이 테스트가 부정확하다고 느끼면 다시 테스트해보고 ECMA5의 setter 및 getter 기능을 사용하여 테스트할 수 있습니다.

우선 변수에 실제로 저장된 객체가 아닌 변수 이름에 setter와 getter가 적용되는 방식은 다음과 같습니다.

Object.defineProperty(window,"obj",{
 get:function(){
  console.log("getter!!!");
 }
});
var x=obj;
obj;//getter!!! undefined
x;//undefined

obj만 "getter!!!"를 출력하지만 x는 출력하지 않는 것을 볼 수 있습니다. 이 기능을 사용하여 테스트하세요.

연속과제 테스트 2:

Object.defineProperty(window,"obj",{
 get:function(){
  console.log("getter!!!");
 }
});
a=b=obj;//getter!!! undefined

getter를 통해 다시 확인하면 A=B=C에서 C는 한 번만 읽혀집니다.

따라서 연속 할당의 실제 연산 규칙은 B = C; A = B입니다. 즉, 연속 할당은 항상 등호 오른쪽에 있는 표현식 결과만 오른쪽에서 왼쪽으로 가져와서 왼쪽에 할당합니다. 등호 옆.

계속과제는 따로 작성할 수 있나요?

위에서 실제 연속 할당의 규칙을 확인할 수 있습니다. 그런 다음 위의 규칙에 따라 연속 할당을 분할하면 결과가 다음과 같이 달라지는 것을 알 수 있습니다. 다음과 같이:

var a={n:1};
a={n:2};
a.x=a;
console.log(a.x);//Object {n: 2, x: Object}

그래서 연속 할당문은 오른쪽에서 왼쪽으로 할당하는 규칙을 따르지만 여전히 별도의 명령문으로 작성할 수는 없습니다.

내 추측으로는 대입문의 정확성을 보장하기 위해 js는 대입문을 실행하기 전에 먼저 할당할 모든 참조 주소의 복사본을 꺼낸 다음 값을 하나씩 할당합니다.

그래서 이 코드의 논리는 다음과 같습니다.

1. 실행하기 전에 a와 a.x의 참조 주소가 먼저 제거됩니다. 이 값은 {n:1}

을 가리킵니다.

2. 메모리에 새 개체 {n:2}를 만듭니다

3. a={n:2}를 실행하고 a의 참조를 {n:1}을 가리키는 것에서 새로운 {n:2}을 가리키는 것으로 변경합니다

4. a.x=a를 실행합니다. 이때 a는 이미 새 개체를 가리키고, a.x는 실행 전에 원래 참조를 유지하므로 a.x는 여전히 원래 {n:1} 개체를 가리킵니다. 새 객체가 원본 객체에 제공됩니다. 이제 콘텐츠가

인 {n:2} 속성 x를 추가합니다.

5. 명령문 실행이 종료되고 원본 객체는 {n:1}에서 {n:1,x:{n:2}}로 변경되며 더 이상 참조하는 사람이 없기 때문에 원본 객체는 GC에 의해 재활용됩니다. 현재 새 객체에 대한 점 {n:2}

6. 따라서 기사 시작 부분에 실행 결과가 있고 a.x를 실행하면 자연스럽게 정의되지 않습니다

위 프로세스는 일련번호로 설명됩니다.

위 프로세스에 따르면 이전 a.x와 새 a.x는 모두 새로 생성된 객체 {n:2}를 가리키므로 합동이어야 함을 알 수 있습니다.

테스트:

var a = {n:1};
var b = a;
a.x = a = {n:2};
console.log(a===b.x); //true

원래 객체에 대한 참조를 추가한다는 의미인 var b=a를 추가했기 때문에 위의 5단계에서는 해제되지 않으므로 위의 결론이 확인됩니다.

후기

이번 시간을 통해 연속과제의 특징에 대해 알게 되었어요. 기사 제목을 다시 보니

로 불러야 할 것 같습니다.

JS의 내부 메커니즘과 가능한 결과를 실제로 이해하지 않는 한 JS의 연속 할당 작업을 사용하지 마세요.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.