2. 객체지향 자바스크립트

2.1 언어 기능

함수 오버로딩과 타입 검사

  • 자바스크립트에서 함수 오버로딩이 직접 제공하지는 않지만 함수 오버로딩을 가능하게 하는 기능이 있다.
  • 함수 오버로딩을 하려면 전달인자의 개수가 몇 개인지 결정할 수 있어야 하고, 전달인자의 타입이 무엇인지 결정 할 수 있어야 한다.
arguments
  • 전달인자의 개수가 몇 개인지 결정하는 부분
  • 자바스크립트의 함수 내부에는 함수에 전달되는 모든 전달인자를 담은 배열같이 동작하는 변수 arguments가 존재한다.
  • arguments는 진짜 배열이 아니다.

2.5 자바스크립트 함수 오버로딩에 관한 두 가지 예



<script type="text/javascript">
	function sendMessage(msg, obj){
	    if(arguments.length == 2){
		    obj.alert(msg);
	    }else{
		    alert(msg);
	    }		    
	}

	sendMessage("Hello, World!");
	sendMessage("How ar you?", window);

	//전달 인자를 여러 개 받아 배열을 만들어 반환하는 함수
	function makeArray(){
        var arr = [];

        for(var i=0 ; i<arguments.length; i++){
            arr.push(arguments[i]);
        }

        return arr;
	}
	
</script>


typeof
  • typeof 연산자는 변수가 담고 있는 값의 타입을 나타내는 문자열 이름을 반환한다.
  • typeof 연산자를 사용하는 방법이 타입을 검사하는 최적의 방법이라고 할 수 있다.

2.7 객체의 타입을 결정하는데 typeof를 사용한 예

 

<script type="text/javascript">


    if(typeof num == 'string'){
        num = parseInt(num);
    }
    
    if(typeof arr == 'string'){
        arr = arr.split(",");
    }

    alert(msg);

	
</script>


constructor
  • 객체의 타입을 검사하는데 사용할 수 있는 두 번째 방법
  • 모든 자바스크립트 객체에 존재하는 constructor라는 프로퍼티를 참조하는 방법이다.

2.8 객체의 타입을 결정하는데 constructor 프로퍼티를 사용하는 예

 

<script type="text/javascript">


    if(num.constructor == String){
        num = parseInt(num);
    }
    
    if(str.constructor == Array){
        str = str.join(',');
    }

    alert(msg);

	
</script>


유효범위

  • 자바스크립트에서는 유효범위가 블록(while, if, for..)안에 존재하지 않고 함수안에 존재한다.
  • 전역 유효범위에 속하는 모든 변수들은 그저 window 객체의 프로퍼티 이다.
  • 변수를 직접선언하지 않으면 함수 유효범위안에서만 사용하였어도 전역 유효범위에 속한다.

2.10 자바스크립트에서 변수 유효범위가 어떻게 작동하는지 보여주는 예

 
<script type="text/javascript">

    
	var foo = "test";
	
	//function이 아니라 if 문이다. 
	if(true){
		var foo = "new test";
	}
	
	alert(foo=="new test");
	
	//function 이기 때문에 old test가 된다. 
	function test(){
		var foo = "old test";
	}
	
	test();
	
	alert(foo == "new test");
	
	// 모든 변수는 그저 windows 객체의 프로퍼티이다. 
	var test = "test";
	alert(window.test == test);
	
</script>

클로저

  • 클로저는 어떤 함수를 감싸는 외부 함수가 종료되었더라도, 내부 함수에서 외부 함의 변수에 접근할 수 있는 방법이다.

2.13 클로저가 어떻게 코드의 의미를 명료하게 만드는지 보여주는 두가지 예

 
<script type="text/javascript">
    var obj = document.getElementById("main");

    obj.style.border = "1px solid red";

    setTimeout( function(){obj.style.display ='none';},1000);

    function delayedAlert(msg, time){

    	setTimeout( function(){alert(msg);},time);
    }

    delayedAlert("Welcome!", 2000);

</script>

  • 커링(currying)
    • 커링이란 함수의 전달인자 몇개를 미리 채움으로써 더 간단한 함수를 만드는 방법이다.

2.14 클로저로 함수를 커링하는 예

 
<script type="text/javascript">

	function addGenerator(num){
	    return function(toAdd){
	        return num+toAdd;
	    }
	}
	
	var addFive = addGenerator(5);
	
	alert(addFive(4) == 9);

</script>

  • 익명 함수를 사용하여 전역 변수를 다른 코드로 숨기는 예

2.15 변수들을 전역 유효범위에서 볼 수 없게 익명 함수를 사용하는 예

 
<script type="text/javascript">

    (function (){

        var msg = "Thanks for visiting!";

        window.onunload = function(){
            alert(msg);
        };
    }());

</script>

콘텍스트

  • 콘텍스트는 this 변수를 통해 작동한다.
  • this 변수는 항상 코드가 속한 객체를 가리킨다.

2.16 한 콘텍스트 안에서 함수를 사용한 후 콘텍스트를 다른 변수로 바꾸는 예

 
<script type="text/javascript">

    var obj = {
    	yes : function(){
	    	//this = obj
	        this.val = true;
        },
        no : function(){
            this.val = false;
        } 
    };

    alert(obj.val == null);

    obj.yes();
    alert(obj.val == true);

    window.no = obj.no;
    window.no();

    alert(obj.val == true);

    alert(window.val == false);

