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 우너효

자바스크립트에서 '익명 함수'와 '클로저'는 자주 잘못 혼용되곤 한다. '클로저'란 다른 함수의 스코프에 있는 변수에 접근 가능함 함수를 뜻한다. 다음의 코드를 보자.


function createComparisonFunction(propertyName) {

return function(object1, object2) {

var value1 = object1[propertyName];

var value2 = object2[propertyName];


if (value1 < value2) {

return -1;

} else if (value1 > value2) {

return 1;

} else {

return 0;

}

};

}


위 코드에서 Bold 처리 된 부분은 내부 함수(익명 함수)이면서 외부 함수의 변수(propertyName)에 접근한다. 내부 함수가 반환되어 다른 컨텍스트에서 실행되는 동안에도 propertyName에 접근할 수 있다. 이런 일이 가능한 것은 내부 함수의 스코프 체인에 createComparisonFunction()의 스코프가 포함되기 때문이다. 


좀 더 쉽게 이해하기 위해 함수를 처음 호출할 때 무슨 일이 일어나는 지 생각해보자.


함수를 호출하면 실행 컨텍스트와 스코프 체인이 생성된다. 함수의 활성화 객체는 arguments 및 이름 붙은 매개변수로 초기화된다. 외부 함수의 활성화 객체는 스코프 체인의 두 번째 객체이다. 이 과정이 포함 관계에 있는 함수에서 계속 발생하여 스코프 체인이 전역 실행 컨텍스트에서 종료될 때까지 이어진다.


함수를 실행하면 값을 읽거나 쓸 변수를 스코프 체인에서 검색한다. 다음 코드를 보자.


function compare(value1, value2) {

if (value1 < value2) {

return -1;

} else if (value1 > value2) {

return 1;

} else {

return 0;

}

}


var result = compare(5, 10);


위 코드는 전역 실행 컨텍스트에서 호출하는 compare()라는 함수를 만든다. compare()를 처음으로 호출하면 arguments, value1, value2를 포함한 활성화 객체가 만들어진다. 전역 실행 컨텍스트의 변수 객체는 this와 result, compare를 포함하는 compare() 실행 컨텍스트의 스코프 체인의 다음에 위치한다. 


실행 컨텍스트마다 변수를 나타내는 객체가 존재한다. 전역 컨텍스트의 변수 객체는 항상 존재하지만, compare()와 같은 로컬 컨텍스트 변수 객체는 함수를 실행하는 동안에만 존재한다. compare() 함수를 정의하면 스코프 체인이 생성되고 자바스크립트 인터프리터는 이를 전역 변수 객체와 함께 미리 읽어 함수 내부의 [[Scope]] 프로퍼티에 저장한다. 함수를 호출하면 실행 컨텍스트가 생성되며 함수의 [[Scope]] 프로퍼티에 들어 있는 객체를 복사하여 스코프 체인이 생성된다. 다음에는 변수 객체로 동작하기도 하는 활성화 객체가 생성되어 컨텍스트의 스코프 체인 맨 앞에 위치한다. 


위 예제에서 compare() 함수의 실행 컨텍스트가 스코프 체인 내에 변수 객체를 두 개, 즉 로컬 활성화 객체와 전역 변수 객체를 갖는다. 스코프 체인이란 변수 객체를 가리키는 포인터 목록이며 객체를 직접 포함하는 것은 아니다.


함수에서 변수에 접근할 때마다 스코프 체인에서 해당 이름의 변수를 검색한다. 함수 실행이 끝나면 로컬 활성화 객체는 파괴되고 메모리에는 전역 스코프만 남는다. 하지만, 클로저는 이와 다르게 동작한다.

다른 함수의 내부에 존재하는 함수는 외부 함수의 활성화 객체를 자신의 스코프 체인에 추가한다. 따라서 createComparisonFunction()(회부 함수) 내부에 있는 익명 함수의 스코프 체인에는 외부 함수의 활성화 객체를 가리키는 포인터가 존재하게 된다. 


