이클립스에서 Android Application 실행 시 USB로 연결 된 안드로이드 기기를 제대로 인식하지 못한다면,


adb가 설치되어 있는 곳으로 가서


adb kill-server

adb start-server

sudo adb devices


를 실행해주자




저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

원본: https://cirw.in/blog/time-to-move-on

번역: 우너효


MVC 패턴은 정말 멋진 생각입니다. 상태를 담고 있는 독립적인 모델과, UI를 가지고 있는 독립적인 뷰, 그리고 무언가를 가지고 있는 독립된... 읭?


MVC 패턴을 적용해 보셨다면 아시겠지만, 코드를 어디에 넣어야 할 지 몰라서 결국 컨트롤러에만 수많은 코드를 꾸역꾸역 넣어본 경험이 있으실 겁니다. 이러한 문제점이 있음을 깨달은 건 비단 저 뿐만은 아니겠지요.


이를 해결하기 위해 저는 새로운 패턴을 사용했습니다. 

바로 MOVE 패턴입니다. 

Models, Operations, Views, 그리고 Events.



Overview

MOVE를 적용한 애플리케이션의 구조

자세한 얘기에 앞서, 위의 다이어그램은 MOVE 패턴을 적용한 애플리케이션의 기본 구조를 나타내고 있습니다.

  • 모델은 애플리케이션이 알아야 할 모든 것을 담고 있습니다.
  • 오퍼레이션은 애플리케이션이 해야 할 모든 것을 담고 있습니다.
  • 뷰는 애플리케이션과 유저 간의 징검다리 역할을 합니다.
  • 이벤트는 모든 요소들이 잘 어우러지게끔 하는 역할을 합니다.

스파게티 코드가 되는 사태를 막기 위해, 타입 별 객체들이 할 수 있는 일에 대해 정해 놓는 것은 정말 중요한 일입니다. 저는 그러한 점을 다이어그램에 화살표로 표시해 놓았습니다. 예를 들어서, 뷰는 모델에 의해 생겨난 이벤트를 받습니다. 그리고, 오퍼레이션은 모델을 변경할 수 있지만, 뷰나 오퍼레이션을 참조해서는 안됩니다.


Models

전형적인 모델 객체는 바로 "user"가 되겠습니다. 적어도 이메일 주소가 있겠고, 이름이나 전화번호도 있을 수 있겠죠. MOVE 애플리케이션에서 모델은 'knowledge'만을 담고 있습니다. 이는 모델 내에 getter와 setter 함수 이외에도, "이게 정말 그 user의 비밀번호가 맞아?"라는 식의 함수가 있을 수도 있다는 겁니다. 하지만, 그러한 정보를 데이터베이스에 저장하거나, 외부 API를 통해 업로드를 하는 함수는 없습니다. 그러한 작업은 오퍼레이션에 의해 처리가 되어야 합니다. 


Operations

애플리케이션의 일반적인 오퍼레이션은 사용자 로그인일 겁니다. 사실 이는 2개의 서브 오퍼레이션(sub-operation)으로 구성되어 있다고 볼 수 있습니다. 하나는 사용자로부터 이메일 주소와 비밀번호를 받는 거고, 다른 하나는 데이터베이스에서 "user" 모델을 불러와 앞서 받은 이메일 주소와 비밀번호의 일치여부를 확인하는 겁니다.

MOVE 패턴에서 오퍼레이션은 행동대장(!?)이라 볼 수 있습니다. 모델을 변경하고, 적절한 때에 적절한 뷰를 보여주고, 사용자의 입력에 의해 발생한 이벤트에 적절한 반응을 하게 됩니다. 잘 만들어진 애플리케이션이라면, 각각의 서브 오퍼레이션들은 해당 부모로부터 독립적으로 실행이 되어야 합니다. 위의 다이어그램의 오퍼레이션 안을 봤을 때, 이벤트들의 흐름은 위로 이루어지고 변화는 아래로 이루어지는 이유가 바로 그 때문입니다. 

오퍼레이션을 이런 식으로 사용할 경우 여러분이 만든 애플리케이션 자체가 프로그램이 부팅 될 때 하나의 오퍼레이션으로 처리될 수 있기 때문에 정말 좋습니다. 서브 오퍼레이션들은 필요한 만큼 만들어져 동시에 존재하고, 병렬적으로 실행이 되며, 작업을 모두 마치고 나면 프로그램을 종료하게 됩니다.


Views

로그인 화면은 사용자에게 몇 개의 텍스트 상자를 보여주는 뷰에 해당합니다. 사용자가 뷰에 있는 "로그인" 버튼을 클릭할 경우, 사용자가 입력한 '이메일 주소'와 '비밀번호'를 담고 있는 "로그인시도(loginAttempt)"라는 이벤트를 만들게 됩니다. 

사용자에게 보여줘야 하거나, 사용자가 조작해야 할 것들은 반드시 뷰를 통해 제공되어야 합니다. 애플리케이션의 상태를 이해하기 쉽게 나타내야 할 뿐 아니라, 끊임 없는 사용자의 조작을 잘 처리하여 의미 있는 이벤트로 만들어야 합니다. 

뷰는 모델을 직접 변경하지 않고, 오퍼레이션에 이벤트를 보내게 됩니다. 그리고 모델에 의해 발생된 이벤트를 통해 변경 사항을 알게 됩니다.


Events

사용자가 로그인을 클릭했을 때 해당 뷰는 "로그인시도"라는 이벤트를 보내게 됩니다. 그리고 로그인 오퍼레이션이 완료될 경우, "현재사용자(currentUser)" 모델이 변경되었음을 알리는 이벤트를 애플리케이션에 보내게 됩니다. 

이벤트에 대한 리스닝(listening)은 MOVE (그리고 MVC)로 하여금 제어의 역전(Inversion of Control)이 가능케 합니다. 즉, 어떠한 뷰를 업데이트 해야 할지 모델이 알지 못하더라도, 뷰를 업데이트 할 수 있게 됩니다. 이는 컴포넌트들이 서로 간섭하지 않고도 연결되어 작동할 수 있게 해주는 매우 강력하고 추상적인 기법입니다.


Why now?

MVC 패턴을 적용하는 게 나쁘다고 말하는 건 아닙니다. 지난 수십 년 간,  대규모의 애플리케이션을 만드는 데 적용된 MVC 패턴은 매우 성공적이었으니까요. 하지만 MVC 패턴이 만들어진 이후로도, 많은 프로그래밍 기법들이 유명세를 탔습니다. 클로저(혹은 익명 블록)가 없었다면 이벤트 바인딩은 매우 힘들었을 겁니다. 그리고 deferrables(deferreds 혹은 promises) 가 없었다면, 개별 오퍼레이션을 객체로 다루는 아이디어는 생겨나지도 못했을 겁니다.


