JScript에서 개체의 프로토타입 속성은 개체 유형의 프로토타입에 대한 참조를 반환하는 데 사용된다는 것을 알고 있습니다.
프로토타입 속성을 사용하여 객체 클래스에 대한 기본 기능 세트를 제공합니다. 그리고 객체의 새로운 인스턴스는 객체의 프로토타입에 할당된 작업을 "상속"합니다. 그런데 이 프로토타입은 어떻게 구현되고 관리됩니까?
객체의 프로토타입 속성에 대한 설명에 대해 JScript 매뉴얼에는 다음과 같이 나와 있습니다. 모든 JScript 내부 객체에는 읽기 전용 프로토타입 속성이 있습니다. 기능(속성 및 메서드)은 프로토타입에 동적으로 추가할 수 있지만 객체에 다른 프로토타입을 제공할 수는 없습니다. 그러나 사용자 정의 개체를 새 프로토타입에 할당할 수 있습니다.
프로토타입 속성의 세 가지 일반적인 사용 예를 살펴보겠습니다.
1. 스크립트 환경의 내장 객체에 메소드를 추가합니다.
코드는 다음과 같습니다.
Array.prototype.max = function() { var i, max = this[0]; for (i = 1; i < this.length; i++) { if (max < this[i]) max = this[i]; } return max; };
2. 메소드를 추가합니다. 사용자 정의 클래스:
코드는 다음과 같습니다.
function TestObject(name) { this.m_Name = name; } TestObject.prototype.ShowName = function() { alert(this.m_Name); };
3. 사용자 정의 클래스의 프로토타입을 업데이트합니다:
코드는 다음과 같습니다.
function TestObjectA() { this.MethodA = function() { alert('TestObjectA.MethodA()'); } } function TestObjectB() { this.MethodB = function() { alert('TestObjectB.MethodB()'); } } TestObjectB.prototype = new TestObjectA();
세 번째 코드가 낯익죠? 네, 앞서 소개한 프로토타입 상속 방법입니다~~ 그런데 오늘은 "상속"에 대해 공부하지 않습니다. 이렇게 상속을 구현할 수 있는 이유는 단지 프로토타입 속성의 부작용 때문입니다.
Prototype에는 객체를 생성하는 함수(즉, OOP의 생성자)를 나타내는 데 사용되는 생성자라는 기본 속성도 있습니다. 생성자 속성은 프로토타입 속성이 있는 모든 객체의 멤버입니다. 여기에는 Global 및 Math 개체를 제외한 모든 JScript 내부 개체가 포함됩니다. 생성자 속성은 특정 객체 인스턴스를 생성하는 함수에 대한 참조를 보유합니다.
JScript에서 프로토타입 속성을 어떻게 사용하는지 알아낸 후, 본격적으로 공부해보겠습니다.
지난 기사에서 JScript에서 프로토타입 속성의 다양한 용도를 나열했지만 JScript는 실제로 우리 디자인 패턴의 프로토타입 패턴 중 하나를 파생 형식으로 사용합니다. 그럼 프로토타입 패턴에 대해 간단히 알아보고 JScript에서 프로토타입이 무엇인지 살펴볼까요?!
프로토타입 패턴이란 무엇인가요?
프로토타입 인스턴스를 이용하여 생성할 객체의 종류를 지정하고, 이 프로토타입을 복사하여 새로운 객체를 생성합니다.
프로토타입 인스턴스를 사용하여 생성할 객체의 유형을 지정하고, 이러한 프로토타입을 복사하여 새 객체를 생성합니다.
프로토타입 패턴을 사용하면 객체를 생성하는 방법에 대한 세부 정보 없이도 사용자 정의 가능한 다른 객체를 생성할 수 있습니다. 작동 원리는 생성할 객체에 프로토타입 객체를 전달하여 생성할 객체를 생성하는 것입니다. 프로토타입 객체에 자신을 복사하도록 요청합니다.
프로토타입 패턴이 무엇인지 계속해서 이해하려면 '디자인 패턴 - 프로토타입' 기사를 참조하세요. Java를 이해하지 못해도 코드를 C#으로 취급하면 됩니다.
프로토타입이 무엇인지 아셨나요? 어쨌든, 프로토타입 패턴의 구현은 복제 작업에 따라 다르다는 점을 기억하세요. 물론 얕은 복사를 원하는지, 깊은 복사를 원하는지 여부는 필요에 따라 다릅니다.
JScript의 프로토타입에 대해 계속 이야기해 보겠습니다. 왜 프로토타입 패턴의 프로토타입과 다르다고 할까요?! 이것은 제가 방금 말한 것이 아닙니다. 이 예제를 보시면 아실 것입니다. 혼란스러울 수 있습니다:
코드는 다음과 같습니다:
<script language="javascript"> function RP() { RP.PropertyA = 1; RP.MethodA = function() { alert("RP.MethodA "); }; this.PropertyA = 100; this.MethodA = function() { alert("this.MethodA"); }; } RP.prototype.PropertyA = 10; RP.prototype.MethodA = function() { alert("RP.prototype.MethodA"); }; </script>
걱정하지 마세요. 아직 예제를 시작하지 않았으며 방금 수업을 진행했습니다. 우리는 데모에 사용합니다. RP란 무엇입니까? rpwt? 물론 그렇지 않습니다. RP는 ResearchPrototype입니다. 좋아요, 더 이상 고민하지 말고 예시와 결과 분석을 살펴보겠습니다.
코드는 다음과 같습니다.
<script language="javascript"> rp = new RP(); alert(RP.PropertyA); RP.MethodA(); alert(rp.PropertyA); rp.MethodA(); </script>
실행 결과가 나타납니다.
1
RP.MethodA
100
이것 .MethodA
이 %$@#^$%&^..., 걱정하지 마세요. 계속 읽어보세요!
코드는 다음과 같습니다.
<script language="javascript"> rp = new RP(); delete RP.PropertyA; alert(RP.PropertyA); delete RP.MethodA; RP.MethodA(); delete rp.PropertyA; alert(rp.PropertyA); delete rp.MethodA; rp.MethodA(); </script>
运行结果再次登场:
undefined
A Runtime Error has occurred.
Do you wish to Debug?
Line: 32
Error: Object doesn't support this property or method
10
RP.prototype.MethodA
好玩吧,看出来什么名堂了吗?这里的RP.PropertyA和RP.MethodA只是用来做参照的,可是怎么把this.PropertyA和this.MethodA都delete了,还能出来结果,而且还是prototype导入的属性和方法呢?
这就是JScript的prototype和prototype pattern中prototype最大的不同了,JScript中的这个所谓的prototype属性其实是个语言本身支持的特性,这里没有发生任何的copy,不管shallow还是deep的。对于JScript的解释引擎,它在处理"."或"[keyName]"引用的对象的属性和方法时,先在对象本身的实例(this)中查找,如果找到就返回或执行。如果没有查找到,就查找对象的prototype(this.constructor.prototype)里是否定义了被查找的对象和方法,如果找到就返回或执行,如果没有查找到,就返回undefined(对于属性)或runtime error(对于方法)。
正因为prototype导入类实例的属性或方法是动态查找的,所以我们才能对系统内部对象添加prototype属性和方法,比如给String对象添加trim方法:
代码如下:
<script lanuage="javascript"> String.prototype.trim() { return this.replace(/(^\s+)|(\s+$)/g, ""); } </scritp>
显然JScript中的这种用法也是prototype pattern中的prototype不能解释和支持的。
这下对于JScript OOP中原型继承法的理解因该没有任何的障碍了吧?同时也应该明白为什么原型继承法有那么大的天生缺陷了吧?当然如果有任何问题,欢迎继续讨论。
附演示示例源代码:
JScript Prototype Research <script language="javascript"> function RP() { RP.PropertyA = 1; RP.MethodA = function() { alert("RP.MethodA "); }; this.PropertyA = 100; this.MethodA = function() { alert("this.MethodA"); }; } RP.prototype.PropertyA = 10; RP.prototype.MethodA = function() { alert("RP.prototype.MethodA"); }; </script> <script language="javascript"> rp = new RP(); delete RP.PropertyA; alert(RP.PropertyA); delete RP.MethodA; RP.MethodA(); delete rp.PropertyA; alert(rp.PropertyA); delete rp.MethodA; rp.MethodA(); </script>