<script> <br>function Point(x,y) <br>{ <br>this.x = x; <br>this.y = y <br>} <br>var p1 = new Point(1,2) <br>var p2 = new Point(3,4) ; 생성된 모든 개체 <br></script>
a라는 속성이 객체 유형의 프로토타입에 추가되고 객체 자체에 a라는 동일한 이름의 속성이 있는 경우 객체의 속성 a에 액세스하면 객체 자체의 속성이 프로토타입이 됩니다. 속성이 "덮어쓰기"되었지만 프로토타입 속성은 사라지지 않습니다. 삭제 연산자를 사용하여 객체 자체의 속성 a를 삭제하면 객체의 프로토타입 속성이 다시 표시됩니다. 이 기능을 사용하면 개체 속성에 대한 기본값을 설정할 수 있습니다. 예:
위의 예에서는 프로토타입을 통해 Point 객체의 기본값(0,0)을 설정하므로 p1의 값은 (0, 0)이고 p2의 값은 (1,2)이므로 p2.x를 삭제하고 p2.y를 삭제하여 p2의 값을 (0,0)으로 복원할 수 있습니다. 더 흥미로운 예는 다음과 같습니다.
코드는 다음과 같습니다.
<script> <span> 함수 Point(x, y) <a style="CURSOR: pointer" data="88210" class="copybut" id="copybut88210" onclick="doCopy('code88210')">{ <u>if(x) this.x = x </u>if(y) this.y = y </a>Point.prototype .x = 0; </span>Point.prototype.y = 0; </div>
<div class="codebody" id="code88210">function LineSegment(p1, p2) <br>{ <br>//개인 멤버<br>var m_firstPoint = p1; >var m_lastPoint = p2; <br>var m_width = { <br>valueOf : function(){return Math.abs(p1.x - p2.x)}, <br>toString : function(){return Math.abs (p1.x - p2.x)} <br>} <br>var m_height = { <br>valueOf : function(){return Math.abs(p1.y - p2.y)}, <br>toString : function() {return Math.abs(p1.y - p2.y)} <br>} <br>//getter <br>this.getFirstPoint = function() <br>{ <br>return m_firstPoint; >} <br>this.getLastPoint = function() <br>{ <br>return m_lastPoint; <br>} <br><br>this.length = { <br>valueOf : function(){return Math.sqrt (m_width* m_width m_height*m_height)}, <br>toString : function(){return Math.sqrt(m_width*m_width m_height*m_height)} <br>} <br>} <br>var p1 = new Point; 🎜>var p2 = new Point(2,3); <br>var line1 = new LineSegment(p1, p2) <br>var lp = line1.getFirstPoint() <br>lp.x = 100; 실수로 다시 쓰기 lp의 값이 파괴되고 lp의 원래 값이 파괴되어 복구할 수 없습니다. <br>alert(line1.getFirstPoint().x) <br>alert(line1.length); //Even line1. 길이가 변경되었습니다<br></script>
this.getFirstPoint()를 다음과 같이 다시 작성하세요.
코드 복사
코드는 다음과 같습니다.
this.getFirstPoint = function()
코드 복사
코드는 다음과 같습니다.
<스크립트>
함수 Point(x, y)
{
if(x) this.x = x;
if(y) this.y = y;
}
Point.prototype.x = 0;
Point.prototype.y = 0;
function LineSegment(p1, p2)
{
//私有成员
var m_firstPoint = p1;
var m_lastPoint = p2;
var m_width = {
valueOf : function(){return Math.abs(p1.x - p2.x)},
toString : function(){return Math.abs(p1.x - p2 .x)}
}
var m_height = {
valueOf : function(){return Math.abs(p1.y - p2.y)},
toString : function(){return Math .abs(p1.y - p2.y)}
}
//getter
this.getFirstPoint = function()
{
function GETTER(){};
GETTER.prototype = m_firstPoint;
새 GETTER()를 반환합니다.
}
this.getLastPoint = function()
{
function GETTER(){};
GETTER.prototype = m_lastPoint;
새 GETTER()를 반환합니다.
}
this.length = {
valueOf : function(){return Math.sqrt(m_width*m_width m_height*m_height)},
toString : function(){return Math. sqrt(m_width*m_width m_height*m_height)}
}
}
var p1 = new Point;
var p2 = new Point(2,3);
var line1 = new LineSegment(p1, p2);
var lp = line1.getFirstPoint();
lp.x = 100; //작은 마음이 없습니다. lp의 내용은 없습니다.
alert(line1.getFirstPoint().x);
alert(line1.length); //line1.length不发生改变
实际上,将一个对象设置为一个类型의 원본, 为对象建立叻读副本,任何时候对副本进行改变,city不会影响到삭제 자기 자신과 같은 이름을 가진 성은 则可以恢复의 원래 성입니다.下面再举一个例子:
<script> <br>function Polygon() <br>{ <br>var m_points = []; <br><br>m_points = Array.apply(m_points, 인수); <br><br>함수 GETTER(){}; <br>GETTER.prototype = m_points[0]; <br>this.firstPoint = new GETTER(); <br><br>this.length = { <br>valueOf : function(){return m_points.length}, <br>toString : function(){return m_points.length} <br>} <br><br> this.add = function(){ <br>m_points.push.apply(m_points, 인수); <br>} <br><br>this.getPoint = function(idx) <br>{ <br>return m_points[idx]; <br>} <br><br>this.setPoint = function(idx, point) <br>{ <br>if(m_points[idx] == null) <br>{ <br>m_points[idx] = point ; <br>} <br>else <br>{ <br>m_points[idx].x = point.x; <br>m_points[idx].y = 포인트.y; <br>} <br>} <br>} <br>var p = new Polygon({x:1, y:2},{x:2, y:4},{x:2, y:6} ); <br>경고(p.length); <br>경고(p.firstPoint.x); <br>alert(p.firstPoint.y); <br>p.firstPoint.x = 100; //불편한 마음이 듭니다 <br>alert(p.getPoint(0).x); //불가능합니다. <br>delete p.firstPoint.x; //恢复 <br>alert(p.firstPoint.x); <br><br>p.setPoint(0, {x:3,y:4}); //통합 설정자(setter)는 점점 더 많은 정보를 제공합니다 <br>alert(p.firstPoint.x); //getter적值发生了改变 <br>alert(p.getPoint(0).x); <br></script>
注意,以上的例子说明了用prototype可以快速创建对象的多个副本, 一般情况下,利用prototype来大weight的创建复杂对象,要比用其他任何방법来copy对象快得多。注意到,用一个对象为原型,来创建大質新对象,这正是prototype Pattern 的本质。
下면是一个例子:
<script> <br>var p1 = new Point(1,2); <br>var 포인트 = []; <br>var PointPrototype = function(){}; <br>PointPrototype.prototype = p1; <br>for(var i = 0; i { <br>points[i] = new PointPrototype(); <br>//P1副本快得多。 <br>} <br></script>
위에서 언급한 사용 기술 외에도 프로토타입에는 고유한 특성으로 인해 다른 용도도 있습니다. 가장 널리 사용되고 잘 알려진 방법은 아마도 상속을 시뮬레이션하는 데 사용하는 것입니다. 다음은 한 섹션에서 논의됩니다.
3 프로토타입의 본질
위에서 프로토타입의 역할에 대해 언급했습니다. 이제 규칙을 통해 프로토타입의 본질을 밝혀보겠습니다.
프로토타입은 C의 정적 필드처럼 동작한다고 합니다. 속성을 프로토타입의 속성으로 추가하면 이 속성은 이 유형으로 생성된 모든 인스턴스에서 공유되지만 이 공유는 읽기 전용입니다. 어떤 경우에도 이 속성을 동일한 이름의 자체 속성으로 덮어쓸 수만 있고 변경할 수는 없습니다. 즉, 객체가 특정 속성을 읽을 때 항상 자신의 도메인의 속성 테이블을 먼저 확인하고, 그러한 속성이 있으면 이 속성을 반환하며, 그렇지 않으면 프로토타입 도메인을 읽고 해당 속성을 반환합니다. 프로토타입 도메인. 또한 JavaScript에서는 프로토타입 필드가 모든 유형의 객체를 참조할 수 있도록 허용합니다. 따라서 프로토타입 필드를 읽은 후에도 속성을 찾을 수 없으면 JavaScript는 프로토타입 필드가 가리키는 객체의 프로토타입 필드를 반복적으로 검색합니다. 객체 자체이거나 주기가 발생할 때까지 다음 다이어그램을 사용하여 프로토타입과 객체 인스턴스 간의 관계를 설명할 수 있습니다.
//TODO:
4 프로토타입의 가치와 한계
위의 분석을 통해 프로토타입을 이해하게 되었는데, 이를 통해 객체를 프로토타입으로 활용하여 수많은 인스턴스를 안전하게 생성할 수 있다는 것이 프로토타입의 진정한 의미이자 가치입니다. 프로토타입의 이 기능을 사용하면 객체의 상속을 시뮬레이션할 수 있다는 사실을 나중에 살펴보겠지만, 프로토타입이 상속을 시뮬레이션하는 데 사용되지만 프로토타입이 상속의 중요한 가치이기는 하지만 확실히 핵심은 아니라는 점을 알아야 합니다. 즉, JavaScript 따라서 프로토타입 지원은 객체 상속을 구현하는 데만 사용되는 것이 아닙니다. 프로토타입 상속이 없더라도 JavaScript의 프로토타입 메커니즘은 여전히 매우 유용합니다.
프로토타입은 객체를 프로토타입으로 사용하여 유형의 복사본을 만들기 때문에 한계도 큽니다. 우선, 해당 유형의 프로토타입 필드에 있는 값 복사본으로 동작하지 않고 "부작용"을 가져오는 참조 복사본으로 동작합니다. 프로토타입에서 참조 유형의 속성 값을 변경하면(또 다른 다소 어색한 설명:P) 이 유형으로 생성된 모든 인스턴스에 완전히 영향을 미칩니다. 때로는 이것이 정확히 우리에게 필요한 것일 수도 있지만(예: 특정 클래스의 모든 객체의 기본값 변경) 때로는 이것이 우리가 원하지 않는 것일 수도 있습니다(예: 클래스 상속의 경우).
<script> <br>{ <br>this.a=[]; <br>} <br>function ClassB() <br>{ <br>this.b=function(){}; .prototype =new ClassA(); <br>var objB1=new ClassB(); <br>objB1.a.push(1,2,3); (objB2 .a); <br>//b의 모든 인스턴스에서 a의 멤버가 변경되었습니다! ! 이는 이 예에서 원하는 것이 아닙니다. <br></script>
JavaScript 구현:
Java 언어에서 객체는 모두 java.lang.Object에서 상속되며, java.lang.Object는 Cloneable 인터페이스가 구현되는 한 Clone 메소드를 제공합니다. 이는 복제 지원을 의미합니다. 그렇지 않으면 예외가 발생합니다. 이 시점에서 JavaScript는 매우 가깝습니다. 모든 개체는 Object에서 상속됩니다. 그러나 Object는 Clone 메서드를 지원하지 않습니다. 그러나 JavaScript를 통해 Expanddo 형식으로 구현하면 향후 모든 개체 생성이 가능합니다. 클론 방식을 실현했습니다.
자바스크립트 자체에서는 Clone 메소드를 제공하지 않기 때문에 var a=new Object(); var b=a와 같은 객체 할당의 경우 이러한 코드는 동일한 객체를 생성합니다. object, you must pass new 이 키워드는 구현에 사용되므로 Clone 구현 과정에서 내부적으로 생성자(constructor) CloneModel을 정의하고 그 부모 개체도 Clone 활동 자체에 사용할 개체로 지정했기 때문에 this 키워드가 사용되었습니다. 생성자 CloneModel을 기반으로 객체를 하나씩 생성합니다. 생성자 내부에 코드가 없기 때문에 실제로 새로 생성된 객체는 모든 구현이 복제해야 하는 객체인 상위 객체에 있다고 말합니다. . 지금까지 복사해야 할 객체를 생성했지만 모든 값은 상위 객체를 가리킵니다.
JavaScript의 객체지향 접근 방식에서는 상위 객체의 값을 덮어쓰지 않으면 이때는 바로 상위 객체를 가리킨다는 점을 논의했습니다. 프로토타입 패턴에서는 객체의 내부 값이 필요합니다. after Clone은 관련이 없어야 하며, 한 번 할당되는 한 objClone의 값은 상위 개체를 가리키는 대신 자체 메모리 공간에 있게 됩니다. 이러한 고려 사항에 따라 objClone[v]=objClone[v]; 문은 상위 개체의 값을 덮어써서 자체 메모리에 복사하는 것입니다.
21.2.1 프로토타입이란
JavaScript에서 객체의 프로토타입 속성은 객체 유형의 프로토타입에 대한 참조를 반환할 수 있습니다. 다소 헷갈리는 설명입니다. 이를 이해하려면 먼저 객체 유형(Type)과 프로토타입(prototype)의 개념을 올바르게 이해해야 합니다. 앞서 우리는 객체의 클래스(Class)와 객체 인스턴스(Instance) 사이에 '생성' 관계가 있다고 말했습니다. 따라서 우리는 '클래스'를 객체 특성의 모델링으로 간주하고 객체를 클래스 특성의 구체적인 표현으로 간주합니다. .ization, 즉 클래스(Class)는 객체의 유형(Type)입니다. 예를 들어 이전 예에서 p1과 p2의 유형은 모두 Point입니다. JavaScript에서는 다음과 같이 instanceof 연산자를 통해 확인할 수 있습니다. p1 instanceof Point p2 instanceof Point 그러나 Point가 p1과 p2의 유일한 유형은 아닙니다. p1과 p2는 모두 객체이므로 Object가 Point보다 더 일반적인 클래스이기 때문에 Object와 Point 사이에 파생 관계가 있다고 말합니다. 이 관계를 "상속"이라고 합니다. , 이는 객체 간의 일반화된 관계의 특수한 경우이기도 하며, 객체지향에서 없어서는 안 될 기본 관계입니다. 객체 지향 분야에서 인스턴스와 유형은 설명 가능한 추상 관계의 유일한 쌍이 아닙니다. JavaScript에서 또 다른 중요한 추상 관계는 유형(Type)과 프로토타입(prototype)입니다. 이 관계는 유형과 인스턴스 간의 추상 관계로 3계층 체인을 형성하는 더 높은 수준의 추상 관계입니다.
그림 21.2에서는 이 관계를 설명합니다.
, 유형과 프로토타입 간의 관계
실생활에서 우리는 다른 것을 바탕으로 무언가가 만들어졌다고 흔히 말합니다. 이 두 가지는 동일한 유형일 수도 있고 다른 유형일 수도 있습니다. "고양이를 그리고 호랑이를 그리다"라는 관용어에서 여기서의 고양이는 프로토타입이고, 호랑이는 타입을 표현하기 위해 "tiger.prototype = a a cat cat" 또는 "tiger.prototype = new"입니다. 고양이()". "프로토타입"은 자연의 사물을 설명하는 "범주화" 관계의 한 유형입니다. 다른 관계에는 "상속" 및 "인터페이스"가 포함됩니다. 일반적으로 '상속'은 사물 사이에 내재된 파생관계를 의미하며, '상속'으로 설명할 수 있는 사물은 강한 상관관계(혈연관계)를 가지고 있습니다. "인터페이스"는 기능 측면에서 사물의 일반적인 특성을 설명합니다. "프로토타입"은 사물 간의 "유사성"을 설명하는 경향이 있습니다. 이러한 관점에서 "프로토타입"은 사물의 상관 관계를 설명하는 데 있어 상속 및 인터페이스보다 더 광범위합니다. Java 프로그래머라면 상속의 관점에서 위의 예를 고려하십시오. 물론 "cat"을 사용하여 "tiger"를 상속하는 것은 불가능하며 "tiger"를 사용하여 "cat"을 상속하는 것도 불가능합니다. 그들의 관계를 설명하려면 공통점을 다루는 "추상 클래스"를 만들거나 "고양이"라고 부를 필요가 있습니다. 그러나 내 시스템에서 "cat"과 "tiger"만 사용해야 한다면 이 중복된 "cat"은 나에게 아무런 의미가 없습니다. 내가 표현해야 할 것은 "tiger"가 "cat"과 약간 비슷하다는 것뿐입니다. 그게 다야. 여기서는 프로토타입을 사용하여 생성할 필요가 없는 "고양이" 유형을 성공적으로 저장하는 데 도움이 되었습니다.프로토타입을 심도 있게 이해하기 위해서는 디자인 패턴 중 하나인 프로토타입 패턴을 연구하면 됩니다. 이 패턴의 핵심은 프로토타입 인스턴스를 사용하여 생성할 객체의 유형을 지정하고, 이러한 프로토타입을 복사하여 새로운 객체를 생성하는 것입니다. JavaScript의 프로토타입은 이와 유사합니다. 프로토타입 패턴에 대한 자세한 내용은 이 책의 범위를 벗어나는 "디자인 패턴"을 참조하세요. 프로토타입 패턴에서는 유형이 한 번에 하나의 프로토타입만 가질 수 있어야 합니다(그리고 인스턴스는 분명히 한 번에 여러 유형을 가질 수 있습니다). JavaScript의 경우 이 제한에는 두 가지 의미가 있습니다. 첫 번째는 각 특정 JavaScript 유형에 하나의 프로토타입만 있다는 것입니다. 기본적으로 프로토타입은 Object 객체입니다(Object 유형이 아닙니다!). 두 번째는 이 유형의 모든 인스턴스 유형이 프로토타입 관계를 충족하는 유형 체인이어야 한다는 것입니다. 예를 들어 p1의 유형은 Point와 Object이고 Object 객체는 Point의 프로토타입입니다. 유형이 ClassA, ClassB, ClassC 및 Object인 객체가 있는 경우 이 네 가지 클래스는 완전한 프로토타입 체인을 형성해야 합니다. 예:
예 21.4 프로토타입 관계의 유형 체인
함수 ClassA()
{
……
}
ClassA.prototype = new Object(); //생략 가능
function ClassB()
{
……
}
ClassB.prototype = new ClassA(); //ClassB는 ClassA의 객체를 프로토타입으로 사용합니다.
function ClassC()
{
…
}
ClassC.prototype = new ClassB( ); //ClassC는 ClassB의 객체를 프로토타입으로 사용합니다.
var obj = new ClassC();
alert(obj instanceof ClassC) //true
alert(obj instanceof ClassB);
alert(objinstanceofClassA); //true
alert(objinstanceofObject); //true
그림 21.3은 이들 간의 관계를 간략하게 설명합니다.
그림 21.3 프로토타입의 유형 체인 관계
흥미롭게도 JavaScript는 유형의 프로토타입의 유형을 지정하지 않으므로(이것은 또 다른 매우 어색한 진술입니다) 어떤 유형이든, 일반적으로 일종의 객체가 될 수 있으므로 object-type -프로토타입(객체 )은 링 구조 또는 기타 흥미로운 토폴로지 구조를 형성할 수 있으며 이러한 구조는 JavaScript에 다양한 용도를 제공하며 그 중 일부는 영리할 뿐만 아니라 아름다움도 가득합니다. 다음 섹션에서는 주로 프로토타입의 사용법을 소개합니다. <