외부 함수가 실행을 마치고 익명 함수를 반환하면 익명 함수의 스코프 체인은 외부 함수의 활성화 객체와 전역 변수 객체를 포함하도록 초기화된다. 이 때문에 익명 함수는 외부 함수의 변수 전체에 접근할 수 있게 된다. 한 가지 흥미로운 점은 외부 함수가 실행을 마쳤는데도 활성화 객체가 파괴되지 않는 점인데 아직 익명 함수의 스코프 체인에서 이를 참조하기 때문이다. 외부 함수가 실행을 마치면 실행 컨텍스트의 스코프 체인은 파괴되지만 활성화 객체는 익명 함수가 파괴될 때까지 메모리에 남는다.




















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

프로시저

SQL의 기본 명령은 선언적 명령이다. (명령 후 결과)

즉, 데이터베이스에서 절차적 명령을 수행하기 위해서는 스토어드 프로그램을 이용해야 한다.


스토어드 프로그램의 종류

  • 스토어드 함수
    의미 그대로 함수. 날짜, 현재 사용자, 시간 등.
    SELECT 쿼리 문 안에 사용 가능.

  • 스토어드 프로시져
    더 다양한 기능을 제공.
    단, 쿼리 안에서 사용 불가능. 쿼리 외부에서 호출해야 함.

  • 트리거
    기존 프로그래밍 언어의 ‘이벤트 핸들러’와 유사.
    어떤 테이블에 레코드가 추가됐을 때 특정 작업을 수행하는 일 따위를 할 수 있음.

  • 이벤트 핸들러
    트리거와 유사하지만 다소 다름.


스토어드 프로시저의 장점

응용 프로그램의 성능 향상

네트워크 트래픽 감소
여러 개의 쿼리로 처리해야 할 작업을, 단일 쿼리로 처리할 수 있게 되기 때문이다.

보안성 향상
SQL Injection 원천 봉쇄

개발 업무의 구분


스토어드 프로시저의 단점

유지 보수가 어려워진다.
모든 코드가 프로그램 안에 들어있지 않기 때문.

GIT에서 관리가 어렵다.

롤백이 어렵다.

명령 자체의 성능이 감소한다.
특히 mysql에서 성능이 좋지 않다.


— 웹 분야에서 스토어드 프로시져의 사용은 점차 증가하고 있다.


스토어드 프로시져로 Hello World 작성하기

DELIMETER $$ // 구분자를 $$로 변경. ;으로 인한 종결 방지.

CREATE PROCEDURE SP_HELLO()

BEGIN

DECLARE STR CHAR(20) DEFAULT ‘POPI’;

SET STR = ‘HELLO, WORLD’;

SELECT STR;

END $$

DELIMETER ;


CALL SP_HELLO();


기본 변수 사용하기

DECLARE 자료형 [DEFAULT 기본값]

— 기본 변수는 프로시져 내에서만 유효함.


세션 변수

@로 시작하는 변수를 만들면, 세션 변수로 기존 프로그래밍 언어의 전역변수와 비슷한 역할을 하게 된다.

SET @name = ‘woonohyo’;

SELECT NAME INTO @name from user_list limit 1; // @name의 값이 바뀌게 된다.


기본 변수에 값 넣기

DELIMETER $$

CREATE PROCEDURE SP_TEST1()

BEGIN

DECLARE A INT;

SET A = 10;

SET A = A * 2;

SELECT A;

END $$

DELIMITER ;


CALL SP_TEST1();



SELECT INTO 사용하기

쿼리의 결과(스칼라 값)를 변수에 넣을 수 있다.

CREATE PROCEDURE SP_TEST2()

BEGIN

DECLARE A INT;

SELECT COUNT(UID) INTO A FROM USER_INFO;

SELECT A;

END $$

DELIMITER ;


결과값을 테이블에 넣기

CREATE TABLE TEST3(NUM INT);

INSERT INTO TEST3 VALUES(1);

CREATE PROCEDURE SP_TEST3()

BEGIN    

DECLARE A INT DEFAULT 1;

SELECT MAX(NUM) INTO A FROM TEST3;

SET A = A + 1;

INSERT INTO TEST3 VALUES (A);

SELECT * FROM TEST3;

END $$

DELIMITER ;

실행 할 때마다 TEST3의 값이 1씩 증가한다.


매개변수 사용하기

IN parameter: 입력에 사용

OUT parameter: 출력에 사용

 INOUT parameter: 입출력에 사용