마치며

물론 MVC 패턴은 훌륭합니다. 다만, 몇십 년 전의 예전 기술로 만들어졌다는 점을 말하고 싶습니다. 

MOVE는 현재 우리가 사용하는 새로운 도구들을 더 잘 사용할 수 있게 해주는 업데이트일 뿐입니다.


추신

이러한 생각을 한 건 비단 저 뿐만이 아닐 겁니다. 

만약 MOVE에 동의하신다면, objectifyinteractions를 활용하셔서 MVC 애플리케이션에 MOVE의 장점을 추가해보세요. 

이와 관련하여 추천하고 싶거나 알고 있는 링크가 있다면 여기로 알려주시기 바랍니다.


추추신

이 포스트는 여기 저기에 일본어로 번역이 되었으며, 러시아어, 스페인어로도 번역이 되었습니다. 고마워요!

저작자 표시
신고
Posted by 우너효

ListView나 GridView를 구현할 때, overlap 되어 있는 view에 가려지게 하지 않기 위해 padding 값을 주는 경우가 있다.


스크롤을 통해 해당 overlap 된 View를 사라지게끔 할 수 있는데, 이 때 사라진 View로 인해 넣어준 padding 범위까지 ListView나 GridView의 내용을 보여주고 싶으면


clipToPadding:false


속성을 지정해주면 된다







적용 후 그리드뷰의 모습. 상단에 Padding이 적용되어 살짝 아래로 내려와 있다.







기존에 GridView의 상단에 위치해 있던 Spinner는 스크롤 시 사라지고,

ClipToPadding:false 로 인해 GridView의 내용이 스크롤 시 상단의 Padding영역까지 모두 보여지게 된다.



저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

출처: 성대사랑 대찬

http://www.skkulove.com/ver3/bbs/board.php?bo_table=fb2014&wr_id=323973&sfl=recom


대학 신입생때만 해도 나만큼은 재미없는 월급쟁이인생 안살 줄 알았지만 뭐 결국 이렇게 살고 있다. 

그나마 서울 중심에서 일할 수 있다는 것으로 만족하며 산다.

시기가 시기인만큼 후배들중에도 몇주뒤면 사회생활을 시작하는 친구들이 많을 것이라 생각한다.

얼마뒤에 신입공채+인턴정규직전환+대외활동정규직전환 된 귀여운 신입애들 들어오는 자리가 마련되어 있는데, 그 시절 생각도 나고 그때 미리 알았더라면 덜 실수했을텐데 하는 것들을 중심으로 써보려 한다.

먼저 이 글은 소위 이야기하는 대기업 기반으로 쓴다는 것을 밝혀둔다.

아무래도 소규모의 중소기업이나 현장기반의 제조업같은 곳은 기업문화가 다를 수도 있어서 그런 점은 양해 바란다.

물론 업종별 편차가 발생하는데 해당 부분은 최대한 배제하고 기술하려 했으니 일반적인 사회생활을 위한 참조글 정도로 보면 감사하겠다.





가) 근태

늦지말자

너무 당연한 이야기라 생각하지만 이거 못지키는 애들 은근히 있다.

돈을 받고 일을 하는 조직인데 이건 기본 항목이다.

과하게 일찍올 필요도 없고 출근시간 10~15분전 정도에 오면 된다.

통상적으로 한달정도는 신입에게 일을 제대로 시키지 않고 probation 기간을 둔다. (실제로 1~3개월 수습기간을 두는 경우가 대부분)

소위 첫인상이 해당기간동안 결정되는데 니가 보일 수 있는 역량은 아무것도 없다.

딱 Attitude 정도가 실질적인 평가항목이 되는건데 근태는 여기에 가장 큰 비중을 차지한다.

니가 10분을 늦으면 2시간을 야근해도 성실하다는 인상을 절!대!로! 줄 수 없다.

뿐만 아니라 "늦는 인간"이라는 인상을 한번 심어주면 실제로 불가피한 경우(아프다던지 가까운 사람 상이 생긴다던지 등등)

너의 사유들이 핑계로 비춰질 수 있다는 치명적인 문제가 발생한다.

더불어 출근 뿐만 아니라 각종 회의, 약속도 늦지 마라.

이건 부서간/팀원간 기본 예절에 어긋나는 부분으로 잘못하면 오만하다는 오해를 불러일으킬 수 있다.


나) 신입 mind

배운다는 자세를 취하고 의사를 적극 표명해라.

신입사원은 실질적인 업무를 할 수 없다.

멍청하고 무능력해서가 아니라 회사 업무란 원래 업에 대한 이해도와 타부서 협업이 제반되어야 하므로

사실상 반년 가량은 일을 "배우는 시기"라 할 수 있다.

바꿔 얘기하자면 신입인 너는 간단한 일을 받아도 어떻게 해야할지 막막해지는 경우가 빈번할 수 밖에 없다.

이럴 때 필요한건 자존심을 내려놓는 일이다.

알아서 할 생각하지 말고 반드시 물어봐라.

너에게 주어진 일은 보통 가벼운 일이기 때문에 기존 파견/계약직 직원이 하던 일일 수도 있고,

혹은 아무도 하지 않던 하나마나 한 menial한 일일 수도 있다.

그런 하찮은 일이라고 묻는게 부끄러워 해서는 안된다. (혹은 서류상 너보다 낮은 파견/계약직이 하던 일이라 부끄러워하지 마라)

첫 몇달은 원래 그러라고 있는 기간이고 아무도 "너"를 하찮게 보지 않는다.

오히려 그정도 일도 안물어봐서 잘못된 결과를 내면 이딴것도 못하는 찐따로 더더욱 욕을 쳐먹게 될 것이므로 그냥 물어봐라.

자주 묻고 익혀나가는 태도는 오히려 긍정적인 평가를 받을 수 있다.

다만 한두번 설명해줬는데 안적어놓고, 혹은 이해 안가는데 알아듣는척 하고 똑같은 얘기를 몇번이나 반복한다면 욕처먹어도 어쩔 수 없는 거다.

남이 시간들여 설명해주면 많아도 두번 이내 이해할 수 있게 노력하던가 못알아듣겠으면 적어놔라.



다) 눈치

넌 이미 너를 제외하고는 짧게는 몇달~ 길게는 몇년을 함께 지낸 사람들이 모여있는 조직에 홀로 새롭게 들어가는거다.

