사용자 도구

사이트 도구


javascript:objectoriented

문서의 이전 판입니다!


Javascript 객체지향 프로그래밍

클래스 만들기

원칙적으로 말해서 JS에는 class는 존재하지 않는다. 단지, 생성자 함수만 존재할 뿐이다.

아래는 Pet 이라는 클래스를 생성한다.

function Pet(name) {
    this.name = name; // name 필드 생성
}
 
Pet.prototype.age = 0; // age 필드 생성
 
// toString 메소드 생성
Pet.prototype.toString = function() {
    return "Pet name : " + this.name + ", age : " + this.age;
}
 
var mong = new Pet("mong"); // 객체 생성
mong.age = 6;
alert(mong);

상속

상속할 때 중요한 부분은 Dog.prototype = new Pet()Dog.prototype.constructor = Dog 부분이다.

// 위에서 이어서, Pet을 상속하는 Dog 생성
function Dog(name, age, breed) {
    Pet.call(this, name);
    this.age = age;
    this.breed = breed;
}
 
// Dog.prototype이 Pet.prototype으로부터 상속하도록 한다.
Dog.prototype = new Pet();
 
// Pet 함수를 가리키는 생성자를 Dog 함수를 가리키도록 변경한다.
Dog.prototype.constructor = Dog;
 
// toString() 메소드 오버라이드
Dog.prototype.toString = function() {
    // 필요할 경우 부모클래스 메소드도 호출 가능
    return "Dog " + Pet.prototype.toString.call(this) + ", breed : " + this.breed;
}
 
var miro = new Dog("Miro", 7, "Pomeranian");
alert(miro);
 
alert("Is miro a Dog? " + (miro instanceof Dog));
alert("Is miro a Pet? " + (miro instanceof Pet));
alert("Is miro an Object? " + (miro instanceof Object));

Class 없이 객체 생성하고 메소드 추가하기

JavaScript does not need classes를 참조하였다.

  • 마치 class를 통해 생성한 객체처럼 필드와 메소드를 둘 수 있다. 메소드에서는 this.field로 필드 값을 읽으면 된다.
    var jane = {
        name: "Jane",
        describe: function() {
            return "Person called " + this.name;
        }
    };
     
    console.log(jane.describe()); // Person called Jane
  • 클래스 없이 상속도 쉽게 가능하다.
    var PersonProto = {
        describe: function () {
            return "Person called "+this.name;
        }
    };
    var jane = {
        __proto__: PersonProto,
        name: "Jane"
    };
    var tarzan = {
        __proto__: PersonProto,
        name: "Tarzan"
    };
    console.log(jane.describe());
    console.log(tarzan.describe());

Class 객체의 method를 Event Handler Function으로 등록하기

Class 객체의 method는 원칙적으로 this가 객체를 가리켜야 하지만, 이벤트 핸들러로 등록되면 이벤트를 발생시킨 객체를 this로 가지게 되는 현상이 발생한다. 이 문제를 해결하려면 Class methods as event handlers in javascript? - Stack Overflow에 나온 방법을 사용해야 한다.

ClickCounter = function(buttonId) {
    this._clickCount = 0;
    var that = this;
    document.getElementById(buttonId).onclick = function(){ that.buttonClicked() };
}
 
ClickCounter.prototype = {
    buttonClicked: function() {
        this._clickCount++;
        alert('the button was clicked ' + this._clickCount + ' times');
    }
}

핵심은 이벤트 핸들러를 등록할 때 this를 that으로 매핑하고, that.buttonClicked()를 호출하도록 function()으로 감싸는 부분이다. 이렇게 하면 클래스 메소드에서는 this를 원래 객체를 가리키는 것으로써 온전하게 사용할 수 있다.

setInterval / setTimeout

setInterval과 setTimeout에서도 DOM 이벤트 바인딩과 동일한 원리가 적용된다.

var A = function(v) {
  this.value = v;
  this.intervalId = null;
};
 
A.prototype.load = function() {
  console.log(new Date() + " : " + this.value);
};
 
A.prototype.start = function() {
  var that = this;
  this.intervalId = setInterval(function() { that.load(); }, 2000);
};
 
A.prototype.stop = function() {
  clearInterval(this.intervalId);
};
 
var a = new A('hello');
a.start();
 
//... after a minute
 
a.stop();

위에서 A.prototype.start 함수를 보면된다.

John Resig Class.extend

// "use strict"가 가능하도록 살짝 수정
/*
 * Simple JavaScript Inheritance By John Resig http://ejohn.org/
 * http://ejohn.org/blog/simple-javascript-inheritance/ MIT Licensed.
 */
// Inspired by base2 and Prototype
(function () {
	"use strict";
 
	var initializing = false, fnTest = /xyz/.test(function () {
		xyz;
	}) ? /\b_super\b/ : /.*/;
 
	// The base Class implementation (does nothing)
	window.Class = function () { // edited for use strict
	};
 
	// Create a new Class that inherits from this class
	Class.extend = function (prop) {
		var _super = this.prototype;
		// Instantiate a base class (but only create the instance,
		// don't run the init constructor)
		initializing = true;
		var prototype = new this();
		initializing = false;
 
		var name;
 
		// Copy the properties over onto the new prototype
		for (name in prop) {
			// Check if we're overwriting an existing function
			prototype[name] = typeof prop[name] === "function" && typeof _super[name] === "function"
							&& fnTest.test(prop[name]) ? (function (name, fn) {
					return function () {
						var tmp = this._super;
 
						// Add a new ._super() method that is the same method
						// but on the super-class
						this._super = _super[name];
 
						// The method only need to be bound temporarily, so we
						// remove it when we're done executing
						var ret = fn.apply(this, arguments);
						this._super = tmp;
 
						return ret;
					};
			}(name, prop[name])) : prop[name];
		}
 
		// The dummy class constructor
		function Class() {
			// All construction is actually done in the init method
			if (!initializing && this.init)
				this.init.apply(this, arguments);
		}
 
		// Populate our constructed prototype object
		Class.prototype = prototype;
 
		// Enforce the constructor to be what we expect
		Class.prototype.constructor = Class;
 
		// And make this class extendable
		Class.extend = window.Class.extend; // edited for use strict
 
		return Class;
	};
}());
// 용례
 
var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  },
  dance: function(){
    return this.dancing;
  }
});
 
var Ninja = Person.extend({
  init: function(){
    this._super( false );
  },
  dance: function(){
    // Call the inherited version of dance()
    return this._super();
  },
  swingSword: function(){
    return true;
  }
});
 
var p = new Person(true);
p.dance(); // => true
 
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
 
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
javascript/objectoriented.1331879852.txt.gz · 마지막으로 수정됨: 2012/03/16 15:37 저자 kwon37xi