CREATE TABLE TEST4 ( 

ID INT PRIMARY KEY AUTO_INCREMENT, 

NAME VARCHAR(20)

);


INSERT INTO TEST4 VALUES (NULL, ‘SHINJI’) (NULL, ‘ASUKA’) (NULL, ‘REI’) (NULL, ‘KAORU');

DELIMTER $$

CREATE PROCEDURE SP_TEST4(IN pname varchar(10))

BEGIN

DECLARE A INT DEFAULT 1;

SELECT * FROM TEST4 WHERE NAME = pname;

END $$

DELIMITER;


CALL SP_TEST4(‘



IF문 사용하기

IF <condition> THEN <statement>

[ELSE IF <condition> THEN <statement>]

[ELSE <statement>]

END IF


WHILE 문 사용하기

WHILE <condition> DO

<statement>

END WHILE



프로시저의 파라미터 중에는 INOUT이 있다. 이는 입/출력 전용임을 뜻한다. 



스토어드 프로시져 실습하기

DELIMITER $$

CREATE PROCEDURE SP_TEST1(IN num INT, INOUT ret INT)

BEGIN

DECLARE n INT;

// 거래 건수가 num 이상인 USER와

SELECT * FROM USER WHERE TRADE_NUM >= num;

// 거래 건수가 num 이상인 MARKET을 선택.

SELECT * FROM MARKET WHERE TRADE_NUM >= num;

SELECT COUNT(*) INTO n FROM USER WHERE TRADE_NUM > num;

SET ret = ret + n;

END $$

DELIMITER ;


SET @n = 10;

CALL SP_TEST1(2, @n); // SP_TEST1(2, 10) 으로 넣으면 INOUT에 상수를 넣었다는 에러 발생.

SELECT @n;



Statement의 생성은 다음과 같이 이루어진다.

CallableStatement cs = c.prepareCall(‘{CALL SP_TEST1(?,?)}’);


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

02 트랜잭션 수준 읽기 일관성



(1) 트랜잭션 수준 읽기 일관성이란?


문장수준 읽기 일관성(Statement-Level Read Consistency)은 쿼리가 시작된 시점을 기준으로 데이터를 일관성 있게 읽어 들이는 것

트랜잭션 수준 읽기 일관성(Transaction-Level Read Consistency)은 트랜잭션이 시작된 시점을 기준으로 일관성 있게 데이터를 읽어 들이는 것

오라클은 완벽한 문장수준의 읽기 일관성을 보장하나 트랜잭션에 대해서는 기본적으로 보장하지 않는다. 



(2) 트랜잭션 고립화 수준


 트랜잭션 수준으로 읽기 일관성을 강화 하려면 트랜잭션 고립화 수준을 높여 주어야 한다. 

트랜잭션 고립화 수준을 조절하는 방법은 네가지 수준이 있다.

ANSI / ISO SQL standard(SQL92)에서 정의함


■ 레벨 0 ( = Read Uncommitted )

 - 트랜잭션에서 처리중인 / 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용

 - Dirty Read, Non-repeatable Read, Phantom Read 현상 발생

 - 오라클은 이 레벨을 지원하지 않음


■ 레벨 1 ( = Read Committed )

 - Dirty Read 방지 : 트랜잭션이 커밋되어 확정된 데이터만 읽는 것을 허용

 - 대부분의 DBMS가 기본모드로 채택하고 있는 일관성 모드

 - Non-Repeatable Read, Phantom Read 현상 발생

 - DB2, SQL Server, Sybase의 경우 읽기 공유 Lock을 이용해서 구현, 하나의 레코드를 읽을 때 Lock을 설정하고 해당 레코드에서 빠지는 순간 Lock해제

 - Oracle은 Lock을 사용하지 않고 쿼리시작 시점의 Undo 데이터를 제공하는 방식으로 구현


■ 레벨 2 ( = Repeatable Read )

 - 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제하는 것을 불허함으로써 같은 데이터를 두번 쿼리했을 때 일관성 있는 결과를 리턴

 - Phantom Read 현상 발생

 - DB2, SQL Server의 경우 트랜잭션 고립화 수준을 Repeatable Read로 변경하면 읽은 데이터에 걸린 공유 Lock을 커밋할 때까지 유지하는 방식으로 구현

 - Oracle은 이 레벨을 명시적으로 지원하지 않지만 for update절을 이용해 구현 가능,

   SQL Server등에서도 for update 절을 사용할 수 있지만 커서를 명시적으로 선언할 때만 사용 가능함


■ 레벨 3 ( = Serializable Read )

 - 선행 트랜잭션이 읽은 데이터를 후행 트랜잭션이 갱신하거나 삭제하지 못할 뿐만 아니라 중간에 새로운 레코드를 삽입하는 것도 막아줌

 - 완벽한 읽기 일관성 모드를 제공

  

 트랜잭션 고립화 수준 조정기능을 위한 script

set tracsaction isolation level serializable;



낮은 단계의 트랜잭션 고립화 수준을 이용시 발생하는 현상 3가지

  • Dirty Read ( = Uncommitted Dependency )
  • Non-Repeatable Read ( = Inconsistent Analysis )
  • Phantom Read 


(3) Dirty Read ( = Uncommitted Dependency)


커밋되지 않은 수정 중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할때 발생

대부분 DBMS가 기본 트랜잭션 고립화 수준을 레벨1 로 설정하고 있어 Dirty Read는 발생하지 않음

 =  커밋된 데이터만 읽을 수 있도록 허용

SQL Server, Sybase등은 데이터를 읽을 때 공유 Lock을 사용,

갱신중인 레코드에는 배타적 Lock이 걸림, 이는 공유 Lock과는 호환되지 않아 갱신중인 레코드는 읽지 못함(Lock에 의한 동시성 저하 발생)

오라클은 다중 버전 읽기 일관성 모델을 채택함으로써 Lock을 사용하지 않고도 Dirty Read를 피해 일관성 있는 데이터 읽기가 가능 

 

(4) Non-Repeatable Read ( = Inconsistent Analysis)


 한 트랜잭션 내에서 같은 쿼리를 두번 수행 할 때 그 사이에 다른 트랜잭션이 값을 수정 또는 삭제함으로써

두 쿼리의 결과가 상이하게 나타나는 비일관성이 발생하는 것을 말함 


(5) Phantom Read


한 트랜잭션 안에서 일정 범위의 레코드를 두번 이상 읽을 때, 첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상

이는 트랜잭션 도중 새로운 레코드가 삽입되는 것을 허용하기 때문에 나타나는 현상임.

Phantom Read현상을 방지하려면 트랜잭션 고립화 수준을 레벨3으로 올려 주어야 한다. 

고립화 수준을 높이면 데이터 일관성은 확보 되지만 동시성이 현격히 저하되는 결과를 초래함

오라클은 해당 쿼리의 SCN 확인 과정을 통해 질의 시점에 존재했던 데이터만을 대상으로 집계 수행을 하므로 동시성을 저하시키지 않으면서 일관성을 유지 

트랜잭션 고립화 수준을 높이면 일관성은 향상 되지만 더 넓은 범위의 Lock을 더 오랫동안 유지하는 방식으로 동시성을 저하한다.(그림2-2참조)

그러나 오라클은 트랜잭션 고립화 수준을 높이더라도 Lock을 사용하지 않으므로 동시성이 저하되지는 않는다.


 

참조


 

위 사용된 Image는 마소7월호에서 발췌하였습니다. 

문서정보


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

목표

  • this 키워드가 어떻게 동작하는지 안다.
  • scope를 이해한다.
  • closure를 이해한다.

- What is scope?
scope는 변수의 유효 범위를 뜻한다. 

코드로 이해해보자.
---------------------------------
function myNum() {
var i = 0;
for ( var i = 0; i < 10; i++) {
}
console.log(i);
}
---------------------------------
위 함수에서 i는 0이 될까 10이 될까? 

정답은 10이다. 이유는 자바스크립트의 scope는 블록(block)이 아닌 함수(function)이기 때문이다.



다른 코드를 보자.


---------------------------------

i = 0;

function myNum() {

// var의 유무에 따라 결과는 다르게 나온다!

var i = 0;

for ( var i = 0; i < 10; i++) {

}

}

myNum();

console.log(i);

---------------------------------


i는 0이 나온다. 왜냐하면 전역변수 구간의 i와 myNum() 함수 내의 i는 서로 다르기 때문이다.

만약 var 없이 코딩을 하게 되면, 전역변수에 있는 i를 가져와서 수정이 이루어지기 때문에 값은 10이 나오게 된다.



그렇다면 var는 어떻게 쓰는 게 좋을까?


1. 중첩된 함수

---------------------------------

function mySNS() {

var name = "LINE";

return function() {

return name;

};

}

---------------------------------


---------------------------------

function mySNS() {

var name = "LINE";

return function() {

return function (prefix) {

return prefix + name;

}

};

}

mySNS()()("my sns is ");

---------------------------------


가장 안 쪽에 있는 함수는, 부모 함수들 중 name이라는 변수가 있는지 계속 찾게 된다.


---------------------------------

function mySNS() {

var name = "LINE";

function inner() {

var x = "inner";

}

inner();

console.log(x);

}

mySNS();

---------------------------------


결과값은 어떻게 될까? ---------------> x is not defined 라는 결과가 뜨게 된다.

왜냐하면 변수 x의 스코프는 inner() 함수 안 쪽에 불과하기 때문이다.



- 즉시실행함수

또 다른 스코프를 만드는 것. 


기본적인 형태는 다음과 같다.


(function() {


})();


---------------------------------

function mySNS() {

 var name = "LINE";

(function() {

var name2 = "KAKAO';

})();

console.log(name + " & " + name2);

}


mySNS();

---------------------------------

결과는 name2 is not defined가 된다. 왜냐하면, name2에 var를 사용하는 바람에 해당 변수의 스코프가 즉시실행함수 내부로 한정되기 때문이다.


만약 바깥에서도 name2 변수를 사용하고 싶으면 즉시실행함수 내부 변수에 var 키워드를 제거해주면 된다.


이외에도 즉시실햄함수는 주로 전역변수를 없애는 목적으로 자주 쓰인다.




- this

this란 context를 가리키는 변수이다. context는 해당 함수가 실행이 되는 공간이라고 생각하면 편하다.


함수 호출 관점에서 this를 이해해보자.

함수를 호출하는 순간에는 무조건 this가 생겨난다. 즉, 모든 함수는 그 함수가 실행되는 context가 항상 존재하게 된다는 의미이다.

기본적으로 함수의 context는 window이다.


---------------------------------

function mySNS() {

this.name = "LINE";

debugger;

return this.name;

}

---------------------------------

위의 함수를 호출했을 때, scope variable을 확인해보면

this: window 임을 알 수 있다.



method에서 this는 어떻게 될까?

---------------------------------

var mySNS = {

name : "LINE";

getName : function() {

debugger;

return this.name;

}

}

---------------------------------

mySNS.getName()을 했을 때, scope variable을 확인해보면

this:object 임을 알 수 있다.



constructor의 this

---------------------------------

function mySNS() {

this.name = "LINE";

this.getName = function() {

return this.name;

}

}

mySNS();

---------------------------------

name3; --> "LINE"

window.name3; --> "LINE"


즉, 변수가 window의 전역공간에 꽂히게 된다.


만약

new mySNS();

를 호출할 땐 어떻게 될까?


mySNS {name3: "LINE", getName3: function}

바로 객체가 하나 생성된다. 


즉, new 키워드를 통해 함수를 호출하면, 해당 함수 내의 this에 묶여있는 모든 속성을 다 담아서 반환하게 된다.

(this가 리턴된다고 생각하면 편하다)



call & apply의 this


-- 과제 --

1. call 함수를 공부하고 간단한 예제를 만들어보자.

2. call 함수에서의 this가 어떤 것을 가리키는지 예제코드에 주석으로 설명을 추가하자.

3. apply와 call의 차이점을 주석으로 설명하라.


-- 과제2 --

web화면에 '선식', '토마토', '마늘' 등을 만들고 해당 버튼을 누르면 console 화면을 통해 관련된 문구를 출력하도록 만들어라.

var obj = {

strTexts : " 은 정말 몸에 좋아요 ^^ ",

registerEvents : function() {

// do something

// strTexts는 this.strTexts로만 접근할 것.

}

};

obj.registerEvents();



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