그들의 조직엔 나름대로의 룰이 있고 니가 보기엔 뭔가 이상하지만 기존의 히스토리에 따라 암묵적으로 형성된 공감대라는게 있다.

반드시 그걸 이해하고 받아들일 필요는 없다만 앞으로 그 팀/회사를 나오기 전 까진 그 안에서 생활해야 한다.

즉 그 조직에 니가 이질감/거부감을 유발시키는 존재가 될 필요는 없단 소리다.

남들이 어떤 얘기를 하는지 잘 듣고, 가급적 그들과 함께 섞일 수 있는 존재임을 인지시켜줘라.

남들이 웃을 때 함께 웃고 그들이 싫어하는 행위는 가급적 하지 말아라.

그리고 그들이 좋아하는 토픽을 캐치해서 적정선까지 제시해주고 동참해라.

부서내 인기인이 될 필요는 없지만 신입은 가만히만 앉아있어도 주목을 끄는 만큼 눈치없는 티를 내면 곤란하다.


라) 로열티

막상 들어가면 많은 윗사람들이 여긴 왜 왔냐~ 갈 수 있으면 딴데가라 등등 본인의 신세한탄을 너에게 할 것이다.

처음에는 ‘아닙니다 만족합니다’ 등으로 회피하겠지만 

횟수가 지속되면 너도모르게 편해져서 ‘아 사실 제가 00기업 떨어지고 왔는데... %$$#$’.....................

이런 볍신같이 같이 회사 까고 앉았지 마라.

신세한탄이니 회사까는건 그건 그들이니까 하는 소리고

넌 "저는 이 회사가 아직 좋은데 과장님만큼 다니면 저도 싫어질까요?" 정도로 받아넘겨라.

신입이 회사 까봐야 얻는건 니 뒷욕 뿐이다.

다만 과도한 회사 숭배나 역시 욕처먹는 지름길


마) 동기

이건 정말 너무 중요하다.

니 동기는 니가 자주 컨택하는 부서부터 같이 일하지 않는 부서까지 다양하게 포진될거다.

1년, 2년 니 업력이 쌓이면서 점점 더 중요해지는건 유관부서와의 협업인데 동기의 인맥은 이럴때 엄청난 자산이 된다.

따라서 동기중에 찌질이가 있어도 넌 입닫고 좋은 놈으로 남아서 좋은 관계를 유지해둬라.

공식적인 업무상 인맥으로 관계를 쌓은 사람들은 딱 그만큼의 정보만 공유하지만

동기는 어느정도 친구적인 부분이 있기 때문에 그 이상의 정보력을 너에게 제공한다.

뿐만 아니라 유관부서 협업자가 "이건 저희 업무가 아닙니다" 하면서 자를 일도

너의 동기라면 "동기니까" 해주게 되는 경우가 많다.

너무 실리적으로 생각하는거 아니냐라고 할 수 있지만 그만큼 동기는 직장생활에서 큰 자산이 되므로

본인이 회사생활 오래할 생각이 조금이라도 있다면 반드시 동기와는 좋은 관계를 유지해둬라. 퇴근하고 피곤하다고 동기모임 빠지거나 하는 만행은 저지르지 말고


바) 겸손

잘난척 금지.

직업을 얻는 행위는 학벌과 스펙이 큰 도움이 되지만 업무 자체는 사실상 업력과 성실도가 더 크게 영향을 미친다.

물론 그 와중에도 서울대는 오~ 해주는건 있지만 그렇다고 그 자체가 직장생활에 직접적 도움이 되는건 아니다.

실제로 특출난 한두명이 가끔 있긴 하지만 대부분은 기본적으로 서류/시험/면접등을 통과해서 뽑힌 애들의 자질은 큰 차이 없다.

나는 잘나서 더 크고 대단한 일을 할 수 있을 것 같지만 너 빼고도 다 잘나고 대단한 일 할줄 아는 사람들임.

진짜 잘난 애들은 오히려 티를 안내는데 꼭 어줍잖게 학생 때 대외활동이니 인턴이니 창업이니 쬐금 깨작거려본 애들이 깝치다가 된통 당하는 경우가 많으니 주의 요망

더불어 신입 3개월차부터 1/2년차정도에 본인이 하고 있는 업무가 나름 대단하거나 중요한 일이라고 착각하는 경우가 많은데

안타깝게도 그건 99%정도는 본인만의 착각인 경우다.

파견직부터 사장까지 모두 자기 일은 나름 대단한 일이라고 속으로 생각한다.

솔직하게 말하자면 어느 조직도 신입이나 사원에게 크거나 대단한 일은 주지 않는다.

그런 일을 할 역량이 덜 갖춰진 탓도 있지만, 사실 그보다 잘못되었을 때 책임을 질 수 있는 위치기 아니기 때문도 있다.

자신의 업무를 폄하할 필요도 없지만 대단한 일이라고 착각하는건(심지어 그걸 입 밖에 내는건) 3년 이불킥 감이다.

짧게 얘기하자면 업무적 자부심과 책임감은 가지되 겸손함은 가지고 있어라.


(Tip 예시)

똑같이 신입을 받은 팀들이면 서로 자기네 신입이 더 우수하다고 믿고 싶어한다. 부서간의 경쟁심리랄까...

그럴 때 다른 동기보단 니가 낫다는걸 (직접적으로 말고 우회적으로) 증명할 수 있는 인증을 부서장에게 쥐어주는 센스를 발휘할 수 있다면

넌 부서장 기를 세워줄 수 있고, 너도 인정을 받을 수 있어 일타쌍피다.

그렇다고 동기를 까서는 안된다. 유일하게 그나마 믿을 수 있는 인맥은 동기라고 생각해야한다.



성실함, 책임감, 밝은 태도, 친화력 등등 같은 더 뻔한 소리는 쓰려다 말았다.

이번에는 신입(입사 후 6개월미만)을 기준으로 썼지만

다음에는 신입(입사 후 1년정도)를 기준으로 써보려한다.

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

There will be case that your custom list item doesn’t respond when you click…so what’s the reason and what’s the solution?

Here several problems and solutions:


1. Scenario: list item layout contains CheckBox

Problem: OnItemClickListener doesn’t respond.

Reason: CheckBox is also having its own click listener by default to change its state, and it overrides the container ListView.

Solution: remove focus on CheckBox by setting these attributes to “false”

1
2
android:focusable="false"
android:focusableInTouchMode="false"



2. Scenario: random

ProblemOnItemClickListener just doesn’t repond any at all!!!!

Reason: No idea..

Solution: in code, just set OnItemClickListener before setting Adapter. It works randomly @@!