</script>

  • apply, call을 이용하여 함수 콘텍스트를 바꾸는 예
  • call : 메서드 첫 번째 전달인자를 콘텍스트로 설정하고 나머지 전달인자를 함수의 전달인자로 넘긴다.
  • apply 함수는 call과 동일한 효과를 나타내지만 함수에 사용되는 인자가 다르다.
  • call은 첫번째 인자로 this, 그 다음부터는 각 인자들이 열거되는 형태이지만
    apply는 첫번째 인자로 this가 사용되는 것은 동일하고 두번째 인자로는 Array타입이 사용된다.

2.18 함수 콘텍스트를 바꾸는 예

 
<script type="text/javascript">

    function changeColor(color){
        this.style.color = color;
    }

    changeColor("white");

    var main = document.getElementById("main");

    changeColor.call(main, "black");

    function setBodyColor(){
        changeColor.apply (document.body, arguments);
    }

    setBodyColor("black");

</script>

2.2 객체지향 기본

객체

  • 객체(object)는 자바스크립의 토대다. 사실상 이 언어에 있는 모든 것이 객체다.

2.19 간단한 객체를 하나 생성하고 프로퍼티를 설정하는 두가지 예

 
<script type="text/javascript">

    var obj = new Object();

    obj.val = 5; 
    obj.click = function(){
        alert("hello");
    }

    var obj = {
    	val : 5,
    	click : function(){
    	   alert("hello");
        }
    }
	
</script>

객체 생성

  • 대부분 객체지향 언어와는 달리 자바스크립트에는 클래스라는 개념이 없다.
  • 자바스크립트에서는 한 객체가 새로운 객체를 생성할 수 있고 다른 객체에서 무언가를 상속받을 수 있다.

2.20 간단히 객체를 하나 생성하고 사용하기

 
<script type="text/javascript">

    // 이름을 하나 받아서 현재 콘텍스트에 저장하는 간단한 함수
    function User(name){
        this.name = name;
    }

    var me = new User("My name");

    //이름이 me의 프로퍼티로 설정된 것을 볼 수 있다. 
    alert(me.name == "My name");

    //me가 User 객체의 인스턴스임을 알 수 있다.     
    alert(me.constructor == User);
    alert(me.constructor);

    //단순히 보면 User가 함수이므로 함수 취급을 하면 어떨까?
    User("Test");

    //이 함수의 this 콘텍스트가 설정되지 않았기 때문에
    //콘텍스트는 기본적으로 전역변수 'window'가 된다. 
    //그 결과 주어진 이름과 window.name이 같아진다. 
    alert(window.name == "Test");
	
</script>

constructor
  • constructor 프로퍼티는 모든 객체에 들어 있으며 항상 객체를 생성한 함수를 가리킨다.
  • 이런 식으로 기반클래스는 같지만 프로퍼티는 다른 새로운 객체를 효과적으로 복제할 수 있다.

2.21 constructor 프로퍼티를 사용하는 예

  
<script type="text/javascript">

    function User(){}

    var me = new User();

    //첫 번째 User 객체의 constructor를 참조하여 새로운 User 객체를 생성한다. 
    var you = new me.constructor

    //실제로 constructor가 같음을 알 수 있다. 
    alert(me.constructor == you.constructor);
	
</script>

public 메서드

  • public 메서드는 누구든지 접근할 수 있는 메서드다.
  • 특정 객체의 모든 인스턴스에서 사용할 수 있는 public 메서드를 만들려면 prototype 라는 프로퍼티에 대해서 알아야 한다.
  • 프로토타입에 프로퍼티를 붙이면 이 프로퍼티는 프로토타입으로 만든 모든 객체의 일부가 되고, 이 프로퍼티는 공개 프로퍼티가 된다.

2.22 prototype 객체를 통해 추가한 메서드를 갖는 객체의 예

  
<script type="text/javascript">

    function User(name, age){
        this.name = name;
        this.age = age;
    }

    User.prototype.getName = function (){
        return this.name;
    };

    User.prototype.getAge = function (){
        return this.age;
    };

    var user = new User("Bob", 33);

    alert(user.getName() == "Bob");
    alert(user.getAge() == 33);
    
</script>

private 메서드

  • private 메서드는 객체 밖에서 접근할 수 없고 객체 안에서만 접근할 수 있다.

2.23 생성자 함수에서만 사용할 수 있는 private 메서드 예

  
    //교실을 표현하는 객체 생성자
    function Classroom(students, teacher){

        //수업을 듣는 모든 학생의 정보를 출력하는 private 메서드
        function disp(){
            alert(this.names.join(","));
        }

        //수업 정보를 public 객체 프로퍼티에 저장한다. 
        this.students = students;
        this.teacher = teacher;

        //오류를 출력하기 위해 private 메소드를 호출한다. 
        disp();        
    }

    var cls = new Classroom(["scott","tiger","lion"], "Mr Smith");

    //disp는 이 객체의 public 프로퍼티가 아니기 때문에 실패한다. 
    cls.disp();