보험최저가로 가입하는요령 쉬운 돈벌기 방법
글수 769
Object Oriented JavaScript #2
The prototype Property
전 장에서 보았듯이 함수는 객체이기 때문에 메소드와 속성을 가지고 있게 된다. 이번엔 그 중 조금 특별한 속성을 알아보려 한다. 그것이 바로 prototype 속성이다. 일반적으로 함수를 선언하게 되면 prototype 속성이 생성된다.이러한 프로토타입 속성은 값이 없는 상태로 생성이 되기 때문에 생성 함수에 영향을 미치지 않는다. 그럼 이제 프로토타입에 속성/메소드를 추가하여 보자.>>> function foo(a,b){return a+b;} >>> foo.constructor; Function() >>>typeof foo.prototype "object"Adding Methods and Properties Using the Prototype
우린 전 장에서 생성자 함수에 대해 알아보았다. 밑의 예제를 통해 prototype속성에 대해 알아보자.이제 Gadget라는 생성자 함수는 2개의 속성과 1개의 메소드를 가지게 된다. 그럼 Gadget의 prototype 속성에 속성과 메소드를 추가하여 보자. prototype 속성은 그 자체가 객체이기 때문에 객체에 속성과 메소드를 추가하는 방법과 동일하다.function Gadget(name, color){ this.name = name; this.color = color; this.whatAreYou = function(){ return 'I am a ' + this.color + ' ' + this.name; } }Gadget.prototype.price = 100; Gadget.prototype.rating = 3; Gadget.prototype.getInfo = function(){ return 'Rating: ' + this.rating + ', price: ' + this.price; } 또는 Gadget.prototype = { price: 100, rating: 3, getInfo: function(){ return 'Rating: ' + this.rating + ', price: ' + this.price; } }Using the Prototype's Methods and Properties
위의 예제처럼 prototype 에 저장된 속성/메소드는 생성자 함수에 의해 생성된 객체에서 적용이 가능하다. 그럼 새로운 객체를 생성하여 알아보자.이렇듯 생성자 함수로부터 생성된 객체는 함수뿐만 아니라 prototype 속성에서도 상속을 받게 된다. 여기서 중요한 것은 prototype 속성은 'Live'하다는 것이다. 이는 prototype 속성의 내용이 변경을 언제든 할 수 있으며, 이는 그대로 상속받은 객체에 영향을 미친다.>>> var newtoy = new Gadget('webcam', 'black'); >>> newtoy.name; "webcam" >>> newtoy.color; "black" >>> newtoy.whatAreYou(); "I am a black webcam" >>> newtoy.price; 100 >>> newtoy.rating; 3 >>> newtoy.getInfo(); "Rating: 3, price: 100"이렇듯 newtoy라는 객체는 여전히 prototype의 영향을 받게 된다.Gadget.prototype.get = function(what){ return this[what]; } newtoy라는 객체가 생성 후 위의 코드를 실행하자. >>> newtoy.get('price'); 100 >>> newtoy.get('color'); "black"Overwriting Prototype's Property with Own Property
만약 생성된 객체가 자신이 가진 속성의 이름과 prototype이 가진 속성의 이름이 같다면 어떻게 될까? 위의 예제를 활용하자. 우선 newtoy 객체에 prototype이 가진 속성 price를 가지게 하자.>>> newtoy.price = 200; >>> newtoy.price; 200 newtoy는 자신의 속성으로 prototype의 속성을 덮어버린다. 따라서 다시 자신의 속성이 없어지면 prototype의 속성을 찾게 된다. >>> delete newtoy.price; >>> newtoy.price; 100Enumerating Properties
객체안에 포함되어 있는 속성들을 보고 싶다면 for-in 반복문을 이용하면 된다. for-in 반복문은 우리가 배우기로 배열의 모든 원소들을 처리할 수 있다고 하였는데, 이는 객체에도 적용이 된다.위와 같이 객체에 포함한 속성을 for-in문을 이용해 알아볼 수 있으나, 모든 속성을 볼 수 있는 것은 아니다. 예를 들어 lenght나 constructor같은 속성들은 위의 결과에 포함되지 않았다. 이렇듯 우리에게 보여지는 속성들을 따로 enumerable(목록) 이라고 지칭한다. 이에 관련된 두가지 메소드에 대해 알아보자.배열에서의 사용 예 var a = [1,2,3]; for(var i in a){ console.log(a[i]); // 콘솔창에 출력하는 명령문 } 객체에서의 사용 예 var o = {p1: 1, p2: 2}; for(var i in o){ console.log(i + '=' + o[i]); } 결과는 아래와 같다. p1=1 p2=2
- propertyIsEnumerable() : 속성이 enumerable인지 체크하는 메소드, Boolean 값을 반환
- hasOwnProperty() : 객체 자신이 소유한 속성인지 체크하는 메소드
위의 두가지 메소드의 사용 예를 보자.위처럼 hasOwnProperty()를 사용함으로써 newtoy자체의 속성인지 prototype의 속성인지를 알 수가 있다.// Gadget이란 객체를 생성하자 function Gadget(name, color){ this.name = name; this.color = color; this.someMethod = function(){return 1;}; } // 객체의 prototype을 지정 Gadget.prototype.price = 100; Gadget.prototype.rating = 3; // newtoy라는 객체를 새로이 생성 var newtoy = new Gadget('webcam', 'black'); // newtoy의 속성을 for문을 이용해 출력 for(var prop in newtoy){ console.log(prop + ' = ' + newtoy[prop]); } name = webcam color = black someMethod = function () { return 1; } price = 100 rating = 3 // newtoy객체가 소유한 속성을 출력 for(var prop in newtoy){ if(newtoy.hasOwnProperty(prop)){ console.log(prop + ' = ' + newtoy[prop]); } } name = webcam color = black someMethod = function () { return 1; }이 밖에 하나의 메소드를 더 소개하자면 isPrototypeOf()가 있다. 이 메소드는 생성된 객체의 prototype의 진위여부를 확인해 준다.// newtoy의 속성을 매개변수로 하면 true를 반환 >>> newtoy.propertyIsEnumerable('name'); true // 대부분의 내장 속성/메소드는 enumberable이 아니므로 false를 반환 >>> newtoy.propertyIsEnumerable('constructor'); false // prototype에서 온 것 또한 false를 반환 >>> newtoy.propertyIsEnumerable('price'); false // 하지만 아래와 같이 prototype에 직접 접근하여 메소드를 사용하여 enumberalble을 확인 할 수 있다. >>> newtoy.constructor.prototype.propertyIsEnumerable('price'); false// Human이란 객체의 prototype을 monkey로 지정한다. var monkey = { hair: true, feeds: 'bananas', breathes: 'air' } function Human(name){ this.name = name; } Human.prototype = monkey; // 새로운 객체 george를 만들고 이의 prototype이 monkey인지 확인한다. var george = new Human('George'); monkey.isPrototypeOf(george); trueThe Secret _proto_ Link
prototype 속성은 현재의 객체안에 그 속성이 없더라도 접근이 가능하다. 이는 과거의 객체 속성에 접근한 적이 있다면 비밀링크(secret link)가 걸리게 된다. 이에 대한 예제를 통해 더욱 알아보자.// Human이란 생성자 함수에 monkey라는 prototype을 지정하자. var monkey = { feeds: 'bananas', breathes: 'air' }; function Human() {}; Human.prototype = monkey; // 그리고 developer 객체를 생성 후 그의 속성을 지정한다. var developer = new Human(); developer.feeds = 'pizza'; developer.hacks = 'JavaScript'; // developer의 속성들을 출력한 결과이다. >>> developer.feeds; "pizza" >>> developer.breathes; "air" // 이제 secret link를 알아보기 위해 developer의 생성자를 쓰레기 값으로 지정하자. // 이에 따라 prototype가 undefined되는 것을 알 수 있다. >>> developer.constructor = 'junk'; >>> typeof developer.constructor.prototype; "undefined" // 하지만 여전히 developer의 속성은 살아 있다. 이는 예전 링크가 여전히 걸려 있기 때문이다. >>> developer.breathes; "air" >>> developer._proto_; Object feeds=bananas breathes=air // 따라서 예전 prototype의 속성을 추가/변경하여도 developer에 영향을 미치게 된다. >>> monkey.test = 1; >>> developer.test; 1Augmenting Built-in Objects
지금까지 배운 모든 내장객체는 prototype 속성을 통해 더욱 확장될 수 있다. PHP에서 in_array()라는 함수를 이용해 임의의 값이 배열안에 포함되어 있는지 확인하는 메소드이다. 자바스크립트에는 이런 함수가 없기에 이에 해당하는 함수 inArray()를 Array의 prototype에 만들어보자.또 다른 예제를 알아보자. Array()에는 reverse()라고 하여 배열의 값을 뒤집는 메소드가 있다. 이를 String()에서도 적용할 수 있게 만들게 되면 아래와 같다.Array.prototype.inArray = function(needle){ for(var i=0, len=this.length ; i < len ; i++){ if(this[i] === needle){ return true; } } return false; } >>> var a = ['red','green','blue']; >>> a.inArray('red'); true >>> a.inArray('yellow'); falseString.prototype.reverse = function(){ return Array.prototype.reverse.apply(this.split('')).join(''); } >>> "JavaScript".reverse(); "tpircSavaJ"
이번 장은 자바스크립트의 주요 특징 중 하나인 상속(Inheritance)에 대해 알아볼 것이다.
이에 대한 올바른 이해와 적절한 사용법에 대해 짚어보자.
Prototype Chaining
모든 함수에는 하나의 객체인 prototype 속성을 포함하게 된다.
그래서 전 장에서 배운대로 new 연산자를 이용해 객체를 생성하게 되면 이 객체는 비밀링크를 갖게 된다.
이 비밀링크는 생성자 함수에서의 속성/메소드를 모두 상속받을 수 있게 한다.
이렇듯 생성된 함수들이 prototype 속성으로 연결이 되어가는 것을 "Prototype Chain"이라 한다.
이에 대한 예제를 통해 알아보자.
// 세개의 함수를 만들어 보자.
function Shape(){
this.name = 'Shape';
this.toString = function() {return this.name;};
}
function TwoDShape(){
this.name = '2D shape';
}
function Triangle(side, height){
this.name = 'Triangle';
this.side = side;
this.height = height;
this.getArea = function() {return this.side*this.height/2;};
}
// 이제 함수에 prototype을 지정하여 연결시켜주자.
TwoDShape.prototype = new Shape();
Triangle.prototype = new TwoDShape();
이렇듯 어떤함수의 prototype 속성을 상위함수로 지정함으로써 상위함수의 객체를 사용하게 해준다.
이는 각각의 함수의 속성/메소드가 변경하여도 비밀링크에 의해 연결이 되어 있어 바로 적용이 된다.
하지만 위의 코드만으로는 불안하다. 왜냐하면 prototype을 new연산자를 통해 지정함으로 overwrite가
되기 때문에 우리는 각각의 함수를 다시 정의해주는 것이 좋다.
TwoDShape.prototype.constructor = TwoDShape;
Triangle.prototype.constructor = Triangle;
이제 Triangle()함수를 이용해 새로운 객체를 생성하고,
Triangle()내의 getArea()메소드와 Shape()내의 toString()메소드를 실행하여 보자.
>>> var my = new Triangle(5,10);
>>> my.getArea();
25
>>> my.toString();
"Triangle"
위의 toString()을 호출함에 있어서의 과정을 살펴보자.
1) Triangle()내의 메소드에서 toString()을 찾는다.
2) 이에 해당하는 것이 없음 prototype 속성이 지정된 TwoDShape()내에서 toString()을 찾는다.
3) 또 해당하는 것이 없음 마지막으로 Shape()으로 가서 찾는다.
4) toString()을 찾아 my객체에서 호출한다. 따라서 this는 my가 되기에 my의 name을 출력한다.
instanceof 연산자를 이용하여 'my'가 세개의 생성자함수의 instance임을 확인할 수 있다.
>>> my instanceof Shape
true
>>> my instanceof TwoDShape
true
>>> my instanceof Triangle
true
>>> my instanceof Array
false
그리고 instanceof와 비슷한 메소드인 isPropertyOf()가 있다.
>>> Sphape.prototype.isPrototypeOf(my)
true
Moving Shared Properties to the Prototype
우린 위의 예제에서 각 함수마다의 name에 this를 이용해 사용하였다.
하지만 이 변수가 고정되어 있는 값을 갖는 변수라면 이는 효율적이지 못할 것이다.
이는 새로운 객체를 만들 때마다 new를 이용하여 이 name이 메모리 어딘가에 계속 저장이 되기 때문이다.
또한 하위함수의 prototype 속성으로 상위함수를 new를 써서 생성하게 되면 이는 또한 낭비가 될것이다.
따라서 그런 낭비를 줄이기 위해 함수의 속성/메소드를 prototype 속성에 저장해준다.
그렇게 되면 아무리 많은 하위객체를 생성하더라도 하나의 prototype 속성을 참조하기에 메모리의 효율을 높일 수 있다.
이를 위해 아래의 예제처럼 사용하여 보자.
function Shape(){}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {return this.name;};
function TwoDShape() {}
TwoDShape.prototype = new Shape();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D Shape';
function Triangle(side, height){
this.side = side;
this.height = height;
}
Triangle.prototype = new TwoDShape();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side*this.height/2;};
>>> var my = new Triangle(5, 10);
>>> my.getArea();
25
>>> my.toString();
"Triangle"
Inheriting the Prototype Only
위의 예제에서 보다 향상된 코드를 보자.
function Shape(){}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {return this.name;};
function TwoDShape() {}
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D Shape';
function Triangle(side, height){
this.side = side;
this.height = height;
}
Triangle.prototype = TwoDShape.prototype;
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side*this.height/2;};
>>> var my = new Triangle(5, 10);
>>> my.getArea();
25
>>> my.toString();
"Triangle"
위와 같은 방식을 통해 각각의 prototype을 동일하게 지정함으로써 my에서 Shape()의 toString()을 연결하는 단계가
전의 예제보다 짧아지게 된다.
하지만 이는 모든 prototype이 같으므로 그의 속성인 name을 변경하게 되면 모든 값이 동일하게 변경된다.
Triangle.prototype.name = 'Triangle';
>>> var s = new Shape();
>>> s.name
"Triangle"
A Temporary Constructor-new F()
위의 예제는 분명 효율적이긴 하나 문제점이 발생하게 된다.
따라서 이에 대한 해결책으로 임시 생성자(temporary constructor)를 생성하게 한다.
임시의 함수 F()를 아무것도 존재하지 않는 함수로 생성하고 이 함수의 prototype을 상위 함수의 prototype으로 지정 후
이를 이용해 객체를 생성하게 한다.
function Shape(){}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {return this.name;};
function TwoDShape() {}
var F = function() {};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D Shape';
function Triangle(side, height){
this.side = side;
this.height = height;
}
var F = function() {};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side*this.height/2;};
>>> var my = new Triangle(5, 10);
>>> my.getArea();
25
>>> my.toString();
"Triangle"
Uber - Access to the Parent from a Child object
일반적인 객체지향 프로그램들은 상위 클래스에 접근하기 위한 특수 구문이 있다.
이것은 상위의 모든 메소드에 어떤 것을 추가하여 사용할 때 편리하다.
이런 구문은 자바스크립트에서 지원을 하지 않지만 비슷하게 사용하는 방법이 있다.
이에 대해 전의 예제를 활용해 'uber'라는 속성에 대해 알아보자.
function Shape(){}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {
var result = [];
if(this.constructor.uber){
result[result.length] = this.constructor.uber.toString();
}
result[result.length] = this.name;
return result.join(', ');
};
function TwoDShape() {}
var F = function() {};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.uber = Shape.prototype;
TwoDShape.prototype.name = '2D Shape';
function Triangle(side, height){
this.side = side;
this.height = height;
}
var F = function() {};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.uber = TwoDShape.prototype;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side*this.height/2;};
>>> var my = new Triangle(5,10);
>>> my.toString();
"Shape, 2D Shape, Triangle"
Copying Properties
지금까지 위에서 상속하는 부분을 예제를 통해 알아보았는데, 사실 위의 코드는 다소 난잡할 수 있다.
이를 위해 상속하는 부분을 함수로 지정하여 단순화 시키자.
function extend(Child, Parent){
var p = Parent.prototype;
var c = Child.prototype;
for(var i in p){
c[i] = p[i];
}
c.uber = p;
}
>>> extend(TwoDShape, Shape);
>>> extend(Triangle, TwoDShape);
위와 같이 상위에서 하위로의 상속을 하기 위해 상위의 모든 메소드/속성을 복사하는 형식으로 사용할 수 있다.
그럼 만약 상위함수의 내용이 바뀌게 된다면 어떻게 될까?
이것은 속성이 무엇을 참조하고 있냐에 따라 다른 결과를 나타내게 된다.
위의 함수를 이용해 예제를 보자.
// 두개의 빈 함수를 생성
>>> var A = function(){};
>>> var B = function(){};
// A함수에 2개의 속성을 입력
>>> A.prototype.stuff = [1,2,3];
>>> A.prototype.name = 'a';
// A를 B에 상속
>>> extend(B, A);
// 그럼 이제 A와 B의 속성은 같은 값을 가지고 있다.
>>> B.prototype.stuff
[1,2,3]
>>> B.prototype.stuff === A.prototype.stuff
true
// B의 복사된 name을 바꾸어 보자.
>>> B.prototype.name += 'b';
"ab"
>>> A.prototype.name;
"a"
// 그럼 배열의 값을 바꿔 비교해 보자.
>>> B.prototype.stuff.push(4,5,6);
>>> A.prototype.stuff;
[1,2,3,4,5,6]
// B의 stuff를 전혀 다른 값으로 바꾸자.
>>> B.prototype.stuff = ['a','b','c'];
["a","b","c"]
>>> A.prototype.stuff;
[1,2,3,4,5,6]
위의 결과는 메모리에서 저장된 위치를 참조하는 방식에 따라 결정이 된다.
밑의 그림을 보고 이야기 해보자.

