L-value와 R-value 에 대한 고찰
참고 : http://cafe.daum.net/codeinside/b7EL/17
일단 이글을 쓰게 된 계기가 존재하는데 그 계기는 http://blog.pj-room.com/63 이 글에 대한 답변을 생각하면서 이다.
계기는 JavaScript 에 의해 L-value 와 R-value 에 대해 생각하게 되었으나, 문제에 대한 원론적인 이해는 단지 JavaScript 라는 언어에 국한된것이 아니란 것을 깨닳게 되어
본 포스닝을 남겨볼까 한다.
해당 링크를 보면 맨 마지막에 "(a.foo)(); 은 vv 가 출력되지만 (a.foo = a.foo)(); 은 ad 가 출력되는 원인이 위의 이유이기 때문이다." 이러한 문장이 존재한다.
마지막 문장을 가만히 곱씹어본 결과 해당 글의 내용으로는 상세한 설명이 되지 않는다는 결론을 내리게 되었다.
우선 이 깨닳음을 얻게된 계기를 마련해준 @codeoverME(daum) 님과 @드보(daum) 님께 감사의 말을 드리고 싶다.
보통 잘못 알고 있는 사람들이 int a = 123; 이 코드에 대해 = 연산자를 기준으로 왼쪽인 a 가 L-Value이며 오른쪽인 123이 R-Value 라고 생각하고 있다.
이는 잘못알고 있는 내용이며 L-Value 와 R-Value의 정의에 대해 먼저 집고 넘어가볼까 한다.
L-Value의 경우 데이터가 저장된 메모리 영역을 추척할 수 있는 값을 L-Value 라고 칭하며 a = 123 에서 a 라는 변수 이름은 운영체제가 메모리에 123이라는 값을 보관하기 위한 메모리 주소의 aliasing 된 이름이므로 a 라는 변수를 통해 123이라는 값이 저장된 메모리 주소를 추적이 가능하므로 a 는 L-Value 가 되며 반면
123의 경우 메모리 주소에 값을 넣기 위한 임시 데이터 이므로 이는 CPU의 레지스터를 통해 메모리에 직접 기록되게 된다. 따라서 123 값만으로는 메모리 주소를 추적할 수 없으므로 R-Value 라고 불리게 된다.
본론부터 말하자면 Javascript 에서의 (a.foo) 의 경우 L-Value로 취급되므로 인터프리터가 a라는 객체를 통해 호출되었다는 것을 추적 할 수 있게 되지만, (a.foo = a.foo)의 경우 R-Value로 취급되어 a 라는 객체를 통해 호출되었다는 객체 추적을 수행하지 못해 this 객체를 global 객체로 자동 바인딩 시켜버리는 것이다.
이와 같이 L-Value 와 R-Value를 올바르게 이해하게 되면 (a.foo)(); 는 vv 가 출력되지만 (a.foo = a.foo)();는 this가 global 객체를 바인딩하여 ad가 출력된다는 의미를 이해할 수 있게 된다.
이를 간단한 코드만으로 확인이 가능한데 아래와 같이 F12 개발자 도구의 콘솔창의 테스트를 수행하게 되면
위와 같이 Invalid left-hand side in assignment 라는 오류가 발생한 것을 알수 있으며 이는 L-Value 가 아니므로 대입연산이 수행되지 않아 실패된다는 의미로 해석이 가능하다.
위의 문제점으로 인해 (a.foo = b.foo)() 에서의 (a.foo = b.foo)는 R-Value 로 취급되어 foo 함수 객체의 데이터 그 자체를 의미하게 되며 이를 즉시실행하므로 객체추적을 하지 못해 ad 가 출력되는 것 이다.