3. Scenario: list item contains ImageButton

ProblemOnItemClickListener just doesn’t repond any at all!!!!

Reason: No idea!!!

Solution: in code, set ImageButton focus to “false”

1
2
ImageButton button = (ImageButton) convertView.findViewById(R.id.imageButton);
button.setFocusable(false);



4. Scenario: list item contain TextView

ProblemOnItemClickListener just doesn’t repond.

Reason: I think you have set this attribute to TextView: android:inputType=”textMultiLine”

Solution: just remove that attribute, using android:minLines/android:maxLines instead.



5. Scenario: list item contain a TextView that is linked to website URL or whatever “mailto:” things

ProblemOnItemClickListener just doesn’t repond.

Reason: the TextView overrides focus of list item.

Solution: just remove attribute “android:autoLink” on TextView.

 

Hope you solve your problems!

Cheers,

Pete Houston


출처 http://xjaphx.wordpress.com/2011/07/14/listview-doesnt-respond-to-onitemclicklistener/

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

■ 주석의 개념

    - 코드에 대한 개요와 코드 자체만 가지고 이용할 수 없는 추가적인 정보 제공

    - 프로그램을 읽는 것과 이해하는 것에 관계된 정보만을 포함하고 있어야 한다.

    - 중복된 주석은 피해야 한다.

    - 주석을 추가해야만 할 정도의 프로그램이라면 재작성을 고려해야 한다.

    - 특수문자(Form feed, backspace 등)를 포함하면 안된다.


■ 주석의 종류 

    - 문서주석 : '/**      */'에 의해 경계가 결정, javadoc 툴을 사용하여 HTML 파일로 축출

    - 구현주석 : '/*      */'과 '//'에 의해 경계가 결정, 개별적 구현에 대한 주석, 코드와는 상관없는 주석


■ 문서주석

    - 자바 클래스, 인터페이스, 생성자, 메서드, 필드 들을 성명

    - 주석 경계기호인 '/**  */' 안에 들어감

    - 클래스, 인터페이스, 맴버 당 하나씩 들어감

    - 선언 바로 전에 나와야 함.

    - 최 상위 레벨의 클래스와 인터페이스들은 열여쓰기를 하지 않고 멤버들(변수, 메서드)은 들여쓰기를 한다.

    - 클래스에 대한 문서주석의 첫 번째 줄은 들여쓰기를 하지 않고 그 다음에 나오는 문서주석은 별표를 수직으로 맞춘다(1개의 스페이스 포함)

    - 생성자를 포함한 멤버들은 문서주석 첫 줄에서 4개의 스페이스로 들여쓰기를 하고 그 이후는 5개의 스페이스 들여쓰기를 한다.

    - 문서주석에 적절하지 않은 클래스, 인터페이스, 변수, 메서드에 대한 정보를 제공하려면 선언 바로 후에 block 주석이나 single line 주석을 사용한다.(클래스의 구현에 대한 세부사항은 class 선언 다음에 block 주석을 사용)

    - Java는 문서주석을 주석 이후 처음 나오는 선언문과 연결시키므로 문서주석은 메서드, 생성자 정의 블록 내부에 위치하면 안된다.


○ 클래스 설명 주석(Document comments)

    - import 문 다음에 기술

    - 블록주석을 사용

    - 각 라인은 *로 시작

    - 해당 클래스에 대한 기능과 용도 기술

    - <pre>...</pre>내용은 수정하지 않음

    - Serialize 기능이 뭔지 모르겠음.(버전관리 프로그램 관련?)

 

/**

 * Serialize 기능을 사용하여 file에 object를 저장

 * <pre>

 * input : input.txt   - 입력데이터 파일

 * output : output.txt - 출력데이터 파일

 * Table : none 

 * </pre>

 *

 * <pre>

 * <b>History:</b>

 *    작성자, 1.0, 2007.3.9 초기작성

 * </pre>

 *

 * @author 최종 수정자

 * @version 1.0, 2007.5.5 메서드 추가

 * @see    None

 */



○ 맴버변수 설명 주석

    - 변수 상단에 위치

    - 블록주석을 사용

    - 용도, 제한사항 등을 기술

    ※ 맴버변수의 기술 순서 : constant - static - primitive - reference


○ 맴버함수 설명 주석

    - 함수의 상단에 위치

    - 블록주석을 사용

    - 메서드 기능설명은 한 두줄로 간결하게 기술

    - 메서드의 파라미터를 type명과 변수명을 적고 간략하게 설명

    - 리턴변수, 예외사항 설명

 

/**

 * 메서드의 기능설명은 한 두줄로 간결하게..

 *

 * @param int list1 메서드의 파라미터 설명, type명과 변수명을 적고 간략하게 설명

 * @return

 * @exception 예외사항한 라인에 하나씩

 */



○ 기타 주석처리

    - 코드 내부의 짧은 statement 뒤의 주석은 //로

    - 맴버변수 정의시 인자가 많으면 각 인자를 한행에 하나씩 기술, 같은 행에 주석 기재

    - 코드가 산만하지 않게 주석을 멀리 사용

    - /*.........*/는 테스트 목적으로 활용했던 부분을 남김

    - 주석의 시작은 항상 라인의 처음에서 시작하며 각 라인은 *로 시작

    - 블럭내 주석은 사용하지 않는다(특별한 경우 제외)

    - 의문점이나 해결못한 것은 임시주석으로 사용(/*-  ..............*/)



■ 구현주석 : block, single-line, trailing, end of line


○ block 주석

    - 파일, 메서드, 자료구조, 알고리즘의 설명 제공

    - 각각의 파일이 시작될 때와 메서드 전에 사용

    - 메서드 안에 존재하는 block 주석은 설명하는 코드와 같은 레벨로 들여쓰기

    - block 주석의 형식을 고치는 일이 일어나지 않는 특별한 block 주석은 /*- 으로 시작

    - 코드의 나머지로부터 분리하기 위해 처음 한줄은 비워둔다.

 

/*

 * 여기에 block comment 작성

 */

 

/*-

 * 형식을 고치지 않는 특별한 block 주석

 * 들여쓰기가 무시되는 특별한 주석

 * :

 * :

 */



○ single line 주석

    - 짧은 주석은 뒤에 따라오는 코드와 같은 레벨의 들여쓰기를 하는 한줄로 나타남

    - 한 줄로 써지지 않는다면 block 주석 형식을 따라야 함


 if(condition) {

/* single line 주석 */

:

}

    if(condition2){

    */ single line 주석 */

    ....

    }



