이전 기사에서 프로토 타입의 개념이 소개되었고 JavaScript의 세 가지 좋은 친구, 프로토 타입 객체 및 인스턴스 간의 관계가 소개되었습니다. 각 생성자는 프로토 타입 객체 인 "Guardian" - 프로토 타입 객체의 핵심에도 "위치"가 있습니다. 두 사람은 사랑에 빠졌지 만 인스턴스는 프로토 타입 객체와 "비밀리에 사랑에 빠졌다"고, 그녀는 또한 프로토 타입 객체의 위치를 그녀의 마음에 유지합니다.
JavaScript 자체는 객체 지향 언어가 아니라 객체 기반 언어입니다. 다른 OO 언어에 익숙한 사람들에게는 여기에 "클래스"라는 개념이 없거나 "클래스"와 "인스턴스"사이의 차이가 없기 때문에 처음에는 약간 불편합니다. 그렇다면 JavaScript의 이러한 물체를 어떻게 이런 식으로 연결합니까?
다행히 JavaScript는 설계 시작시 "상속"구현 방법을 제공했습니다. "상속"을 이해하기 전에 이제 프로토 타입 체인의 개념을 이해할 것입니다.
프로토 타입 체인
프로토 타입은 생성자에 대한 포인터가 있다는 것을 알고 있습니다. 서브 클래스 프로토 타입 객체를 새 슈퍼 클래스 ()의 다른 인스턴스와 동일하게 만드는 경우 어떻게해야합니까? 현재 서브 클래스 프로토 타입 객체에는 슈퍼 클래스 프로토 타입에 대한 포인터가 포함되어 있으며 슈퍼 클래스 프로토 타입에는 슈퍼 클래스 생성자에 대한 포인터도 포함되어 있습니다. . . 이런 식으로, 프로토 타입 체인이 형성된다.
특정 코드는 다음과 같습니다.
함수 superclass () {this.name = "women"} superclass.prototype.saywath = function () {return this.name + ": i`ma girl!"; } function subclass () {this.subname = "당신의 자매"; } subclass.prototype = new SuperClass (); subclass.prototype.subsaywhat = function () {return this.subname + ": 나는 아름다운 소녀"; } var sub = new subclass (); console.log (sub.saywhat ()); // 여자 : 나는 소녀!프로토 타입 체인을 사용하여 상속을 달성하십시오
위의 코드에서 서브 클래스가 슈퍼 클래스의 특성 및 메소드를 상속 함을 알 수 있습니다. 이 상속 구현은 슈퍼 클래스 인스턴스를 서브 클래스의 프로토 타입 객체에 할당하는 것입니다. 이러한 방식으로, 서브 클래스의 프로토 타입 객체는 슈퍼 클래스 인스턴스에 의해 덮어 쓰고, 모든 특성과 방법을 갖고, 슈퍼 클래스의 프로토 타입 객체에 대한 포인터를 갖는다.
프로토 타입 체인을 사용하여 상속을 구현할 때주의를 기울여야 할 사항이 있습니다.
상속 후 생성자의 변화에주의하십시오. 서브 클래스의 프로토 타입이 슈퍼 클래스를 가리키기 때문에 서브의 생성자는 슈퍼 클래스를 가리 킵니다. 프로토 타입 체인을 이해할 때는 끝에 기본 객체 객체를 무시하지 않으므로 모든 객체에서 Tostring과 같은 내장 방법을 사용할 수 있습니다.
프로토 타입 체인을 통해 상속을 구현할 때 프로토 타입 메소드의 문자 적 정의를 사용할 수 없습니다. 프로토 타입 객체 (이전 기사에도 소개 됨)를 다시 작성하기 때문입니다.
함수 superclass () {this.name = "women"} superclass.prototype.saywath = function () {return this.name + ": i`ma girl!"; } function subclass () {this.subname = "당신의 자매"; } subclass.prototype = new SuperClass (); Subclass.prototype = {// 슈퍼 클래스 속성과 메소드를 상속받을 수 없기 때문에 프로토 타입 객체가 여기에 덮어 씁니다 : function () {return this.subname + ": I 'Beautiful Girl"; }} var sub = new subclass (); console.log (sub.saywhat ()); // typeerror : 정의되지 않은 것은 함수가 아닙니다인스턴스 공유 문제. 프로토 타입과 생성자를 이전에 설명 할 때, 우리는 한 번 참조 유형 속성을 포함하는 프로토 타입이 모든 인스턴스에서 공유 될 것이라고 소개했습니다. 마찬가지로, "부모 클래스"프로토 타입의 기준 유형의 특성도 프로토 타입에서 공유됩니다. 프로토 타입 상속을 통해 "부모 클래스"의 참조 유형 속성을 수정하면 프로토 타입에서 상속 된 다른 모든 인스턴스가 영향을받습니다. 이것은 자원뿐만 아니라 우리가보고 싶지 않은 현상을 낭비합니다.
함수 superclass () {this.name = "여자"; this.bra = [ "a", "b"]; } function subclass () {this.subname = "당신의 자매"; } subclass.prototype = new SuperClass (); var sub1 = 새로운 서브 클래스 (); sub1.name = "man"; sub1.bra.push ( "c"); console.log (sub1.name); // man console.log (sub1.bra); // [ "a", "b", "c"] var sub2 = new subclass (); console.log (sub1.name); // woman console.log (sub2.bra); // [ "a", "b", "c"]참고 : 여기서 배열에 요소를 추가하면 슈퍼 클래스에서 상속 된 모든 인스턴스가 영향을받지 만 이름 속성을 수정하면 다른 인스턴스에 영향을 미치지 않습니다. 배열은 참조 유형이고 이름은 기본 유형이기 때문에 다른 인스턴스에는 영향을 미치지 않습니다.
인스턴스 공유 문제를 해결하는 방법은 무엇입니까? 계속 내려다 보자 ...
클래식 상속 (생성자 도둑질)
우리는 객체를 단독으로 정의하기 위해 프로토 타입을 사용하지 않는다는 것을 소개했듯이 실제 개발에서 프로토 타입 체인 만 사용하는 경우는 거의 없습니다. 참조 유형을 공유하는 문제를 해결하기 위해 JavaScript 개발자는 고전적인 상속 패턴을 도입했습니다 (일부 사람들은 차용 생성자 상속을 부릅니다). 구현은 하위 유형 생성자에서 SuperType 생성자를 호출하는 것이 매우 간단합니다. JavaScript에서 제공하는 콜 () 또는 apply () 함수를 사용해야합니다. 예를 살펴 보겠습니다.
함수 superclass () {this.name = "여자"; this.bra = [ "a", "b"];} 함수 subclass () {this.subname = "당신의 자매"; // 슈퍼 클래스의 범위를 현재 생성자에 할당하여 수퍼 클래스의 상속을 구현하기 위해 수퍼 클래스의 상속을 구현합니다.} var sub1 = new subclass (); sub1.bra.push ( "c"); console.log (sub1.bra); // [ "a", "b", "c"] var sub2 = new subclass (); console.log (sub2.bra); // [ "a", "b"]SuperClass.call (this); 이 문장은 슈퍼 클래스 생성자의 초기화 작업이 서브 클래스의 인스턴스 (컨텍스트) 환경에서 호출되므로 각 인스턴스는 자체 BRA 속성 사본을 갖도록하므로 서로 영향을 미치지 않습니다.
그러나이 구현 방법은 여전히 완벽하지 않습니다. 생성자가 소개되기 때문에 이전 기사에 언급 된 생성자와의 문제에도 직면 해 있습니다. 생성자에 메소드 정의가있는 경우 인스턴스에 대한 별도의 함수 참조가 있습니다. 우리의 목적은이 방법을 공유하는 것이며, SuperType 프로토 타입에서 정의하는 방법은 하위 유형 인스턴스에서 호출 될 수 없습니다.
함수 superclass () {this.name = "여자"; this.bra = [ "a", "b"]; } superclass.prototype.saywhat = function () {console.log ( "hello"); } function subclass () {this.subname = "당신의 자매"; SuperClass.call (this); } var sub1 = 새로운 서브 클래스 (); console.log (sub1.saywhat ()); // typeerror : undefined는 함수가 아닙니다프로토 타입 객체 및 생성자에 대한 이전 기사를 읽은 경우 이미이 문제를 해결하기위한 답을 알고 있어야합니다.
조합 상속
조합 상속은 프로토 타입 체인과 생성자의 장점을 결합하고 상속을 달성하기 위해 결합하는 방법입니다. 간단히 말해서, 프로토 타입 체인을 사용하여 속성과 방법을 상속하고 빌린 생성자를 사용하여 인스턴스 속성의 상속을 구현하는 것입니다. 이것은 인스턴스 속성 공유의 문제를 해결할뿐만 아니라 초형 속성 및 메소드를 상속받을 수있게합니다.
함수 superclass () {this.name = "여자"; this.bra = [ "a", "b"]; } superclass.prototype.saywhat = function () {console.log ( "hello"); } function subclass () {this.subname = "당신의 자매"; SuperClass.call (this); // 슈퍼 클래스에 대한 두 번째 호출} subclass.prototype = new SuperClass (); // 슈퍼 클래스에 대한 첫 번째 호출 var var1 = new subclass (); console.log (sub1.saywhat ()); //안녕하세요조합 상속 방법은 또한 실제 개발에서 상속을 구현하는 데 가장 일반적으로 사용되는 방법입니다. 이 시점에서 실제 개발 요구를 충족시킬 수 있지만 사람들의 완벽을 추구하는 것은 끝이 없으므로 필연적 으로이 패턴에 대해 "찾을 수 있습니다"가 있습니다. 패턴은 슈퍼 타입 생성자를 두 번 불렀습니다! 두 번. . . 당신은 그것을 만들었습니까? 이 증폭은 성능 손실의 100 배입니까?
가장 강력한 반박은 해결책을 제시하는 것이지만 다행히도 개발자는이 문제에 대한 최상의 솔루션을 찾았습니다.
기생 조합 상속
이 상속 방법을 도입하기 전에 먼저 기생 생성자의 개념을 이해합니다. 기생 생성자는 위에서 언급 한 공장 패턴과 유사합니다. 그 아이디어는 공통 기능을 정의하는 것입니다. 이 기능은 구체적으로 객체 생성을 처리하는 데 사용됩니다. 창조가 완료되면이 객체를 반환합니다. 이 함수는 생성자와 매우 유사하지만 생성자는 값을 반환하지 않습니다.
함수 gf (이름, bra) {var obj = new Object (); obj.name = 이름; obj.bra = 브라; obj.saywhat = function () {console.log (this.name); } return obj;} var gf1 = new Gf ( "빙빙", "C ++"); console.log (gf1.saywath ()); // bingbing기생 상속의 구현은 기생 생성자와 유사하다. 특정 유형에 의존하지 않는 "Factory"기능을 작성하고, 특히 객체 상속 프로세스를 처리 한 다음 상속 된 객체 인스턴스를 반환합니다. 다행히도 이것은 우리가 직접 구현할 필요가 없습니다. Dao GE (Douglas)는 오랫동안 구현 방법을 제공했습니다.
함수 객체 (obj) {function f () {} f.prototype = obj; return new f ();} var suplass = {이름 : "빙빙", 브래지어 : "c ++"} var subclass = object (슈퍼 클래스); console.log (subclass.name); // bingbing간단한 생성자는 공개 기능으로 제공되며, 전달 된 객체의 인스턴스가 생성자의 프로토 타입 객체에 할당되며, 마침내 생성자 인스턴스를 반환하는 것은 매우 간단하지만 효능은 매우 양호하지 않습니까? 이 방법은 나중에 "프로토 타입 상속"이라고하며, 기생 상속은 객체의 사용자 정의 속성을 향상시켜 프로토 타입을 기반으로 달성됩니다.
함수 buildObj (obj) {var o = 객체 (obj); o.saywhat = function () {console.log ( "hello"); } return o;} var superclass = {name : "bingbing", bra : "c ++"} var gf = buildobj (superclass); gf.saywhat (); // hello기생충 상속은 또한 프로토 타입에서 기능 재사용 문제에 직면하여 사람들은 빌딩 블록을 다시 조립하기 시작했으며, 하위 유형 프로토 타입을 지정할 때 부모 유형 생성자를 호출하는 문제를 해결하고 동시에 기능의 재사용을 최대화하기 위해 기생 조합 상속이 탄생했습니다. 위의 기본 구현 방법에 따라 다음과 같습니다.
// 매개 변수는 두 생성자 함수 inheritobj (sub, sup) {// 인스턴스 상속을 구현하고 superType var proto = Object (sup. prototype)의 사본을 얻습니다. // 프로토 인스턴스의 생성자 속성을 호환하여 proto.constructor = sub; // 생성 된 개체를 하위 유형의 프로토 타입에 할당 하위 유형의 프로토 타입 = 프로토;} 함수 superClass () {this.name = "women"; this.bra = [ "a", "b"];} superclass.prototype.saywhat = function () {console.log ( "hello");} 함수 subclass () {this.name = "women"; this.bra = [ "a", "b"];} superclass.prototype.saywhat = function () {console.log ( "hello");} 함수 subclass () {this.subname = "sister"; superclass.call (this);} inheritobj (서브 클래스, 슈퍼 클래스); var sub1 = new subclass (); console.log (sub1.saywhat ()); //안녕하세요이 구현은 슈퍼 타입에 대한 두 가지 호출을 피하고 서브 클래스. 프로토 타입에 불필요한 특성을 저장하고 프로토 타입 체인을 유지합니다. 이 시점에서 상속 여정은 진정으로 끝났 으며이 구현은 가장 이상적인 상속 구현 방법이되었습니다! 자바 스크립트의 상속에 대한 사람들의 논쟁은 여전히 계속되고 있습니다. 일부는 OO를 옹호하고 일부는 OO의 특성을 실현하기 위해 JavaScript에서 불필요한 노력을 기울이는 것에 반대합니다. 만약 그렇다면, 적어도 나는 더 깊은 이해를 가지고 있습니다!