인사이드 자바스크립트를 공부하며 정리하는 포스팅입니다.



1.클래스, 생성자, 메서드


일반적으로 C++, Java와 같은 언어에서는 class라는 키워드를 제공하여 프로그래머가 클래스를 만들 수 있다.

그리고 클래스와 같은 이름의 메서드로 생성자를 구현한다. 그러나 자바스크립트에는 이러한 개념이 없다.(ES5에서는)

자바스크립트에서는 함수객체로 클래스, 생성자, 메서드도 구현 가능하다.



var Person = function(arg){
    this.name = arg;
};

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

Person.prototype.setName = function(name){
    this.name = name;
}

var me = new Person("song");
console.log(me.getName());



2.상속


자바스크립트는 클래스를 기반으로 하는 전통적인 상속을 지원하지는 않는다.(ES5기준) 하지만 자바스크립트 특성 중 객체 프로토타입 체인을 이용하여 상속을 구현할 수 있다.


1) 클래스 개념 없이 객체의 프로토타입으로 상속 구현하기.

아래 예제는 더글라스 크락포드가 자바스크립트 객체를 상속하는 방법으로 소개한 코드이다.

var create_object = function(o){ function F() {} F.prototype = o; return new F(); };


생성된 F객체는 object o에 프로토타입 링크가 연결되어 있고, 

또, 이 object o는 Object prototype에 프로토타입 링크가 연결되어 있다.


그리고 프로토타입으로 상속을 구현하기에 중심이되는 또 다른 메서드가 있다. 

바로 extend() 메서드이다. 자바스크립트에서는 범용적으로 extend() 메서드로 자신이 원하는 객체 혹은 함수를 추가시킨다.

다음 코드는 jQuery 1.0의 extend 함수이다.


function extend(obj, prop){
    if(!prop){prop = obj; obj = this;}
    for(var i in prop) obj[i] = prop[i];
    return obj;
}


위와 같은 extend() 함수의 약점은 얕은 복사를 하고 있다는 것이다. 프로퍼티 중 객체가 있는 경우 깊은 복사를 하는 것이 일반적이다.



create_object(), extend() 메서드를 이용하여 상속을 하는 예제를 구현해 보자.

//클래스 개념 없이 프로토타입 특성으로만 상속 구현하기

//더글라스 크락포드가 자바스크립트 객체를 상속하는 방법으로 소개한 코드.
var create_object = function(o){
    function F() {}
    F.prototype = o;
    return new F();
};
//  _proto_          _proto_
//F ------> object o -------> Object.prototype

var person = {
    name : "song",
    getName : function(){
        return this.name;
    },
    setName : function(arg){
        this.name = arg;
    }
};

var student = create_object(person);
student.setName("ssong");
console.log(student.getName());

//위와 같이 부모 객체의 메서드를 그대로 상속받아서 사용할 수 있고, 자신의 메서드를 재정의 혹은 추가로 구현할 수 있다.
//이때, 자바스크립트에서는 범용적으로 extend()라는 이름의 함수로 자산이 원하는 객체 혹은 메서드를 추가한다.

function extend(obj, prop){
    if(!prop){prop = obj; obj = this;}
    for(var i in prop) obj[i] = prop[i];
    return obj;
}

var studentAdded = {
    setAge : function(age){
        this.age = age;
    },
    getAge : function(){
        return this.age;
    }
};

extend(student, studentAdded);
student.setAge(25);
console.log(student.getAge());


//한 단계 더 상속을 구현해보도록 하겠다.
//student를 상속받은 HiSchoolStudent를 구현하겠다.

var hiSchoolStudent = create_object(student);

var hiSchoolStudentAdded = {
    grade : 3,
    setGrade : function(grade){
        this.grade = grade;
    },
    getGrade : function(){
        return this.grade;
    }
};

extend(hiSchoolStudent, hiSchoolStudentAdded);
console.log(hiSchoolStudent.getName());
console.log(hiSchoolStudent.getAge());
console.log(hiSchoolStudent.getGrade());


2) 클래스역할을 하는 함수로 상속하기.


아래 예제는 일반적인 상속 예제이다. 


핵심이 되는 부분은 Student.prototype에 부모가 될 Person의 인스턴스를 넣어주고, 생성자를 다시 지정해주는 것이다.

이렇게 함으로써, Student의 객체는 Person 객체의 함수와 메서드를 사용할 수 있게 프로토타입 링크가 형성된다.


주의할 점은 자동으로 부모 객체의 생성자가 호출되지는 않으므로 자식 생성자에서 부모 생성자를 호출해주어야 한다.

Person.call(this, name); 부분이 부모 생성자를 호출해 주는 부분이다. 

부모 생성자에 생성될 객체를 this로 넘긴다. 


//클래스역할을 하는 함수로 상속하기 var Person = function(name){ this.name = name; }; Person.prototype.setName = function(name){ this.name = name; }; Person.prototype.getName = function(){ return this.name; }; var Student = function(name, _calss){ //부모클래스 생성자 호출 Person.call(this, name); this.class = _calss; }; Student.prototype = new Person(); Student.prototype.constructor = Student; Student.prototype.getClass = function(){ return this.class; }; Student.prototype.setClass = function(_calss){ this.class = _calss; }; var song = new Student("song", 3); console.log(song.getName()); console.log(song.getClass()); console.log(song instanceof Person); // true console.log(song instanceof Student); // true


3.캡슐화


자바스크립트의 강력한 특성 중 하나인 클로저를 활용하여 캡슐화를 할 수 있다.


1) 기본 예제

아래 예제는 public 메서드가 클로저 역할을하고, private 멤버인 name에 접근한다.

자바스크립트에서 할 수 있는 기본적인 정보은닉 방법이다.

*모듈 패턴


주의할 점은 private 멤버가 객체나 배열인 경우 사용자가 get~~()함수를 통해 받은 값을 손쉽게 수정할 수 있다. 때문에 깊은 복사를 통해서 새로은 객체나 배열을 리턴해주어야 한다.


var Person = function(arg){
    var name = arg ? arg: "song";
    return {
        getName: function(){
            return name;
        },
        setName: function(arg){
            name = arg;
        }
    };
}

var song = Person(); // or var song = new Person();
console.log(song.getName());


위 예제는 객체를 리턴하는데, 이 객체는 Person 함수 객체의 프로토타입에는 접근할 수 없다.

때문에 Person을 부모로 하는 프로토타입을 이용한 상속을 구현하기에는 용이하지 않다. 때문에 이를 보완하기 위해 함수를 반환한다.


2) 캡슐화를 적용한 상속가능 함수.


var Person = function(arg){
    var name = arg ? arg: "song";

    var Person = function(){}
    Person.prototype = {
        getName: function(){
            return name;
        },
        setName: function(arg){
            name = arg;
        }
    };
    
    return Person;
}();

var song = new Person();
console.log(song.getName());