○ trailing 주석

    - 매우 잛은 주석의 경우 코드와 같은 줄에 나타난다.

    - 코드와의 확실한 구별을 위해 충분히 멀리 떨어뜨림.


if(condition) {                              /* trailing 주석 */

return TRUE ;

}

else {

    return expressionReturn();               /* trailing 주석 */

}



○ end of line 주석

    - 한 줄 모두를 주석처리 하거나 한 줄의 일부분을 주석처리

    - 본문 주석을 위하여 여러 줄에 연속되어 사용하면 안됨

    - 코드섹션을 주석처리 하기 위하여 여러 줄을 연속하여 사용 가능


if(condition) {                          // end of line 주석

    expression1 ;

    expression2 ;

}

else {                                   // end of line 주석

    expression3 ;

    expression4 ;

}

 

// 블럭을 통째로 주석처리 할 경우

// if(condition2) {

//     expression5 ;

//     expression6 ;

// }

// else {

//     expression7 ;

//     expression8 ;

// }

 


■ javadoc로 HTML 문서 생성

    - 개발한 클래스의 모든 설명주석(/* ,.......*/)은 javadoc을 이용하여 HTML 문서 형태로 클래스의 API를 문서화 한다.

    - javadoc은 jdk를 이용한다.


javadoc verbos author version d <대상 디렉토리> <java 소스 파일명>