1) 처음 A의 stuff는 메모리의 한 자리를 차지하게 된다.
2) 그리고 B의 stuff가 A와 같은 메모리를 참조하게 된다.
3) B의 stuff가 전의 위치와 전혀 다른 메모리를 차지하게 된다.
4) 결국 A와 B의 stuff는 다른 위치의 메모리를 참조하게 된다.
Example
주 제 : Shape()에서 상속된 함수를 이용해 캔버스에 그림을 그려보자.
실행하기 : http://www.phpied.com/files/canvas 를 Firefox에서 불러온 후, 파이어버그를 통해 소스를 입력
소스보기 : 소스
실습예제
// 세점을 이용해 삼각형을 그리자.
var p1 = new Point(100, 100);
var p2 = new Point(300, 100);
var p3 = new Point(200, 0);
var t = new Triangle(p1,p2,p3);
t.draw();
t.getPerimeter();
t.getArea();
var r = new Rectangle(new Point(200,200), 50, 100);
r.draw();
r.getArea();
r.getPerimeter();
var s = new Square(new Point(130,130), 50);
s.draw();
s.getArea();
s.getPerimeter();
new Square(p1,200).draw();
Including JavaScript in an HTML Page
HTML페이지에 자바스크립트을 포함하는 방법은 <script> 태그를 이용하는 것이다.첫번째 script태그를 보면 js파일을 불러와서 사용하게 된다. 그리고 두번째 태그를 이용해 html 소스안에 직접 입력할 수 있다. 브라우저는 페이지를 순차적으로 실행하기 때문에 첫번째 태그안의 변수를 두번째에도 사용하게 된다. 앞으로 알아볼 내용은 다음과 같다.<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>JS test</title> <script type="text/javascript" src="somefile.js"></script> </head> <body> <script type="text/javascript"> var a = 1; a++; </script> </body> </html>
- The BOM(Browser Object Model)
- The DOM(Document Object Model)
- Listening to browser events
- The XMLHttpRequest object
BOM
BOM(브라우저 객체 모델)은 브라우저나 컴퓨터 화면에 접근하는 객체들의 모음이다. 이 객체들은 전연객체인 window, window.screen을 통해 접근할 수가 있다.The window Object's Object
전에 배웠듯이 자바스크립트는 모든 호스트환경에서 전역객체를 제공한다. 브라우저에서는 window객체를 사용한다.이제 window 객체가 가지고 있는 속성/메소드들을 알아보자.>>> window.somevar = 1; >>> somevar; 1 >>> parseInt('123'); 123 >>> window.parseInt('123'); 123window.navigator
navigator 객체는 브라우저에 대한 정보들을 담고 있다. 그 중 하나의 속성인 userAgent가 있다. 이를 Firefox에서 실행하여 보자.브라우저마다 지원하는 코드가 있기 때문에 이를 이용해 브라우저에 맞는 코드를 사용할 수가 있다. Internet Explorer에서 위의 속성을 쓰게 되면 MSIE라는 문자열이 생긴다. 이를 이용한 예제를 보자.>>> window.navigator.userAgent "Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5"if(navigator.userAgent.indexOf('MSIE') !== -1){ // this is IE } else { // not IE }window.location
location 객체는 현재 페이지의 URL에 대한 정보를 담고 있다. 따라서 location.href는 URL의 전체를, location.hostname은 도메인만을 보여준다. 간단한 반복문을 이용해 location의 모든 속성을 확인할 수 있다.for(var i in location){ console.log(i + ' = "' + location[i] + '"') } hash = "" host = "www.google.co.kr" hostname = "www.google.co.kr" href = "http://www.google.co.kr/" pathname = "/" port = "" protocol = "http:" search = "" replace = "function replace() { [native code] }" assign = "function assign() { [native code] }" reload = "function reload() { [native code] }"window.history
history 객체는 같은 브라우저 세션에 있는 방문페이지를 접근할 수 있게 한다.// 현재까지 방문한 페이지 수를 반환 >>> window.history.length // 방문 페이지의 전/후 페이지로 가게 위해선 아래와 같이 한다. >>> history.forward() >>> history.back() // 또한 임의의 페이지로 이동하기 위해 history.go()를 사용할 수 있다. >>> history.go(-1); >>> history.go(0); // 현재페이지를 Reloadwindow.screen
screen은 브라우저 밖의 컴퓨터 화면에 대한 정보를 담고 있다. 여기서 제공하는 속성에 대해 알아보자.height와 availHeight의 차이점은 height는 화면의 세로길이를 반환하지만, availHeight는 윈도우 작업표시줄을 제외한 길이를 반환한다.>>> window.screen.colorDepth 32 >>> screen.width 1280 >>> screen.availWidth 1280 >>> screen.height 1024 >>> screen.availHeight 996window.open()/close()
새로운 창을 띄우거나 닫기 위한 메소드이다. window.open()에 들어가는 매개변수에는 URL, target, length, status 등이 있다.var win = window.open('http://blog.naver.com/asus1984', 'width=300,height=300,resizable=yes'); >>> win; // 새 창 띄우기 >>> window.close(win); // 창 닫기window.moveTo(), window.resizeTo()
브라우저의 위치를 변경하거나 크기를 임의로 지정할 수 있다.window.moveTo(100,100) // 화면의 왼쪽상단부터 100px,100px의 위치로 이동 window.resizeTo(x,y) // 가로 x, 세로 y로 크기를 조정window.alert(), window.prompt(), window.confirm()
우리는 alert()에 대해 예전에 알아보았다. 그럼 다른 메시지창에 대해서도 알아보자.
- prompt() : 텍스트 입력창
- confirm() : OK, Cancel 두 버튼이 있는 메시지창
prompt()창을 브라우저에서 띄우게 되면 아래와 같다.>>> prompt('And your name was?');위의 메시지창을 실행 후 반환되는 값은 아래와 같다.
- Null : '취소' 혹은 X아이콘을 눌렀을 시
- ""(빈 문자열) : 입력창에 아무것도 쓰지않고 '확인'을 눌렀을 시
- text string : 입력창에 입력한 문자열을 '확인'혹은 Enter로 반환 시
confirm()창은 '확인'과 '취소' 두 개의 버튼을 가지고 있는 메시지창이다.>>> confirm('Are you ready?');위의 메시지창을 실행 후 반환되는 값은 boolean형이다.
- true : '확인'버튼을 눌렀을 시
- false : '취소' 혹은 X아이콘을 눌렀을 시
window.setTimeout(), window.setInterval()
setTimeout(), setInterval() 메소드는 어떤 코드를 시간에 맞게 실행하고자 할 때 사용된다. 그 중 setInterval() 메소드는 밀리세컨드를 기준으로 그 시간이 지난 후 코드를 실행하게 된다. 다음 예제를 보자.(2초는 2000밀리세컨드)위와 같이 실행을 하게 되면 boo()함수의 코드 내용을 2초 후에 실행하게 된다. 이를 중간에서 중단하고 할 시에는 아래와 같은 방법을 사용한다.>>> function boo() {alert('Boo!');}; >>> setTimeout(boo, 2000);setTimeout() 메소드는 입력된 시간만큼 반복되어 코드를 실행하고자 할 때 사용한다.>>> var id = setTimeout(boo, 2000); >>> clearTimeout(id);
DOM
DOM(Document Object Model)은 XML이나 HTML문서를 트리구조로 나타내는 방법이다.
DOM의 메소드나 속성을 이용하여 페이지안의 element를 삽입, 수정, 삭제할 수 있다.
아래의 예를 보자.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>My page</title>
</head>
<body>
<p class="opener">first paragraph</p>
<p><em>second</em> paragraph</p>
<p id="closer">final</p>
<!-- and that's about it -->
</body>
</html>
HTML은 기본적으로 head와 body 두개의 child를 가지고 있다.
위의 예제에서 body는 3개의 child를 가지고 2번째 p는 또 em이라는 child를 가지게 된다.
이런것을 바로 DOM tree라고 한다.
Accessing DOM Nodes
DOM tree는 노드들로 구성되어 있다. 위에서 본 html, head, body등이 이에 해당한다.
이제부터 이러한 노드들에 접근하여 그들의 속성을 확인하고 수정해보자.
앞으로의 진행에서 사용되는 예제는 위의 예제를 사용할 것이며,
아래의 주소를 Firefox에서 접속하여 앞으로의 예제들을 수행해 보자.
예제 : http://compstat.chonbuk.ac.kr/JavaScript/Chap7/ex.html
The document Node
document는 현재 페이지에 접근하게 해준다. 이 객체를 살펴보기 위해 Firebug에서 'document'를 쳐보자.
그럼 콘솔창에 그 페이지에 관한 정보들이 나오게 된다.
모든 노드들의 속성을 보게 되면 nodeType, nodeName, nodeValue 등이 있다.
그 중 nodeType은 노드가 element일 땐 1, attribute일 땐 2, text일 땐 3을 반환한다.
여기서 document의 nodeType은 9가 된다.
이제 트리구조에 대해 알아보자. XML문서는 항상 하나의 루트노드를 가지게 된다.
HTML문서에선 그 루트가 <HTML>이 된다.
이러한 루트에 접근하는 속성이 documentElement이다.
>>> document.documentElement
<html>
// 이에 대한 nodeType은 1이 될 것이다.
>>> document.documentElement.nodeType
1
이제 그럼 이런 element가 child노드를 가지고 있는지 알아보고, 이에 대한 속성들을 이용해 깊이 나아가자.
// child노드가 있는지 알아보는 hasChildNode() 메소드
>>> document.documentElement.hasChildNode()
true
// 위에서 말했듯이 html은 두개의 child노드를 가지고 있다.
>>> document.documentElement.childNodes.length
2
>>> document.documentElement.childNodes[0]
<head>
>>> document.documentElement.childNodes[1]
<body>
// body의 하위노드를 살펴보면 9개가 나온다.
이는 p코드 3개 + 주석 1개 + 텍스트 3개 + 양끝의 공백 2개를 합한 것이다.
>>> var bd = document.documentElement.childNodes[1];
>>> bd.childNodes.length
9
// Attributes란 각 노드가 가지고 있는 속성을 말한다.
>>> bd.childNodes[1].hasAttributes()
true
>>> bd.childNodes[1].attributes[0].nodeName
"class"
>>> bd.childNodes[1].attributes[0].nodeValue
"opener"
>>> bd.childNodes[1].getAttribute('class')
"opener"
// 태그안의 내용을 보는 속성이 두개가 있다.
>>> bd.childNodes[3].innerHTML
"<em>second</em> paragraph"
>>> bd.childNodes[3].textContent
"second paragraph"
지금까지 childNodes, nodeName, nodeValue등을 이용해 노드에 접근하는 방법에 대해 알아보았다.
그럼 이제 태그이름 혹은 속성의 이름을 가지고 각 노드에 접근하여 보자.
// p태그를 가지고 있는 노드를 알아보자.
>>> document.getElementsByTagName('p').length
3
>>> document.getElementsByTagName('p')[0]
<p class="opener">
>>> document.getElementsByTagName('p')[2]
<p id="closer">
// document의 모든 노드 갯수를 보기 위해 '*'를 이용
>>> document.getElementsByTagName('*').length
9
nextSibling, previousSibling을 이용해 DOM 트리의 노드를 이동할 수 있다.
>>> var para = document.getElementById('closer')
>>> para.nextSibling
"\n"
>>> para.previousSibling.previousSibling
<p>
>>> document.body.previousSibling
<head>
// firstChild, lastChild에 대해 알아보자.
firstChild는 childNodes[0]와 같으며, lastChild는 childNodes[childNodes.length-1]과 같다.
>>> document.body.firstChild
"\n"
>>> document.body.lastChild
"\n"
>>> document.body.lastChild.previousSibling
Comment length=21 nodeName=#comment
Creating New Nodes
새로운 노드를 생성하기 위해서 createElement()메소드를 사용할 수 있다.
또한 이 새로운 노드를 DOM tree에 넣기 위한 appendChild()메소드가 있다.
이에 대한 예제를 살펴보자.
// 새로운 element 생성
>>> var myp = document.createElement('p');
>>> myp.innerHTML = 'yet another';
// 생성된 element는 기본속성을 가지고 있기에 아래와 같이 수정할 수 있다.
>>> myp.style
CSSStyleDeclaration length=0
>>> myp.sytle.border = '2px dotted blue';
"2px dotted blue"
// 이제 생성된 element를 DOM tree에 넣어보자.
>>> document.body.appendChild(myp)
<p style="border: 2px dotted blue;">
appendChild()를 이용해 노드를 삽입하게 되면 마지막 노드로 들어가게 된다.
또한 노드를 생성하는 방법 중 기존의 노드를 복사하여 붙이는 방법이 있다.
노드를 복사하는 메소드가 cloneNode()이다.
이 메소드는 boolean형의 매개변수를 가지는데, false는 해당노드만을 복사하고, true는 그 하위노드까지도 복사를 하게 한다.
// 복사할 노드를 변수로 저장
>>> var el = document.getElementsByTagName('p')[1]; el;
<p><em>second</em> paragraph</p>
// 매개변수를 false로 놓고 복사하자. 하지만 결과에는 영향이 없다.
이는 'p'라는 element만이 복사되고 내용이 없기 때문이다.
>>> document.body.appendChild(el.cloneNode(false));
// 매개변수를 true로 놓고 복사하자.
>>> document.body.appendChild(el.cloneNode(true));
// 또한 EM만을 복사할 수도 있다.
>>> document.body.appendChild(el.firstChild.cloneNode(true));
<em>
DOM tree에서 노드를 제거 또는 교환하는 방법에 대해서 알아보자.
노드를 제거하는 메소드는 removeChild()이며, 교환하는 메소드는 replaceChild()이다.
이에 해당하는 예제를 간단히 살펴보자.
// 삭제하고자 하는 노드를 removeChild를 이용해 제거한다.
>>> var myp = document.getElementByTagName('p')[1];
>>> var removed = document.body.removeChild(myp);
>>> removed
// 교환하고자 할 때는 replaceChild(교환할 노드, 교환될 노드)를 사용한다.
>>> var p = document.getElementByTagName('p')[0];
>>> document.body.replaceChild(removed, p);
Events
Events란 브라우저에서의 어떤 조작에 의해 자바스크립트의 함수가 실행되는 것을 말한다.
다음은 그 조작에 해당하는 예이다.
- 유저가 버튼을 클릭시
- 유저가 Form안에 문자를 입력시
- 페이지가 로딩이 됐을 시
이제 이러한 조작들이 어떻게 실행되는지에 대해 알아보자.
Inline HTML Attributes
하나의 태그 안에 특별한 속성을 더해 Event를 발생하는 예제를 보자.
<div onclick="alert('Ouch!')"> click </div>
위의 예제는 div를 클릭시 div안의 onclick부분이 실행되는 예제이다.
Element Properties
이번엔 다른 click 이벤트를 알아보자.
<div id="my-div"> click </div>
<script type="text/javascript">
var myelement = document.getElemetById('my-div');
myelement.onclick = function(){
alert('Ouch!');
alert('And double ouch!');
}
</script>
위의 방법은 전의 방법보다 더 좋다고 할 수 있다.
왜냐하면 우선 div안의 코드가 간결하고 자바스크립트와 HTML의 내용이 분리되어 있어
수정하기에 편하기 때문이다.
Cross-Browser Even Listeners
모든 이벤트가 모든 브라우저에서 동일하게 실행되는 것은 아니다.
아래의 예제를 보자.
document.addEventListener('click', function(e){
console.log(e.target.nodeName);
}, false);
위의 예제는 element를 클릭시 그 노드의 이름을 출력하는 이벤트이다.
위의 경우 Internet Explorer에서는 다른 결과를 가져온다.
IE에서는 addEventListener()메소드를 가지고 있지않고 attachEvent()를 사용한다.
이 또한 사용하지 않는 브라우저에서는 onclick()를 사용하게 된다.
이처럼 브라우저마다의 지원하는 메소드가 다르기에 이를 받쳐줄 코드를 작성해야 한다.
아래의 코드가 그 예이다.
function callback(evt){
evt = evt || window.event;
var target = (typeof evt.target !== 'undefined') ? evt.target : evt.srcElement;
console.log(target.nodeName);
}
if(document.addEventListener){
document.addEventListener('click', callback, false);
}else if(document.attachEvent){
document.attachEvent('onclick', callback);
}else{
document.onclick = callback;
}
Types of Events
- Mouse 이벤트
- mouseup, mousedown, click, dblclick(더블클릭)
- mouseover, mouseout, mousemove
- Keyborad 이벤트
- keydown, keypress, keyup
- Loading / Window 이벤트
- load, unload, beforeunload
- abort(FF에서 페이지로딩을 중단 혹은 IE에서 이미지 로드를 중단시),
error(FF,IE에서 자바스크립트 에러가 발생하거나 IE에서 이미지가 로딩실패시) - resize, scroll, contextmenu(오른쪽 버튼클릭시 나오는 메뉴가 나타날 시)
- Form 이벤트
- focus(필드로 들어올 시), blur(필드를 벗어날 시)
- change, select
- reset, submit
XMLHttpRequest
XMLHttpRequest()는 웹서버와 데이터를 주고 받기 위한 객체이다.
이는 AJAX의 주 기능를 하는 객체로 하나의 페이지안에서 웹서버에 요청한 자료를 그대로 응답받아 변경 가능하게 해준다.
그럼 AJAX에서 XMLHttpRequest()사용의 두가지 단계를 살펴보면,
- Send the request - XMLHttpRequest객체를 생성하여 웹 서버에 요청하기
- Process the response - 웹서버에서 응답을 받아 해당 내용을 화면에 반영하기
Send the Request
XMLHttpRequest()객체의 기본적인 사용 예를 보자.
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = myCallback;
xhr.open('GET', 'somefile.txt', true);
xhr.send('');
1)코드는 XMLHttpRequest 생성하는 것이다.
2)코드는 웹서버로부터 응답을 받게 되면 실행되는 함수를 지정한다.
3)코드는 웹서버에 보낼 요청의 초기화함수이다.매개변수는 (요청방식, 접속 URL, 동기/비동기 방식 지정)이다.
4)코드는 웹 서버에 요청을 전송하는 함수이다.
Process the Response
위에서 명시된 예제에서 onreadystatechange 속성은 readyState라는 속성의 값이 변경될 때마다 호출된다.
이 readyState 속성은 XMLHttpRequest의 상태를 표시할 때 사용된다.
- 0 - uninitialized
- 1 - loading
- 2 - loaded
- 3 - interactive
- 4 - complete
또한 웹서버에서 응답이 도착했을 시 처리 상태를 저장하는 status라는 속성이 있다.
- 200 - OK (요청 성공)
- 403 - Forbidden (접근 거부)
- 404 - Not Found (페이지없음)
- 500 - Internal Server Error (서버 오류 발생)
따라서 아래의 코드와 같은 방식을 이용하여 응답상태와 처리상태를 구분하여 코드를 실행할 수 있겠다.
function myCallback(){
if(xhr.readyState < 4){
return;
}
if(xhr.status !== 200){
alert('Error');
return;
}
alert(xhr.responseText);
}
responseText 속성은 응답받는 텍스트의 내용을 불러온다.
Creating XMLHttpRequest Objects
XMLHttpRequest 객체를 생성하는 방법은 브라우저마다 다른게 지원하고 있다.
이를 위한 코드는 아래와 같다.
var ids = ['MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
var xhr;
if(typeof window.XMLHttpRequest === 'function'){
xhr = new XMLHttpRequest();
}else{
for(var i=0 ; i<ids.length ; i++){
try{
xhr = new ActiveXObject(ids[i]);
break;
}catch(e){}
}
}
ids에 저장된 객체들은 버전순으로 되어있기에 최신버전이 지원이 안되는 브라우저에서는 하위버전의 객체를 생성하게 될것이다.
Example
그럼 이제 위의 것들을 종합하여 코드 하나를 작성하여 보자.
우선 메인 페이지에 3개의 <div>를 생성하고 그곳에 차례대로 text, html, xml파일의 내용을 불러오자.
본 예제는 http://www.phpied.com/files/jsoop/xhr.html을 FF에서 실행하자.
그리고 그 페이지의 경로에는 준비된 3개의 파일이 각각 존재한다.(content.txt, content.html, content.xml)
그럼 이제 메인 페이지에 각각의 준비된 파일의 내용을 불러오는 코드를 작성하자.
// XMLHttpRequest객체를 생성하여 요청하는 함수생성
function request(url, callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = (function(myxhr){
return function(){
callback(myxhr);
}
})(xhr);
xhr.open('GET', url, true);
xhr.send('');
}
// 실행하는 부분
request('http://www.phpied.com/files/jsoop/content.txt',
function(o){
document.getElementById('text').innerHTML = o.responseText;
}
);
request('http://www.phpied.com/files/jsoop/content.html',
function(o){
document.getElementById('html').innerHTML = o.responseText;
}
);
request('http://www.phpied.com/files/jsoop/content.xml',
function(o){
document.getElementById('xml').innerHTML
= o.responseXML.getElementsByTagName('root')[0].firstChild.nodeValue;
}
);
위의 코드를 실행하게 되면 아래와 같은 페이지가
이렇게 바뀌게 된다.
이러한 부분은 앞으로 할 AJAX에서 더욱 자세하게 알아보자.
Coding Patterns
지금까지 배운 자바스크립트를 활용하여 코드를 짜는데 있어서 코드 운영의 활용과 효율성을 높이기
위한 코딩패턴에 대해 알아보자.
Separating Behavior
웹 페이지의 구성은 아래와 같다.
- Content(HTML)
- Presentation(CSS)
- Behavior(JavaScript)
웹을 구성하는데 있어서 이들의 구분이 분명해야한다.
이를때면, style 속성을 HTML에서 사용하지 말고 CSS에서 다루는 것이 좋고, <font> 역시 그렇다.
또한 자바스크립트 파일인 .js파일은 body를 닫기전에 사용하는것이 좋다.
Namespaces
전역변수는 변수의 이름선정에 있어 충돌이 일어날 수 있기에 사용을 자제하는 것이 좋다.
이러한 충돌을 줄이는 방법 중 하나는 하나의 전역객체를 생성하여 필요한 변수나 함수를 그 객체의 속성에 포함시키는 것이다.
그럼 MYAPP라는 전역 객체를 생성하여 그 속성에 필요한 메소드나 속성을 포함해 보자.
var MYAPP = {};
MYAPP.event = {
addListener: function(el, type, fn){
// 실행코드
},
removeListener: function(el, type, fn){
// 실행코드
},
getEvent: function(e){
//...
}
// 기타 등등
};
위와 같이 MYAPP의 속성인 event에 생성하고자 하는 메소드들을 포함하여 다른 메소드와의 충돌을 피할 수 있게 된다.
이를 생성자함수와 같이 이용해 보자.
MYAPP.dom = {};
MYAPP.dom.Element = function(type, prop){
var tmp = document.createElement(type);
for(var i in prop){
tmp.setAttribute(i, prop[i]);
}
return tmp;
}
MYAPP.dom.Text = function(txt){
return document.createTextNode(txt);
}
// 위의 코드를 사용해 보자.
var el1 = new MYAPP.dom.Element(
'a',
{href:'http://blog.naver.com/asus1984'}
);
var el2 = new MYAPP.dom.Text('click me');
el1.appendChild(el2);
document.body.appendChild(el1);
MYAPP.dom.Element()를 통해 엘리먼트의 타입과 속성을 생성하는 함수를 만들고,
MYAPP.dom.Text()를 통해 텍스트 노드를 생성하는 함수를 만든다.
그리고 이를 이용해 <a>의 경로를 지정하고 이에 해당하는 텍스트 'click me'를 포함시킨다.
마지막으로 namespace()를 생성하여 쉽게 아래와 같은 작업을 할 수 있게 해준다.
MYAPP.namespace('dom.style');
MYAPP.dom = {};
MYAPP.dom.style = {};
첫 줄의 사용예를 통해 아래 두줄의 결과를 이루게 해주는 코드를 작성해 보자.
var MYAPP = {};
MYAPP.namespace = function(name){
var parts = name.split('.');
var current = MYAPP;
for(var i in parts){
if(!current[parts[i]]){
current[parts[i]] = {};
}
current = current[parts[i]];
}
}
// 사용 예
MYAPP.namespace('event');
MYAPP.namespace('dom.style');
// 위의 결과는 아래와 동일하다.
var MYAPP = {
event: {},
dom: {
style: {}
}
}
Private Properties and Methods
일반적인 언어에서는 public, private, protected 와 같은 식별자를 가지고 있다.
하지만 자바스크립트는 접근식별자를 가지고 있지 않다.
그러나 이와 같은 식별자를 지역변수를 통해 유사하게 사용할 수 있다.
아래의 예를 보자.
var MYAPP = {};
MYAPP.dom = {};
MYAPP.dom.Button = function(text, conf){
var styles = {
font: 'Verdana',
border: '1px solid black',
color: 'black',
background: 'grey'
};
function setStyles(){
for(var i in styles){
b.style[i] = conf[i] || styles[i];
}
}
conf = conf || {};
var b = document.createElement('input');
b.type = conf['type'] || 'submit';
b.value = text;
setStyles();
return b;
};
위와 같이 사용하여 styles과 setStyles()은 함수안에서만 사용되는 private속성/메소드가 된다.
JSON
JSON(JavaScript Object Notation)은 용어 그대로 해석하면 '자바스크립트 객체 표현식'이다.
이는 자바스크립트의 언어적인 측면에서 상당히 핵심적인 기능 중 하나이다.
JSON을 이용하면 코드내의 배열이나 함수등을 깔끔하게 정리할 수가 있게 된다.
아래의 코드를 통해 비교해보자.
// 일반적인 함수의 표현식
function js(){
this.prop = 'json';
this.method = function(){
}
}
// JSON을 이용한 표현식
var js = {
prop: 'json',
method: function(){
}
}
위의 비교를 통해 무엇을 알 수 있을까? 사실 별반 다를게 없어 보일 것이다.
하지만 이를 써서 좋은 점은 무엇인지 알아보자.
1. XML에 비해 간편하게 데이터 교환이 가능하다.
// XML코드
<?xml version="1.1" encoding="iso-8859-1"?>
<response>
<name>Stoyan</name>
<family>Stefanov</family>
<books>
<book>book1</book>
<book>book2</book>
<book>book3</book>
</books>
</response>
// JSON 표현식
{
'name': 'Stoyan',
'family': 'Stefanov',
'books': ['book1','book2','book3']
}
위의 코드만 보아도 문자열의 byte수가 훨씬 적어진다. 따라서 서버측에서 받아들이기가 쉬워진다.
2. XML에 비해 사용이 편리하다.
서버의 응답으로 XML을 사용하는 것보다 JSON표현식을 사용하는 것이 편리하다.
왜냐하면 XML을 응답 데이터로 전달하면 자바스크립트에서는 XMLHttpRequest 객체의 responseXML 속성을 이용하여 인터페이스를
조작하는 코드를 작성해야 한다. 하지만 JSON표현식을 사용할 경우 responseText속성에 전달된 응답 데이터를 eval함수를 이용
하여 간단하게 자바스크립트 객체로 변환할 수 있다.
var obj = eval('(' + xhr.responseText + ')');
alert(obj.name);
alert(obj.books[2]);
Design Patterns
Erich Gamma, Richard Helm, Ralph Johnson, John Vissides 이 4명의 개발자에 의해 정리된 '디자인패턴'을 the Gang of Four 또는 GoF라고 한다. 자주 사용되는 23개의 디자인 패턴에 대해 알아보면 아래와 같다.
| 생성에 관한 패턴 | 구조에 관한 패턴 | 행동에 관한 패턴 |
|
|
|
Singleton 패턴
싱글턴 패턴은 유일무일한 단 하나의 객체를 생성하는 패턴이다. 즉, 중복된 것을 제외 하고 유일한 것을 뽑는 패턴이라고 할 수 있다. 그럼 이를 만드는 코드를 보자.function Logger(){
if(typeof global_log === 'undefined'){
global_log = this;
}
return global_log;
}
var a = new Logger();
var b = new Logger();
alert(a === b);
Factory 패턴
팩토리 패턴은 객체 생성에 관련된 디자인 패턴이다. 이 팩토리 패턴는 객체 생성하는 부분을 캡슐화를 할 수 있으며, 이를 서브에서 활용할 수 있게 한다. 다음의 예를 보자. 기능적으로 유사한 생성자 함수 3개를 생성하자.var MYAPP = {};
MYAPP.dom = {};
MYAPP.dom.Text = function(){
this.insert = function(where){
var txt = document.createTextNode(this.url);
where.appendChild(txt);
};
};
MYAPP.dom.Link = function(){
this.insert = function(where){
var link = document.createElement('a');
link.href = this.url;
link.appendChild(document.createTextNode(this.url));
where.appendChild(link);
};
};
MYAPP.dom.Image = function(){
this.insert = function(where){
var im = document.createElement('img');
im.src = this.url;
where.appendChild(im);
};
};
var o = new MYAPP.dom.Image(); o.url = 'http://images.packtpub.com/images/PacktLogoSmall.png'; o.insert(document.body); var o = new MYAPP.dom.Text(); o.url = 'http://images.packtpub.com/images/PacktLogoSmall.png'; o.insert(document.body); var o = new MYAPP.dom.Link(); o.url = 'http://images.packtpub.com/images/PacktLogoSmall.png'; o.insert(document.body);
var o;
if(type === 'Image'){
o = new MYAPP.dom.Image();
}
if(type === 'Link'){
o = new MYAPP.dom.Link();
}
if(type === 'Text'){
o = new MYAPP.dom.Text();
}
o.url = 'http://....';
o.insert();
MYAPP.dom.factory = fufnction(type){
return new MYAPP.dom[type];
}
var o = MYAPP.dom.factory(type);
o.url = 'http://...';
o.insert();
Decorator 패턴
데코레이터 패턴은 구조에 관한 디자인 패턴이다. 이는 확장에 의한 구조로써 아래의 예를 보자.var tree = {};
tree.decorate = function(){
alert('Make sure the tree won\'t fall');
};
// 그럼 이제 tree에서 확장하게 하는 함수를 작성하자.
tree.getDecoretor = function(deco){
tree[deco].prototype = this;
return new tree[deco];
}
// 그럼 확장할 속성들을 만들어보자.
tree.RedBalls = function(){
this.decorate = function(){
this.RedBalls.prototype.decorate();
alert('Put on some red balls');
}
};
tree.BlueBalls = function(){
this.decorate = function(){
this.BlueBalls.prototype.decorate();
alert('Add blue balls');
}
};
tree.Angel = function(){
this.decorate = function(){
this.Angel.prototype.decorate();
alert('An angel on the top');
}
};
// 이 함수들을 실행하자.
tree = tree.getDecorator('RedBalls');
tree = tree.getDecorator('BlueBalls');
tree = tree.getDecorator('Angel');
// 마지막으로 decorate()메소드를 실행하자.
tree.decorate();
Observer 패턴
옵저버 패턴에서는 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의합니다. 다음의 예제를 보자.var observer = {
addSubscriber: function(callback){
this.subscribers[this.subscribers.length] = callback;
},
removeSubscriber: function(callback){
for(var i=0 ; i<this.subscribers.length; i++){
if(this.subscribers[i] === callback){
delete(this.subscribers[i]);
}
}
},
publish: function(what){
for(var i=0 ; i<this.subscribers.length; i++){
if(typeof this.subscribers[i] === 'function'){
this.subscribers[i](what);
}
}
},
make: function(o){
for(var i in this){
o[i] = this[i];
o.subscribers = [];
}
}
};
var blogger = {
writeBlogPost: function(){
var content = 'Today is '+new Date();
this.publish(content);
}
};
var la_times = {
newIssue: function(){
var paper = 'Martians have landed on Earth!';
this.publish(paper);
}
};
observer.make(blogger);
observer.make(la_times);
var jack = {
read: function(what){
console.log('I just read that '+what);
}
};
var jill = {
gossip: function(what){
console.log('You didn\'t hear it from me, but '+what);
}
};
blogger.addSubscriber(jack.read);
blogger.addSubscriber(jill.gossip);
>>> blogger.writeBlogPost();
I just read that Today is Mon Jan 12 2009 17:57:11 GMT+0900
You didn't hear it from me, but Today is Mon Jan 12 2009 17:57:11 GMT+0900
>>> blogger.removeSubscriber(jill.gossip);
>>> blogger.writeBlogPost();
I just read that Today is Mon Jan 12 2009 17:57:11 GMT+0900
>>> la_times.addSubscriber(jill.gossip);
>>> la_times.newIssue();
You didn't hear it from me, but Martians have landed on Earth!
출처 : http://compstat.chonbuk.ac.kr/JavaScript/index.html
태초에 나는 개그이야기를 만들었다.
내말을 믿고 나를 따르면 천당,
내말을 믿지않고 나를 따르지 않으면 지옥,
나는 하늘나라(우주)에 사느니라.
그럼 난 외계인?




웃대가리
위의 메시지창을 실행 후 반환되는 값은 아래와 같다.
위의 메시지창을 실행 후 반환되는 값은 boolean형이다.
