728x90

 

 

java를 공부하다보면 중요한 개념으로 this 라는 키워드를 만나게 된다.

java에서는 보통 다음과 같은 경우에 만나볼 수 있다.

 

public class Test {
    private String name;
    private int age;
    public Test() {}
    public Test(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public static void main(String[] ar) {
    
    }
}

 

this가 사용된 부분은 6, 7 라인이다.

여기서 this는 this 키워드가 작성된 클래스 자기 자신을 뜻한다.

그래서 5라인에서의 name, age와 구분하기 위해 자기 자신임을 뜻하는 this를 사용하고 있는 부분이다.

 

그 증거로 다음과 같은 소스로 확인해볼 수 있다.

 

public class Test {
    private String name;
    private int age;
    public Test() {}
    public Test(String name) {
        this.name = name;
    }
    public Test(int age) {
        age = age;
    }
    public void disp() {
        System.out.println("name : " + name + ", age : " + age);
    }
    
    public static void main(String[] ar) {
        // this 키워드를 사용한 경우
        Test t1 = new Test("xxxelppa");
        t1.disp();
        
        // this 키워드를 사용하지 않은 경우
        Test t2 = new Test(21);
        t2.disp();
    }
}

 

[실행결과]

name : xxxelppa, age : 0
name : null, age : 0

 

 

17라인의 t1 객체에서 사용한 5라인의 생성자를 보면, this 키워드를 사용하여

자기 자신의 변수와 매개변수로 넘어온 변수를 구분해서 사용하고 있기 때문에 실행결과의 첫번째 라인과 같이 정상적으로 name이 할당됨을 볼 수 있다.

 

반면, 21라인에서 t2를 생성할 때 사용한 생성자는 8라인에 정의되어 있는데

내용부를 보면 age를 age에 담고 있다.

물론, 매개변수와 클래스의 변수명이 다르면 지금과 같은 상황은 생기지 않지만, 변수명이 동일할 경우 구분할 수 없기 때문에

9라인에서 사용된 this가 없는 age는 모두 자신과 가장 가까운 곳에 있는 매개변수 age를 바라보게 된다.

그래서 9라인의 뜻은, 매개변수로 받은 age에 매개변수 age를 담아라.

즉, 21 = 21 의 연산을 하고 있는 것이다.

 

그렇기 때문에 22라인의 t2.disp()의 결과의 age값이 0으로 할당되지 않음을 볼 수 있다.

 

 

 

 

 

이번 게시글의 목적은 java에서의 this가 아니므로 여기서 정리를 하고

본격적으로 javascript에서의 this에 대해 알게된 내용을 기계적으로 정리하려 한다.

 

결론부터 얘기하면, javascript의 this는 호출 방법에 따라 달라진다.

 

 

 

 

함수를 호출하는 방법에는 네가지가 있다.

1. function을 선언하고 이름으로 호출하는 경우로 일반 함수 호출 이라고 한다.

2. object에 function을 담아 오브젝트의 멤버로써 호출하는 경우로 멤버 함수로의 호출 이라고 한다.

3. javascript의 내장함수인 call을 이용한 호출 방법.

4. javascript의 내장함수인 apply를 이용한 호출 방법.

 

각기 네가지 호출 방식에 따라 this는 경우에 따라 같을 수는 있으나, 서로 다른 것을 나타낸다.

 

 

728x90

 

 

개발자 도구에서 다음의 코드를 작성해보자.

function thisTest() {
    return this.toString();
}
thisTest();

 

thisTest라는 function을 선언하고 호출하는 모습이다.

이 코드의 실행 결과는 다음과 같다.

 

[실행결과]

"[object Window]"

 

즉, 일반함수의 경우 this는 글로벌 객체인 Window를 나타낸다.

 

 

 

두번째 함수 호출 방식인 오브젝트를 선언해서 this를 출력해보기 위해 다음의 코드를 작성해보자.

var thisTest2 = {
    exec : thisTest,
    toString : function() {
        return "[object thisTest2]";
    }
}
thisTest2.exec();

 

[실행결과]

"[object thisTest2]"

 

2라인의 thisTest는 앞서 정의한 thisTest를 뜻하며,

3라인의 toString은 thisTest2의 toString을 재정의한 것으로

만약 exec의 호출 function의 thisTest안에서 this가 thisTest2를 바라보고 있다면 바로 3라인에서 재정의한 toString을 호출한 것이다.

그리고 그 실행 결과로 exec를 호출하여 thisTest를 실행한 결과 this가 바라보는 것이 thisTest2라는 것을 알아낼 수 있다.

 

즉, 오브젝트의 멤버로써 호출할 경우 이 오브젝트를 소유한 객체를 this에 넘겨준다.

 

 

 

마지막으로 call과 apply를 사용할 경우에는

매개변수를 넘겨주느냐 아니냐에 따라 this가 달라지는 것을 볼 수 있다.

.call() 이나 .apply() 를 사용할 경우 Window 객체를

그 이외에 매개변수를 넘겨주면, 해당 매개변수의 객체를 바라보게 된다.

(여기서 예외는 매개변수로 undefined를 넘겨주면 Window를 바라보도록 되어있다.)

 

ECMAScript의 표준 문서를 보면 이러한 결과가 나오는 이유를 알 수 있다고 하는데,

부끄럽게도 보고도 이해하지 못했다.

 

나중에 이해하는 날이 오리라 믿으며 우선 끝까지 한번 학습을 할 계획이다.

언어 공부의 시작은 암기라고 ..

자바를 처음 배울 때 무슨 뜻인지도 모르고 public static void main(String[] ar)을 달달 외우던 때로 돌아온 기분이다.

선암기 후이해.

 

정확한 원인은 이해하지 못했지만, 코드를 보면 어떤 결과가 나오는지부터 알아가려한다.

 

 

 

 

가장 중요한 결론은, javascript에서의 this는 다른 언어의 this와 상당히 다른 모습을 가지고 있다는 것이다.

 

 

 

 

728x90
728x90

 

 

javascript에 대해 막연하게 단순하고 쉬운 스크립트 언어 라고만 생각했다.

굉장히 후회하고 또 반성하고 있다.

 

늦게나마 javascript에 대해 알아보는데, 새로운걸 알아갈수록 기쁘다기보다 부끄러운 마음이 더 크다.

 

 

일반적으로 프로그래밍 언어를 시작할 때 배우는 java나 c를 가지고 예를 들어보자. (java를 기준으로 알아볼 예정이다.)

 

if(true) {
    String name = "xxxelppa";
}

System.out.println("이름 : " + name);

 

소스상에 위와 같은 부분이 있다고 하자.

장담하건데 "cannot be resolved to a variable' 라는 컴파일 오류가 발생할 것이다.

왜냐면 name이라는 변수는 if 조건절 안에 선언된 변수이기 때문이다.

 

그렇다면 이 에러를 해결하기 위해서 어떻게 해야할까.

여러가지 방법이 있겠지만 다음과 같이 해결할 수 있다.

 

String name = "";

if(true) {
    name = "xxxelppa";
}

System.out.println("이름 : " + name);

 

 

이렇게 수정을 하면 1라인에 선언된 name이라는 문자열 변수를 7라인에서도 바라볼 수 있기 때문에 에러가 발생하지 않는다.

이것이 바로 변수의 범위, scope 이다.

 

java에서는 일반적으로 중괄호가 그 scope를 결정하는 역할을 한다.

그렇다면 javascript에서는 어떨까

 

개발자 도구를 켜고(f12) 실습해보자.

 

if(true) {
    var name = "xxxelppa";   
}

console.log("이름 : " + name);

 

이런 코드를 실행 시키면 어떻게 될까?

앞서 java에서 알아본 바에 의하면 이 코드는 무조건 에러가 발생한다.

왜냐하면 if 조건절 안에 name이 선언 되어있고, console.log 는 조건절 범위 밖에 위치하면서 name을 바라보려 하기 때문이다.

하지만 실행 결과는 놀랍게도

이름 : xxxelppa

라고 잘 나온다.

 

왜 이러는 걸까.

 

 

728x90

 

 

다양한 관점에서 'var 가 전역 변수를 선언하는 예약어겠지' 라던가

'선언 하면 전부 전역 변수인가?' 라는 생각을 할지도 모르겠다.

 

하지만 지금은 변수의 범위, scope에 대해 얘기를 하려 하기 때문에, 눈치가 빠르다면 if 조건절의 중괄호는 scope를 생성하지 않는구나 라고 생각할 수 있겠다.

 

 

결론부터 얘기하면 javascript에서 변수의 scope를 생성하는 경우는 딱 세가지이다.

1. function

2. with

3. catch

이 세가지 예약어를 통해서만 scope이 생성되며, 그 이외의 경우에는 scope를 생성하지 않는다.

 

(이번에는 function에 대해서만 알아보려 한다.)

이런 관점에서 다음의 코드를 작성해보자.

 

function testFunc() {
    var name2 = "xxxelppa";   
}

console.log("이름 : " + name2);

 

 

if대신 function을 사용했을 뿐인데, 실행해보면 "Uncaught ReferenceError: name2 is not defined" 라는 에러를 발생할 것이다.

즉, function안에 선언된 name2는 testFunc 함수 내부에서만 사용할 수 있다는 뜻이다.

 

 

 

이제 이런 성질을 이용해서 private한 변수를 생성할 수 있다.

그 발상의 근거는 (개인적인 의견이다.)

1. 외부에서는 function안에 선언된 변수에 접근할 수 없다.

2. 내부함수 속에있는 변수에 접근할 수 있는 함수를 선언하고 이 함수만 리턴해버리면 변수에는 직접 접근할 수 없다.

 

2번의 설명이 좀 복잡하지만 다음 간단한 예제를 보면 금방 이해할 수 있다.

 

function temp() {
    var innerVar;

    return {
        getInnerVar : function() {
            return innerVar;
        },
        setInnerVar : function(param) {
            innerVar = param;
        }
    }
}

var test = temp();

 

코드를 보면 1라인에서 temp라는 함수를 하나 정의 하고 있다.

이 temp라는 함수는 innerVar이라는 변수를 하나 가지고 있는데,

앞서 살펴보았듯 function의 외부에서는 직접 접근이 불가능하다.

 

그리고 이 temp라는 함수는 오브젝트를 리턴 해버리는데

getInnerVar 라는 키값에 function을 하나 value로 가지고

setInnerVar 라는 키값에도 function을 하나 value로 가지는

단순한 키-값 쌍의 오브젝트이다.

 

이 두개의 오브젝트는 innerVar에 접근하여 값을 설정, 반환 하는 역할을 한다.

 

그런 이유로 14라인에서 test에 담긴 내용을 보면 다음과 같다.

 

 

 

개발자 도구로 test라는 변수에 담긴 내용을 출력해본 결과이다.

그럼 이제 test에 담긴 두개의 함수를 사용해보자.

 

 

이 결과를 가지고 무엇을 알 수 있을까?

바로 java에서 private 변수를 선언한 것처럼 직접 변수에 접근할 수 없고

개발자가 작성한 getter와 setter를 통해서만 변수에 접근할 수 있다는 것을 뜻한다.

 

다시말해, 개발단계에서 개발자가 의도한 방식 이외의 접근을 막는다는 것이다.

 

 

 

 

728x90

'Archive > js' 카테고리의 다른 글

javascript 에서의 this 키워드  (0) 2017.12.21

+ Recent posts