■ HTML / JavaScript 주석

    - 설명주석 : 블록주석(<!--  ......  // -->)을 사용하며 각 라인은 '*'로 시작한다.


<!

 

* 사용자 정보 조회

*

* history :

*           작성자, 1.0, 2006.3.9 초기 작성

* author : 최종수정자

* version : 1.1 2007.3.10 - javascript 함수 추가

* see : 관련된 모듈 기술

*

//-->



출처 : Tong - NetSET님의 틀이부#프로그래밍언어통


저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

전역을 피하는 자바스크립트 코딩 기법

객체 소유권과 밀접히 관련된 이론으로, 전역 변수나 함수 사용을 가능한 한 피해야 한다. 이는 스크립트가 실행되는 환경을 항상 일정하게, 관리하기 쉽게 만드는 일이다. 전역 변수는 단 하나만 생성하고 그 안에 다른 객체와 함수가 존재하도록 해야 한다. 전역 변수는 단 하나만 생성하고 그 안에 다른 객체와 함수가 존재하도록 해야 한다. 다음의 코드를 보자.


// 전역에 두 가지를 추가한다. 다음은 나쁜 코딩 사례이다.

var name = "Woonohyo";

function sayName() {

alert(name);

}


위 코드는 전역에 변수 name과 함수 sayName()을 추가한다. 하지만 위의 방법보다는 다음과 같이 이들을 모두 포함하는 객체를 만드는 편이 낫다.


// 전역에는 단 하나만 추가하자.

var MyApplication = {

name = "Woonohyo";

sayName: function() {

alert(this.name);

}

};


고쳐 쓴 코드에서는 전역 객체를 MyApplication 단 하나만 정의하며 name 변수와 sayName() 함수는 모두 그 안에 존재한다. 이렇게 하면 이전 코드의 문제 두 가지를 해결할 수 있다. 


1. 변수 name이 다른 기능과 관련 있을 수도 있는 window.name 프로퍼티를 덮어쓰지 않는다.

2. 기능을 어디서 호출하는지 혼란스럽지 않다. 

MyApplication.sayName()을 호출하는 코드만 보아도, 문제가 있을 때는 MyApplication을 정의한 코드를 살펴봐야 함을 알 수 있다.


이렇게 전역에 단 하나의 객체만을 추가하는 방법이 '네임스페이스'라는 개념이며 야후! 사용자 인터페이스(YUI) 라이브러리에 도입되어 유명해졌다. YUI 버전 2에서는 다음과 같이 여러 가지 네임스페이스를 통해 기능을 추가했다.


  • YAHOO.util.Dom - DOM을 조작하는 메서드이다.

  • YAHOO.util.Event - 이벤트를 다루는 메서드이다.

  •  YAHOO.lang - 저수준 언어 기능과 관련된 메서드이다.

YUI에서는 전역 객체 YAHOO가 컨테이너이며 이 안에 다른 객체가 정의된다. 이런 식으로 단순히 기능을 한데 묶기 위해 사용하는 객체를 '네임스페이스'라고 한다. YUI 라이브러리는 전체가 이 개념 위에서 만들어졌으므로 같은 페이지에서 다른 자바스크립트 라이브러리와 문제 없이 공존할 수 있다.

네임스페이스에 쓸 전역 객체 이름을 정할 때는 모든 사람이 동의하고 다른 라이브러리에서 쓰지 않을만큼 충분히 고유하게 정해야 한다. 대개는 YAHOO나 Wrox처럼 회사 이름을 쓰면 된다. 일단 네임스페이스를 만들면 다음과 같이 기능을 한데 묶는다.


// 전역 객체 생성

var Woonohyo = {};


// Professional Javascript의 네임스페이스 생성

Woonohyo.ProJS = {};


// 기존에 사용한 다른 객체 등록

Woonohyo.ProJS.EventUtil = { ... };

Woonohyo.ProJS.CookieUtil = { ... };


위 예제에서는 전역인 Woonohyo에 네임스페이스를 생성한다. 이 포스트에 있는 코드를 모두 Woonohyo.ProJS 네임스페이스에 두면 다른 저자들도 자신의 코드를 Woonohyo 객체에 추가할 수 있다. 모두가 이 패턴을 따른다면 다른 개발자가 EventUtil이나 CookieUtil이란 객체를 사용하더라도 다른 네임스페이스에 존재하므로 걱정할 필요가 사라진다.

다음 예제를 살펴보자.


// Professional Ajax의 네임스페이스 생성

Woonohyo.ProAjax = {};


// 기존에 사용한 다른 객체 등록

Woonohyo.ProAjax.EventUtil = { ... };

Woonohyo.ProAjax.CookieUtil = { ... };


// ProJS의 객체는 그대로 사용 가능

Woonohyo.ProJS.EventUtil.addHandler( ... );


// ProAjax도 별도로 존재

Woonohyo.ProAjax.EventUtil.addHandler( ... );


네임스페이스를 쓰면 코드가 좀 늘어나긴 하지만 관리하기 쉬워지므로 그만한 가치는 충분하다. 또한 페이지에 다른 개발자의 코드가 존재하더라도 서로 침범하지 않게 된다.






NameSpace 타입


E4X에서는 네임스페이스를 Namespace 객체로 표현한다. Namespace 객체는 일반적으로 네임스페이스 접두사를 네임스페이스 URI와 연결하는데 사용하지만 접두사가 항상 필요하진 않다. 다음과 같이 Namespace 생성자를 사용해서 Namespace 객체를 생성한다.


var ns = new Namespace();


다음과 같이 URI나 접두사와 URI를 넘겨 Namespace 객체를 초기화할 수 있다.


var ns = new Namespace("http://www.woonohyo.net/");    // 접두사 없는 네임스페이스

var woonohyo = new Namespace("woonohyo", "http://www.woonohyo.net/");    // woonohyo 네임스페이스


Namespace 객체의 정보는 다음과 같이 prefix와 uri 프로퍼티로 접근한다.


alert(ns.uri);             // "http://www.woonohyo.net/"

alert(ns.prefix);        // undefined

alert(wrox.uri);        // "http://www.woonohyo.net/"

alert(wrox.prefix);    // "woonohyo" 


Namespace 객체에 접두사를 할당하지 않으면 prefix 프로퍼티는 undefined이다. 기본 네임스페이스를 생성하려면 접두사에 빈 문자열을 지정해야 한다.

XML 리터럴에 네임스페이스가 들어있거나 네임스페이스 정보가 들어 있는 XML 문자열을 XML 생성자로 파싱하면 Namespace 객체가 자동으로 생성된다. Namespace 객체가 생성되면 namespace() 메서드에 접두사를 넘겨 Namespace 객체의 참조를 가져올 수 있다. 다음 예제를 보자.


var xml = <woonohyo:root xmlns:woonohyo="http://www.woonohyo.net/">

<woonohyo:message> Hello, Woonohyo! </woonohyo:message>

</woonohyo:root>;



var woonohyo = xml.namespace("woonohyo");

alert(woonohyo.uri);

alert(woonohyo.prefix);


위 예제에서는 네임스페이스 정보를 담은 XML 리터럴을 생성했다. uri와 prefix 프로퍼티를 사용할 수 있는 시점부터 woonohyo 네임스페이스의 Namespace 객체에 namespace("woonohyo")로 접근이 가능하다.










저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

Transaction Isolation Level이란 사용자에게 트랜잭션의 안정성을 보장해 주는 수준을 뜻한다.


4단계로 되어있으며, 각 단계 별로 안정성과 성능이 달라진다.



  • Read Uncommitted (가장 낮은 수준)
  • Read Committed
  • Repeatable Read
  • Serializable (가장 높은 수준)

실습용 테이블을 만들어서 살펴보자

CREATE TABLE TX_TEST(A INT, B CHAR(8), C TIMESTAMP);
언제 레코드가 바뀌는 지 정확히 알기 위해 TIMESTAMP 컬럼을 넣었다.

INSERT INTO TX_TEST (A, B) VALUES (1, 'A'), (2, 'B'), (3, 'C'), (4, 'D');
여러 레코드를 한 번에 넣을 수 있는 방법.

SELECT * FROM TX_TEST;





Isolation Level 변경하는 법
SET GLOBAL TRANSACTION ISOLATION LEVEL [LEVEL_NAME];


Isolation Level 확인하는 법

SELECT @@TX_ISOLATION;



GLOBAL 값을 변경하더라도, 세션의 Isolation Level이 변경되지 않을 수 있다.


Session에 대한 Level 변경하는 법

SET SESSION TRANSACTION ISOLATION LEVEL [LEVEL_NAME];




1. READ-UNCOMMITTED 인 경우


[세션 A에서]

START TRANSACTION;

UPDATE TX_TEST SET A = A + 1;


[세션 B에서]

SELECT * FROM TX_TEST;


세션 A에서 commit을 하지 않았음에도, transaction 중간 변경사항이 세션 B에서도 확인할 수 있게 되었다.

일반적인 데이터베이스의 transaction에서 이러한 일이 생겨서는 안된다.


만약 이 때 세션 B에서 UPDATE 문을 날리면 어떻게 될까?


UPDATE TX_TEST SET A = A + 5;

...


세션 A에서 TRANSACTION이 이루어지고 있기 때문에, 해당 TRANSACTION이 끝나기를 기다리게 된다.

(장시간 기다릴 경우 LOCK WAIT TIMEOUT EXCEEDED 오류가 난다)


[세션 A]

SELECT NOW(); ROLLBACK;


[세션 B]

SELECT * FROM TX_TEST;


현재 컬럼 C에 찍혀있는 TIMESTAMP 값은 해당 UPDATE 문을 날렸을 때의 TIMESTAMP이다.




2. READ-COMMITTED 인 경우


각 세션에 다음을 통해 Transaction Isolation Level을 read-committed로 변경하자.

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;


[세션 A]

START TRANSACTION;

UPDATE TX_TEST SET A = A * 10;


SELECT * FROM TX_TEST;


[세션 B]

START TRANSACTION;

SELECT * FROM TX_TEST;


세션 A에서 날린 UPDATE 문의 결과를 세션 B에서는 아직 확인할 수 없다.



[세션 A]

COMMIT;


[세션 B]

SELECT * FROM TX_TEST;


세션 A의 TRANSACTION이 끝난 이후 세션 B에서도 업데이트 된 레코드를 읽을 수 있게 되었다.

하지만, 세션 B의 TRANSACTION이 진행 중인데 레코드의 값이 변경이 되는 것은 문제가 될 수 있다.




3. REPEATABLE-READ


각 세션에 다음을 통해 Transaction Isolation Level을 REPEATABLE READ로 변경하자.

SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;


[세션 A, B]

START TRANSACTION;


[세션 A]

UPDATE TX_TEST SET B = CONCAT(B, 'A');

SELECT * FROM TX_TEST;



[세션 B]

SELECT * FROM TX_TEST;



심지어 세션 A에서 COMMIT을 하고 난 이후에도,

SELECT * FROM TX_TEST;

가 된다.


결국 세션 B에서 COMMIT; 을 하고 난 뒤에, 세션 A에서 UPDATE를 한 결과 레코드들을 확인할 수 있게 된다.


만약 세션 B에서 TRANSACTION 중 UPDATE 문을 사용하면 어떻게 될까?

당연히 세션 A에서 TRANSACTION-UPDATE가 이루어지고 있기 때문에 LOCK이 걸려서 응답을 기다리게 된다.


만약 세션 A에서 COMMIT;을 하게 되면 A의 UPDATE 문과 B의 UPDATE 문의 결과를 모두 반영한 레코드를 각 세션들이 확인할 수 있게 된다.



4. SERIALIZABLE


각 세션에 다음을 통해 Transaction Isolation Level을 SERIALIZABLE로 변경하자.

SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;


[세션 A, B]

START TRANSACTION;


[세션 B]

SELECT * FROM TX_TEST;    [정상 작동]

UPDATE TX_TEST SET A = A + 1;    [LOCK이 걸림]


[세션 A]

UPDATE TX_TEST SET A = A + 1;    [DEADLOCK FOUND ERROR 발생]

심지어 세션 B에서 TRANSACTION-UPDATE를 하고 있는 경우에는, SELECT조차 실행이 되지 않는다.







저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

모든 함수는 prototype 프로퍼티를 갖는다. 이 프로퍼티는 해당 참조 타입의 인스턴스가 가져야 할 프로퍼티와 메서드를 담고 있는 객체이다. 이 객체는 생성자를 호출할 때 생성되는 객체의 문자 그대로 '프로토타입(원형)'이다. 프로토타입의 프로퍼티와 메서드는 객체 인스턴스 전체에서 공유된다는 점이 프로토타입의 장점이다. 객체 정보를 생성자에 할당하는 대신 다음과 같이 직접적으로 프로토타입에 할당할 수 있다.


function Person() {

}


Person.prototype.name = "Woonohyo";

Person.prototype.age = 27;

Person.prototype.job = "Software Engineer";

Person.prototype.sayName = function() {

alert(this.name);

};


var person1 = new Person();

person1.sayName();    // "Woonohyo"


var person2 = new Person();

person2.sayName();    // "Woonohyo"


alert(person1.sayName == person2.sayName);    // true


여기에서 프로퍼티들과 sayName() 메서드는 Person의 prototype 프로퍼티에 직접 추가되었고 생성자 함수는 비워 두었다. 비록 생성자 함수는 비어있지만, 생성자를 호출헤 만든 객체에도 프로퍼티와 메서드는 존재한다. 생성자 패턴과는 달리 프로퍼티와 메서드를 모든 인스턴스에서 공유하므로 person1과 person2는 같은 프로퍼티 집합에 접근하며 같은 sayName() 함수를 공유한다. 세부 동작에 대한 이해를 위해서는 ECMAScript의 프로토타입에 대해 알아야 한다.



- 프로토타입은 어떻게 동작하는가

함수가 생성될 때마다 prototype 프로퍼티 역시 특정 규칙에 따라 생성된다. 기본적으로 모든 프로토타입은 자동으로 contructor 프로퍼티를 갖는데 이 프로퍼티는 해당 프로토타입이 프로퍼티로서 소속된 함수를 가리킨다. 예를 들어 위의 코드에서 Person.prototype.constructor는 Person을 가리킨다. 다음에는 생성자에 따라 각종 프로퍼티와 메서드가 프로토타입에 추가된다.

커스텀 생성자를 정의하면해당 프로토타입은 단지 constructor 프로퍼티만 가지며 다른 메서드는 Object에서 상속한다. 생성자를 호출해서 인스턴스를 생성할 때마다 해당 인스턴스 내부에는 생성자의 프로토타입을 가리키는 포인터가 생성된다. ECMA-262 5판에서는 이 포인터를 [[Prototype]]이라고 부른다. 스크립트에서 [[Prototype]]에 접근하는 표준은 없지만 파이어폭스, 사파리, 크롬은 모두 __proto__ 라는 프로퍼티를 지원한다. 인스턴스와 직접 연결되는 것은 생성자의 프로토타입이지 생성자 자체가 아님을 이해해야 한다.


프로토타입은 contructor 프로퍼티를 갖고 기타 추가된 프로퍼티들도 가지게 된다. Person의 인스턴스인 person1과 person2는 Person.prototype을 가리키는 내부 프로퍼티를 가질 뿐 생성자와 직접 연결되지는 않는다. 이 인스턴스들에는 아무 프로퍼티나 메서드도 없는데 person1.sayName()이 동작하는 것도 객체 프로퍼티를 검색하는 메커니즘 때문이다. 

[[prototype]]은 구현 환경에 따라 접근 불가능할 수도 있지만 객체 사이에 프로토타입 연결이 존재하는지는 isPrototypeOf() 메서드를 통해 알 수 있다. 요약하면, isPrototypeOf()는 다음과 같이 [[Prototype]]이 자신을 호출하는 프로토타입을 가리킬 때 true를 반환한다.


alert(Person.prototype.isPrototypeOf(person1));    // true

alert(Person.prototype.isPrototypeOf(person2));    // true


이 코드에서 프로토타입의 isPrototypeOf() 메서드를 person1과 person2 모두에 대해 호출했다. 두 인스턴스는 모두 Person.prototype에 연결되므로 isPrototypeOf() 메서드는 true를 반환한다.

ECMAScript 5판에는 [[Prototype]]의 값을 반환하는 Object.getPrototypeOf() 라는 메서드가 추가 되었다. 다음의 코드를 보자.


alert(Object.getPrototypeOf(person1) == Person.prototype);    // true

alert(Object.getPrototypeOf(Person1).name);    // "Woonohyo"


첫번째 줄은 단순히 Object.getPrototypeOf()에서 반환 된 객체가 해당 객체의 프로토타입이 맞는지만 확인한다.

두번째 줄은 프로토타입의 name 프로퍼티 값인 "Woonohyo"를 가져온다.

이 메서드를 통해 프로토타입을 이용한 상속 구현을 할 수 있다.

(메서드 지원 브라우저: IE9+, Firefox 3.5+, Safari 5+, Opera 12+, Chrome)


객체에서 프로퍼티를 읽으려 할 때마다 해당 프로퍼티 이름으로 찾으려는 검색은 객체 인스턴스 자체에서 시작한다. 인스턴스에서 프로퍼티 이름을 찾으면 그 값을 반환하고, 그렇지 않으면 포인터를 프로토타입으로 올려서 검색을 계속한다. 프로퍼티를 프로토타입에서 찾으면 그 값을 반환한다. 따라서 person1.sayName()을 호출하면 두 단계가 발생한다. 첫 단계에서 자바스크립트 엔진은 person1 인스턴스에 sayName이라는 프로퍼티가 있는지 확인한다. 찾을 수 없기 때문에 person1의 프로토타입에서 sayName이 있는지 확인하고, 찾았으므로 프로토타입에 저장된 함수가 실행된다. person2.sayName()을 호출하면 똑같은 방식으로 검색하여 실행하고 같은 결과를 반환한다. 프로토타입은 이런 식으로 여러 객체 인스턴스 사이에서 프로퍼티와 메서드를 공유한다.


객체 인스턴스에서 프로토타입에 있는 값을 읽을 수는 있지만, 수정은 불가능하다. 프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면 해당 프로퍼티는 인스턴스에 추가되며 프로토타입까지 올라가지 않는다.


function Person() {

}


Person.prototype.name = "Woonohyo";

Person.prototype.age = 27;

Person.prototype.job = "Software Engineer";

Person.prototype.sayName = function() {

alert(this.name);

};


var person1 = new Person();

var person2 = new Person();


person1.name = "Wonbin";

alert(person1.name);    // "Wonbin" - 인스턴스에서

alert(person2.name);    // "Woonohyo" - 프로토타입에서


위 예제에서 person1의 name 프로퍼티에 새 값이 반영되었다. person1의 경우 person1.name에 접근하면 인스턴스에서 name 프로퍼티를 반환하고, person2의 경우 person2.name에 접근하면 인스턴스에서 찾지 못하므로 프로토타입을 검색해 name 프로퍼티를 찾는다.

즉, 객체 인스턴스에 프로퍼티를 추가하면 해당 프로퍼티는 프로토타입에 존재하는 프로퍼티를 '가리게' 된다. (프로토타입에 존재하는 동명의 프로퍼티에 대한 접근 차단)

심지어 프로퍼티를 null로 설정해도 인스턴스의 프로퍼티만 변경할 뿐 프로토타입 프로퍼티에 다시 연결되지 않는다. 다시 프로토타입 프로퍼티에 접근하기 위해서는 delete 연산자를 사용해야 한다.


function Person() {

}


Person.prototype.name = "Woonohyo";

Person.prototype.age = 27;

Person.prototype.job = "Software Engineer";

Person.prototype.sayName = function() {

alert(this.name);

};


var person1 = new Person();

var person2 = new Person();


person1.name = "Wonbin";

alert(person1.name);    // "Wonbin" - 인스턴스에서

alert(person2.name);    // "Woonohyo" - 프로토타입에서


delete person1.name;

alert(person1.name);    // "Woonohyo" - 프로토타입에서


hasOwnProperty("propertyName") - 프로퍼티가 인스턴스에 존재하는지 프로토타입에 존재하는지 확인할 수 있는 메서드. (true = 인스턴스, false = 프로토타입)

Object로부터 상속되는 메서드로, 다음과 같이 해당 프로퍼티가 객체 인스턴스에 존재할 때만 true를 반환한다.


function Person() {

}


Person.prototype.name = "Woonohyo";

Person.prototype.age = 27;

Person.prototype.job = "Software Engineer";

Person.prototype.sayName = function() {

alert(this.name);

};


var person1 = new Person();

var person2 = new Person();


alert(person1.hasOwnProperty("name"));    // false


person1.name = "Wonbin";

alert(person1.name);    // "Wonbin" - 인스턴스에서

alert(person1.hasOwnProperty("name"));    // true


alert(person2.name);    // "Woonohyo" - 프로퍼티에서

alert(person2.hasOwnProperty("name"));    // false


delete person1.name;

alert(person1.name);    // "Woonohyo" - 프로퍼티에서

alert(person1.hasOwnProperty("name"));    // false















저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

클로저 내부의 this 객체는 꽤 복잡하게 동작한다. this 객체는 런타임에서 함수가 실행 중인 컨텍스트에 묶인다. 즉 전역 함수에서 this는 스트릭트 모드가 아닐 때는 window, 스트릭트 모드에서는 undefined이며 함수가 객체 메서드로 호출되었을 때 this는 해당 객체이다. 하지만 클로저를 작성하는 방식으로 인해 이를 분명히 알기는 어렵다. 다음 코드를 보자.


var name = "The Window";


var object = {

name: "My Object",

getNameFunc: function() {

return function() {

return this.name;

};

}

};


alert(object.getNameFunc()());    // "The Window" (스트릭트 모드가 아닌 경우)


여기에서 name이라는 전역 변수와 객체를 함께 생성했는데 객체에도 name 프로퍼티가 존재한다. 객체의 getNameFunc() 메서드는 익명 함수를 반환하며 익명 함수는 this.name을 반환한다. getNameFunc()는 함수를 반환하므로 object.getNameFunc()()을 호출하면 getNameFunc()가 반환하는 함수를 즉시 호출하는 것이나 마찬가지이며 문자열을 얻는다. 반환 받은 문자열은 전역 name 변수의 값인 "The Window"이다. 익명 함수가 외부 스코프의 this 객체를 포함하지 않았던 이유는 무엇일까?


모든 함수는 호출되는 순간 자동으로 this와 arguments 두 특별한 변수를 갖게 됨을 상기하자. 내부 함수는 결코 외부 함수의 this와 arguments에 직접적으로 접근할 수 없다. 다음과 같이 외부 함수의 this 객체를 다른 변수에 저장해서 클로저가 이 변수에 접근하도록 하는 일은 가능하다.


var name = "The Window";


var object = {

name : "My Object",

getNameFunc : function() {

var that = this;

return function() {

 return that.name;

};

}

};


alert(object.getNameFunc()());    // "My Object"


굵게 처리한 두 줄로 인해 다른 결과가 나왔다. 익명 함수를 정의하기 전에 외부 함수의 this 객체를 that이란 변수에 할당했다. 이제 클로저를 정의하면 that은 외부 함수에 고유한 변수이므로 클로저는 이 변수에 접근이 가능하다. 함수가 반환한 뒤에도 that은 여전히 object에 묶여 있으므로 object.getNameFunc()()을 호출하면 "My Object"를 반환한다.



this의 값이 예상과 다른 특별한 경우가 몇 가지 있다. 이전 예제를 조금 수정한 다음 코드를 보자.


var name = "The Window";


var object = {

name : "My Object",

getName : function() {

return this.name;

}

};


getName() 메서드는 단순히 this.name의 값을 반환한다. object.getName()을 호출하는 다양한 방법과 그 결과를 보자.


object.getName();    // "My Object"

(object.getName)();    // "My Object"

(object.getName = object.getName)();    // "The Window" (단, 스트릭트 모드가 아닌 경우)


첫 번째 줄은 일반적인 방법으로 object.getName()을 호출했는데 this.name과 object.name은 같으므로 "My Object"를 반환했다. 

두 번째 줄은 object.getName을 호출하기 전에 괄호로 감쌌다. 함수를 참조한 것처럼 보이겠지만 object.getName과 (object.getName)은 같은 것으로 정의되어 있으므로 this 값은 그대로 유지된다. 

세 번째 줄에서는 먼저 할당한 후 그 결과를 호출했다. 할당 표현식의 값은 함수 자체이므로 this의 값이 유지되지 않기 때문에 "The Window"를 반환하게 된다. 

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효